1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
34 #include <sys/ioctl.h>
39 #include <systemd/sd-journal.h>
43 #include "path-util.h"
46 #include "logs-show.h"
48 #include "journal-internal.h"
49 #include "journal-def.h"
50 #include "journal-verify.h"
51 #include "journal-authenticate.h"
52 #include "journal-qrcode.h"
54 #include "unit-name.h"
56 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
58 static OutputMode arg_output = OUTPUT_SHORT;
59 static bool arg_follow = false;
60 static bool arg_all = false;
61 static bool arg_no_pager = false;
62 static unsigned arg_lines = 0;
63 static bool arg_no_tail = false;
64 static bool arg_quiet = false;
65 static bool arg_merge = false;
66 static bool arg_this_boot = false;
67 static const char *arg_cursor = NULL;
68 static const char *arg_directory = NULL;
69 static int arg_priorities = 0xFF;
70 static const char *arg_verify_key = NULL;
72 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
74 static usec_t arg_since, arg_until;
75 static bool arg_since_set = false, arg_until_set = false;
76 static const char *arg_unit = NULL;
77 static const char *arg_field = NULL;
86 } arg_action = ACTION_SHOW;
88 static int help(void) {
90 printf("%s [OPTIONS...] [MATCHES...]\n\n"
91 "Query the journal.\n\n"
93 " --since=DATE Start showing entries newer or of the specified date\n"
94 " --until=DATE Stop showing entries older or of the specified date\n"
95 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
96 " -b --this-boot Show data only from current boot\n"
97 " -u --unit=UNIT Show data only from the specified unit\n"
98 " -p --priority=RANGE Show only messages within the specified priority range\n"
99 " -f --follow Follow journal\n"
100 " -n --lines[=INTEGER] Number of journal entries to show\n"
101 " --no-tail Show all lines, even in follow mode\n"
102 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
103 " verbose, export, json, json-pretty, json-sse, cat)\n"
104 " -a --all Show all fields, including long and unprintable\n"
105 " -q --quiet Don't show privilege warning\n"
106 " --no-pager Do not pipe output into a pager\n"
107 " -m --merge Show entries from all available journals\n"
108 " -D --directory=PATH Show journal files from directory\n"
110 " --interval=TIME Time interval for changing the FSS sealing key\n"
111 " --verify-key=KEY Specify FSS verification key\n"
114 " -h --help Show this help\n"
115 " --version Show package version\n"
116 " --new-id128 Generate a new 128 Bit ID\n"
117 " --header Show journal header information\n"
118 " --disk-usage Show total disk usage\n"
119 " -F --field=FIELD List all values a certain field takes\n"
121 " --setup-keys Generate new FSS key pair\n"
122 " --verify Verify journal file consistency\n"
124 , program_invocation_short_name);
129 static int parse_argv(int argc, char *argv[]) {
146 static const struct option options[] = {
147 { "help", no_argument, NULL, 'h' },
148 { "version" , no_argument, NULL, ARG_VERSION },
149 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
150 { "follow", no_argument, NULL, 'f' },
151 { "output", required_argument, NULL, 'o' },
152 { "all", no_argument, NULL, 'a' },
153 { "lines", optional_argument, NULL, 'n' },
154 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
155 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
156 { "quiet", no_argument, NULL, 'q' },
157 { "merge", no_argument, NULL, 'm' },
158 { "this-boot", no_argument, NULL, 'b' },
159 { "directory", required_argument, NULL, 'D' },
160 { "header", no_argument, NULL, ARG_HEADER },
161 { "priority", no_argument, NULL, 'p' },
162 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
163 { "interval", required_argument, NULL, ARG_INTERVAL },
164 { "verify", no_argument, NULL, ARG_VERIFY },
165 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
166 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
167 { "cursor", required_argument, NULL, 'c' },
168 { "since", required_argument, NULL, ARG_SINCE },
169 { "until", required_argument, NULL, ARG_UNTIL },
170 { "unit", required_argument, NULL, 'u' },
171 { "field", required_argument, NULL, 'F' },
180 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:", options, NULL)) >= 0) {
189 puts(PACKAGE_STRING);
191 puts(SYSTEMD_FEATURES);
203 arg_output = output_mode_from_string(optarg);
204 if (arg_output < 0) {
205 log_error("Unknown output format '%s'.", optarg);
209 if (arg_output == OUTPUT_EXPORT ||
210 arg_output == OUTPUT_JSON ||
211 arg_output == OUTPUT_JSON_PRETTY ||
212 arg_output == OUTPUT_JSON_SSE ||
213 arg_output == OUTPUT_CAT)
224 r = safe_atou(optarg, &arg_lines);
225 if (r < 0 || arg_lines <= 0) {
226 log_error("Failed to parse lines '%s'", optarg);
239 arg_action = ACTION_NEW_ID128;
251 arg_this_boot = true;
255 arg_directory = optarg;
263 arg_action = ACTION_PRINT_HEADER;
267 arg_action = ACTION_VERIFY;
271 arg_action = ACTION_DISK_USAGE;
276 arg_action = ACTION_SETUP_KEYS;
281 arg_action = ACTION_VERIFY;
282 arg_verify_key = optarg;
287 r = parse_usec(optarg, &arg_interval);
288 if (r < 0 || arg_interval <= 0) {
289 log_error("Failed to parse sealing key change interval: %s", optarg);
297 log_error("Forward-secure sealing not available.");
304 dots = strstr(optarg, "..");
310 a = strndup(optarg, dots - optarg);
314 from = log_level_from_string(a);
315 to = log_level_from_string(dots + 2);
318 if (from < 0 || to < 0) {
319 log_error("Failed to parse log level range %s", optarg);
326 for (i = from; i <= to; i++)
327 arg_priorities |= 1 << i;
329 for (i = to; i <= from; i++)
330 arg_priorities |= 1 << i;
336 p = log_level_from_string(optarg);
338 log_error("Unknown log level %s", optarg);
344 for (i = 0; i <= p; i++)
345 arg_priorities |= 1 << i;
352 r = parse_timestamp(optarg, &arg_since);
354 log_error("Failed to parse timestamp: %s", optarg);
357 arg_since_set = true;
361 r = parse_timestamp(optarg, &arg_until);
363 log_error("Failed to parse timestamp: %s", optarg);
366 arg_until_set = true;
381 log_error("Unknown option code %c", c);
386 if (arg_follow && !arg_no_tail && arg_lines <= 0)
389 if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
390 log_error("--since= must be before --until=.");
394 if (arg_cursor && arg_since_set) {
395 log_error("Please specify either --since= or --cursor=, not both.");
402 static int generate_new_id128(void) {
407 r = sd_id128_randomize(&id);
409 log_error("Failed to generate ID: %s", strerror(-r));
413 printf("As string:\n"
414 SD_ID128_FORMAT_STR "\n\n"
416 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
418 "#define MESSAGE_XYZ SD_ID128_MAKE(",
419 SD_ID128_FORMAT_VAL(id),
420 SD_ID128_FORMAT_VAL(id));
422 for (i = 0; i < 16; i++)
423 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
425 fputs(")\n", stdout);
430 static int add_matches(sd_journal *j, char **args) {
436 STRV_FOREACH(i, args) {
439 r = sd_journal_add_disjunction(j);
440 else if (path_is_absolute(*i)) {
445 p = canonicalize_file_name(*i);
448 if (stat(path, &st) < 0) {
450 log_error("Couldn't stat file: %m");
454 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
455 t = strappend("_EXE=", path);
456 else if (S_ISCHR(st.st_mode))
457 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
458 else if (S_ISBLK(st.st_mode))
459 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
462 log_error("File is not a device node, regular file or is not executable: %s", *i);
471 r = sd_journal_add_match(j, t, 0);
474 r = sd_journal_add_match(j, *i, 0);
477 log_error("Failed to add match '%s': %s", *i, strerror(-r));
485 static int add_this_boot(sd_journal *j) {
486 char match[9+32+1] = "_BOOT_ID=";
495 r = sd_id128_get_boot(&boot_id);
497 log_error("Failed to get boot id: %s", strerror(-r));
501 sd_id128_to_string(boot_id, match + 9);
502 r = sd_journal_add_match(j, match, strlen(match));
504 log_error("Failed to add match: %s", strerror(-r));
511 static int add_unit(sd_journal *j) {
512 _cleanup_free_ char *m = NULL, *u = NULL;
517 if (isempty(arg_unit))
520 u = unit_name_mangle(arg_unit);
524 m = strappend("_SYSTEMD_UNIT=", u);
528 r = sd_journal_add_match(j, m, strlen(m));
530 log_error("Failed to add match: %s", strerror(-r));
537 static int add_priorities(sd_journal *j) {
538 char match[] = "PRIORITY=0";
543 if (arg_priorities == 0xFF)
546 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
547 if (arg_priorities & (1 << i)) {
548 match[sizeof(match)-2] = '0' + i;
550 r = sd_journal_add_match(j, match, strlen(match));
552 log_error("Failed to add match: %s", strerror(-r));
560 static int setup_keys(void) {
562 size_t mpk_size, seed_size, state_size, i;
563 uint8_t *mpk, *seed, *state;
565 int fd = -1, r, attr = 0;
566 sd_id128_t machine, boot;
567 char *p = NULL, *k = NULL;
571 r = sd_id128_get_machine(&machine);
573 log_error("Failed to get machine ID: %s", strerror(-r));
577 r = sd_id128_get_boot(&boot);
579 log_error("Failed to get boot ID: %s", strerror(-r));
583 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
584 SD_ID128_FORMAT_VAL(machine)) < 0)
587 if (access(p, F_OK) >= 0) {
588 log_error("Sealing key file %s exists already.", p);
593 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
594 SD_ID128_FORMAT_VAL(machine)) < 0) {
599 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
600 mpk = alloca(mpk_size);
602 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
603 seed = alloca(seed_size);
605 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
606 state = alloca(state_size);
608 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
610 log_error("Failed to open /dev/random: %m");
615 log_info("Generating seed...");
616 l = loop_read(fd, seed, seed_size, true);
617 if (l < 0 || (size_t) l != seed_size) {
618 log_error("Failed to read random seed: %s", strerror(EIO));
623 log_info("Generating key pair...");
624 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
626 log_info("Generating sealing key...");
627 FSPRG_GenState0(state, mpk, seed, seed_size);
629 assert(arg_interval > 0);
631 n = now(CLOCK_REALTIME);
634 close_nointr_nofail(fd);
635 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
637 log_error("Failed to open %s: %m", k);
642 /* Enable secure remove, exclusion from dump, synchronous
643 * writing and in-place updating */
644 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
645 log_warning("FS_IOC_GETFLAGS failed: %m");
647 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
649 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
650 log_warning("FS_IOC_SETFLAGS failed: %m");
653 memcpy(h.signature, "KSHHRHLP", 8);
654 h.machine_id = machine;
656 h.header_size = htole64(sizeof(h));
657 h.start_usec = htole64(n * arg_interval);
658 h.interval_usec = htole64(arg_interval);
659 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
660 h.fsprg_state_size = htole64(state_size);
662 l = loop_write(fd, &h, sizeof(h), false);
663 if (l < 0 || (size_t) l != sizeof(h)) {
664 log_error("Failed to write header: %s", strerror(EIO));
669 l = loop_write(fd, state, state_size, false);
670 if (l < 0 || (size_t) l != state_size) {
671 log_error("Failed to write state: %s", strerror(EIO));
676 if (link(k, p) < 0) {
677 log_error("Failed to link file: %m");
685 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
686 "the following local file. This key file is automatically updated when the\n"
687 "sealing key is advanced. It should not be used on multiple hosts.\n"
691 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
692 "at a safe location and should not be saved locally on disk.\n"
693 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
696 for (i = 0; i < seed_size; i++) {
697 if (i > 0 && i % 3 == 0)
699 printf("%02x", ((uint8_t*) seed)[i]);
702 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
705 char tsb[FORMAT_TIMESPAN_MAX], *hn;
708 ANSI_HIGHLIGHT_OFF "\n"
709 "The sealing key is automatically changed every %s.\n",
710 format_timespan(tsb, sizeof(tsb), arg_interval));
712 hn = gethostname_malloc();
715 hostname_cleanup(hn);
716 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
718 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
721 /* If this is not an UTF-8 system don't print any QR codes */
722 setlocale(LC_CTYPE, "");
724 if (streq_ptr(nl_langinfo(CODESET), "UTF-8")) {
725 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
726 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
736 close_nointr_nofail(fd);
747 log_error("Forward-secure sealing not available.");
752 static int verify(sd_journal *j) {
759 log_show_color(true);
761 HASHMAP_FOREACH(f, j->files, i) {
763 usec_t first, validated, last;
766 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
767 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
770 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
772 /* If the key was invalid give up right-away. */
775 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
778 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
779 log_info("PASS: %s", f->path);
781 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
783 log_info("=> Validated from %s to %s, final %s entries not sealed.",
784 format_timestamp(a, sizeof(a), first),
785 format_timestamp(b, sizeof(b), validated),
786 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
788 log_info("=> No sealing yet, %s of entries not sealed.",
789 format_timespan(c, sizeof(c), last - first));
791 log_info("=> No sealing yet, no entries in file.");
799 static int access_check(void) {
802 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
803 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
807 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
808 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
810 if (geteuid() != 0 && in_group("adm") <= 0) {
811 log_error("No access to messages. Only users in the group 'adm' can see messages.");
819 int main(int argc, char *argv[]) {
821 sd_journal *j = NULL;
822 bool need_seek = false;
823 sd_id128_t previous_boot_id;
824 bool previous_boot_id_valid = false;
825 unsigned n_shown = 0;
827 log_parse_environment();
830 r = parse_argv(argc, argv);
834 signal(SIGWINCH, columns_lines_cache_reset);
836 if (arg_action == ACTION_NEW_ID128) {
837 r = generate_new_id128();
841 if (arg_action == ACTION_SETUP_KEYS) {
851 r = sd_journal_open_directory(&j, arg_directory, 0);
853 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
855 log_error("Failed to open journal: %s", strerror(-r));
859 if (arg_action == ACTION_VERIFY) {
864 if (arg_action == ACTION_PRINT_HEADER) {
865 journal_print_header(j);
870 if (arg_action == ACTION_DISK_USAGE) {
872 char sbytes[FORMAT_BYTES_MAX];
874 r = sd_journal_get_usage(j, &bytes);
878 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
883 r = add_this_boot(j);
891 r = add_matches(j, argv + optind);
895 r = add_priorities(j);
903 r = sd_journal_query_unique(j, arg_field);
905 log_error("Failed to query unique data objects: %s", strerror(-r));
909 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
912 if (arg_lines > 0 && n_shown >= arg_lines)
915 eq = memchr(data, '=', size);
917 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
919 printf("%.*s\n", (int) size, (const char*) data);
929 r = sd_journal_seek_cursor(j, arg_cursor);
931 log_error("Failed to seek to cursor: %s", strerror(-r));
935 r = sd_journal_next(j);
937 } else if (arg_since_set) {
938 r = sd_journal_seek_realtime_usec(j, arg_since);
940 log_error("Failed to seek to date: %s", strerror(-r));
943 r = sd_journal_next(j);
945 } else if (arg_lines > 0) {
946 r = sd_journal_seek_tail(j);
948 log_error("Failed to seek to tail: %s", strerror(-r));
952 r = sd_journal_previous_skip(j, arg_lines);
955 r = sd_journal_seek_head(j);
957 log_error("Failed to seek to head: %s", strerror(-r));
961 r = sd_journal_next(j);
965 log_error("Failed to iterate through journal: %s", strerror(-r));
969 if (!arg_no_pager && !arg_follow)
974 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
976 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
978 log_error("Failed to get cutoff: %s", strerror(-r));
984 printf("-- Logs begin at %s. --\n",
985 format_timestamp(start_buf, sizeof(start_buf), start));
987 printf("-- Logs begin at %s, end at %s. --\n",
988 format_timestamp(start_buf, sizeof(start_buf), start),
989 format_timestamp(end_buf, sizeof(end_buf), end));
994 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
998 r = sd_journal_next(j);
1000 log_error("Failed to iterate through journal: %s", strerror(-r));
1008 if (arg_until_set) {
1011 r = sd_journal_get_realtime_usec(j, &usec);
1013 log_error("Failed to determine timestamp: %s", strerror(-r));
1021 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1023 if (previous_boot_id_valid &&
1024 !sd_id128_equal(boot_id, previous_boot_id))
1025 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1027 previous_boot_id = boot_id;
1028 previous_boot_id_valid = true;
1033 arg_all * OUTPUT_SHOW_ALL |
1034 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1035 on_tty() * OUTPUT_COLOR;
1037 r = output_journal(stdout, j, arg_output, 0, flags);
1048 r = sd_journal_wait(j, (uint64_t) -1);
1050 log_error("Couldn't wait for journal event: %s", strerror(-r));
1057 sd_journal_close(j);
1061 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;