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/>.
35 #include <sys/ioctl.h>
38 #include <systemd/sd-journal.h>
42 #include "path-util.h"
45 #include "logs-show.h"
47 #include "journal-internal.h"
48 #include "journal-def.h"
49 #include "journal-verify.h"
50 #include "journal-authenticate.h"
51 #include "journal-qrcode.h"
53 #include "unit-name.h"
55 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
57 static OutputMode arg_output = OUTPUT_SHORT;
58 static bool arg_follow = false;
59 static bool arg_all = false;
60 static bool arg_no_pager = false;
61 static unsigned arg_lines = 0;
62 static bool arg_no_tail = false;
63 static bool arg_quiet = false;
64 static bool arg_merge = false;
65 static bool arg_this_boot = false;
66 static const char *arg_cursor = NULL;
67 static const char *arg_directory = NULL;
68 static int arg_priorities = 0xFF;
69 static const char *arg_verify_key = NULL;
71 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
73 static usec_t arg_since, arg_until;
74 static bool arg_since_set = false, arg_until_set = false;
75 static const char *arg_unit = NULL;
76 static const char *arg_field = NULL;
85 } arg_action = ACTION_SHOW;
87 static int help(void) {
89 printf("%s [OPTIONS...] [MATCHES...]\n\n"
90 "Query the journal.\n\n"
92 " --since=DATE Start showing entries newer or of the specified date\n"
93 " --until=DATE Stop showing entries older or of the specified date\n"
94 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
95 " -b --this-boot Show data only from current boot\n"
96 " -u --unit=UNIT Show data only from the specified unit\n"
97 " -p --priority=RANGE Show only messages within the specified priority range\n"
98 " -f --follow Follow journal\n"
99 " -n --lines[=INTEGER] Number of journal entries to show\n"
100 " --no-tail Show all lines, even in follow mode\n"
101 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
102 " verbose, export, json, json-pretty, json-sse, cat)\n"
103 " -a --all Show all fields, including long and unprintable\n"
104 " -q --quiet Don't show privilege warning\n"
105 " --no-pager Do not pipe output into a pager\n"
106 " -m --merge Show entries from all available journals\n"
107 " -D --directory=PATH Show journal files from directory\n"
109 " --interval=TIME Time interval for changing the FSS sealing key\n"
110 " --verify-key=KEY Specify FSS verification key\n"
113 " -h --help Show this help\n"
114 " --version Show package version\n"
115 " --new-id128 Generate a new 128 Bit ID\n"
116 " --header Show journal header information\n"
117 " --disk-usage Show total disk usage\n"
118 " -F --field=FIELD List all values a certain field takes\n"
120 " --setup-keys Generate new FSS key pair\n"
121 " --verify Verify journal file consistency\n"
123 , program_invocation_short_name);
128 static int parse_argv(int argc, char *argv[]) {
145 static const struct option options[] = {
146 { "help", no_argument, NULL, 'h' },
147 { "version" , no_argument, NULL, ARG_VERSION },
148 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
149 { "follow", no_argument, NULL, 'f' },
150 { "output", required_argument, NULL, 'o' },
151 { "all", no_argument, NULL, 'a' },
152 { "lines", optional_argument, NULL, 'n' },
153 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
154 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
155 { "quiet", no_argument, NULL, 'q' },
156 { "merge", no_argument, NULL, 'm' },
157 { "this-boot", no_argument, NULL, 'b' },
158 { "directory", required_argument, NULL, 'D' },
159 { "header", no_argument, NULL, ARG_HEADER },
160 { "priority", no_argument, NULL, 'p' },
161 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
162 { "interval", required_argument, NULL, ARG_INTERVAL },
163 { "verify", no_argument, NULL, ARG_VERIFY },
164 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
165 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
166 { "cursor", required_argument, NULL, 'c' },
167 { "since", required_argument, NULL, ARG_SINCE },
168 { "until", required_argument, NULL, ARG_UNTIL },
169 { "unit", required_argument, NULL, 'u' },
170 { "field", required_argument, NULL, 'F' },
179 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:", options, NULL)) >= 0) {
188 puts(PACKAGE_STRING);
190 puts(SYSTEMD_FEATURES);
202 arg_output = output_mode_from_string(optarg);
203 if (arg_output < 0) {
204 log_error("Unknown output format '%s'.", optarg);
208 if (arg_output == OUTPUT_EXPORT ||
209 arg_output == OUTPUT_JSON ||
210 arg_output == OUTPUT_JSON_PRETTY ||
211 arg_output == OUTPUT_JSON_SSE ||
212 arg_output == OUTPUT_CAT)
223 r = safe_atou(optarg, &arg_lines);
224 if (r < 0 || arg_lines <= 0) {
225 log_error("Failed to parse lines '%s'", optarg);
238 arg_action = ACTION_NEW_ID128;
250 arg_this_boot = true;
254 arg_directory = optarg;
262 arg_action = ACTION_PRINT_HEADER;
266 arg_action = ACTION_VERIFY;
270 arg_action = ACTION_DISK_USAGE;
275 arg_action = ACTION_SETUP_KEYS;
280 arg_action = ACTION_VERIFY;
281 arg_verify_key = optarg;
286 r = parse_usec(optarg, &arg_interval);
287 if (r < 0 || arg_interval <= 0) {
288 log_error("Failed to parse sealing key change interval: %s", optarg);
296 log_error("Forward-secure sealing not available.");
303 dots = strstr(optarg, "..");
309 a = strndup(optarg, dots - optarg);
313 from = log_level_from_string(a);
314 to = log_level_from_string(dots + 2);
317 if (from < 0 || to < 0) {
318 log_error("Failed to parse log level range %s", optarg);
325 for (i = from; i <= to; i++)
326 arg_priorities |= 1 << i;
328 for (i = to; i <= from; i++)
329 arg_priorities |= 1 << i;
335 p = log_level_from_string(optarg);
337 log_error("Unknown log level %s", optarg);
343 for (i = 0; i <= p; i++)
344 arg_priorities |= 1 << i;
351 r = parse_timestamp(optarg, &arg_since);
353 log_error("Failed to parse timestamp: %s", optarg);
356 arg_since_set = true;
360 r = parse_timestamp(optarg, &arg_until);
362 log_error("Failed to parse timestamp: %s", optarg);
365 arg_until_set = true;
380 log_error("Unknown option code %c", c);
385 if (arg_follow && !arg_no_tail && arg_lines <= 0)
388 if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
389 log_error("--since= must be before --until=.");
393 if (arg_cursor && arg_since_set) {
394 log_error("Please specify either --since= or --cursor=, not both.");
401 static int generate_new_id128(void) {
406 r = sd_id128_randomize(&id);
408 log_error("Failed to generate ID: %s", strerror(-r));
412 printf("As string:\n"
413 SD_ID128_FORMAT_STR "\n\n"
415 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
417 "#define MESSAGE_XYZ SD_ID128_MAKE(",
418 SD_ID128_FORMAT_VAL(id),
419 SD_ID128_FORMAT_VAL(id));
421 for (i = 0; i < 16; i++)
422 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
424 fputs(")\n", stdout);
429 static int add_matches(sd_journal *j, char **args) {
435 STRV_FOREACH(i, args) {
438 r = sd_journal_add_disjunction(j);
439 else if (path_is_absolute(*i)) {
444 p = canonicalize_file_name(*i);
447 if (stat(path, &st) < 0) {
449 log_error("Couldn't stat file: %m");
453 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
454 t = strappend("_EXE=", path);
455 else if (S_ISCHR(st.st_mode))
456 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
457 else if (S_ISBLK(st.st_mode))
458 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
461 log_error("File is not a device node, regular file or is not executable: %s", *i);
470 r = sd_journal_add_match(j, t, 0);
473 r = sd_journal_add_match(j, *i, 0);
476 log_error("Failed to add match '%s': %s", *i, strerror(-r));
484 static int add_this_boot(sd_journal *j) {
485 char match[9+32+1] = "_BOOT_ID=";
494 r = sd_id128_get_boot(&boot_id);
496 log_error("Failed to get boot id: %s", strerror(-r));
500 sd_id128_to_string(boot_id, match + 9);
501 r = sd_journal_add_match(j, match, strlen(match));
503 log_error("Failed to add match: %s", strerror(-r));
510 static int add_unit(sd_journal *j) {
511 _cleanup_free_ char *m = NULL, *u = NULL;
516 if (isempty(arg_unit))
519 u = unit_name_mangle(arg_unit);
523 m = strappend("_SYSTEMD_UNIT=", u);
527 r = sd_journal_add_match(j, m, strlen(m));
529 log_error("Failed to add match: %s", strerror(-r));
536 static int add_priorities(sd_journal *j) {
537 char match[] = "PRIORITY=0";
542 if (arg_priorities == 0xFF)
545 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
546 if (arg_priorities & (1 << i)) {
547 match[sizeof(match)-2] = '0' + i;
549 r = sd_journal_add_match(j, match, strlen(match));
551 log_error("Failed to add match: %s", strerror(-r));
559 static int setup_keys(void) {
561 size_t mpk_size, seed_size, state_size, i;
562 uint8_t *mpk, *seed, *state;
564 int fd = -1, r, attr = 0;
565 sd_id128_t machine, boot;
566 char *p = NULL, *k = NULL;
570 r = sd_id128_get_machine(&machine);
572 log_error("Failed to get machine ID: %s", strerror(-r));
576 r = sd_id128_get_boot(&boot);
578 log_error("Failed to get boot ID: %s", strerror(-r));
582 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
583 SD_ID128_FORMAT_VAL(machine)) < 0)
586 if (access(p, F_OK) >= 0) {
587 log_error("Sealing key file %s exists already.", p);
592 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
593 SD_ID128_FORMAT_VAL(machine)) < 0) {
598 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
599 mpk = alloca(mpk_size);
601 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
602 seed = alloca(seed_size);
604 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
605 state = alloca(state_size);
607 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
609 log_error("Failed to open /dev/random: %m");
614 log_info("Generating seed...");
615 l = loop_read(fd, seed, seed_size, true);
616 if (l < 0 || (size_t) l != seed_size) {
617 log_error("Failed to read random seed: %s", strerror(EIO));
622 log_info("Generating key pair...");
623 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
625 log_info("Generating sealing key...");
626 FSPRG_GenState0(state, mpk, seed, seed_size);
628 assert(arg_interval > 0);
630 n = now(CLOCK_REALTIME);
633 close_nointr_nofail(fd);
634 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
636 log_error("Failed to open %s: %m", k);
641 /* Enable secure remove, exclusion from dump, synchronous
642 * writing and in-place updating */
643 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
644 log_warning("FS_IOC_GETFLAGS failed: %m");
646 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
648 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
649 log_warning("FS_IOC_SETFLAGS failed: %m");
652 memcpy(h.signature, "KSHHRHLP", 8);
653 h.machine_id = machine;
655 h.header_size = htole64(sizeof(h));
656 h.start_usec = htole64(n * arg_interval);
657 h.interval_usec = htole64(arg_interval);
658 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
659 h.fsprg_state_size = htole64(state_size);
661 l = loop_write(fd, &h, sizeof(h), false);
662 if (l < 0 || (size_t) l != sizeof(h)) {
663 log_error("Failed to write header: %s", strerror(EIO));
668 l = loop_write(fd, state, state_size, false);
669 if (l < 0 || (size_t) l != state_size) {
670 log_error("Failed to write state: %s", strerror(EIO));
675 if (link(k, p) < 0) {
676 log_error("Failed to link file: %m");
684 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
685 "the following local file. This key file is automatically updated when the\n"
686 "sealing key is advanced. It should not be used on multiple hosts.\n"
690 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
691 "at a safe location and should not be saved locally on disk.\n"
692 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
695 for (i = 0; i < seed_size; i++) {
696 if (i > 0 && i % 3 == 0)
698 printf("%02x", ((uint8_t*) seed)[i]);
701 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
704 char tsb[FORMAT_TIMESPAN_MAX], *hn;
707 ANSI_HIGHLIGHT_OFF "\n"
708 "The sealing key is automatically changed every %s.\n",
709 format_timespan(tsb, sizeof(tsb), arg_interval));
711 hn = gethostname_malloc();
714 hostname_cleanup(hn);
715 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
717 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
720 /* If this is not an UTF-8 system don't print any QR codes */
721 if (is_locale_utf8()) {
722 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
723 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
733 close_nointr_nofail(fd);
744 log_error("Forward-secure sealing not available.");
749 static int verify(sd_journal *j) {
756 log_show_color(true);
758 HASHMAP_FOREACH(f, j->files, i) {
760 usec_t first, validated, last;
763 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
764 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
767 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
769 /* If the key was invalid give up right-away. */
772 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
775 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
776 log_info("PASS: %s", f->path);
778 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
780 log_info("=> Validated from %s to %s, final %s entries not sealed.",
781 format_timestamp(a, sizeof(a), first),
782 format_timestamp(b, sizeof(b), validated),
783 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
785 log_info("=> No sealing yet, %s of entries not sealed.",
786 format_timespan(c, sizeof(c), last - first));
788 log_info("=> No sealing yet, no entries in file.");
796 static int access_check(void) {
799 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
800 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
804 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
805 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
807 if (geteuid() != 0 && in_group("adm") <= 0) {
808 log_error("No access to messages. Only users in the group 'adm' can see messages.");
816 int main(int argc, char *argv[]) {
818 sd_journal *j = NULL;
819 bool need_seek = false;
820 sd_id128_t previous_boot_id;
821 bool previous_boot_id_valid = false;
822 unsigned n_shown = 0;
824 setlocale(LC_ALL, "");
825 log_parse_environment();
828 r = parse_argv(argc, argv);
832 signal(SIGWINCH, columns_lines_cache_reset);
834 if (arg_action == ACTION_NEW_ID128) {
835 r = generate_new_id128();
839 if (arg_action == ACTION_SETUP_KEYS) {
849 r = sd_journal_open_directory(&j, arg_directory, 0);
851 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
853 log_error("Failed to open journal: %s", strerror(-r));
857 if (arg_action == ACTION_VERIFY) {
862 if (arg_action == ACTION_PRINT_HEADER) {
863 journal_print_header(j);
868 if (arg_action == ACTION_DISK_USAGE) {
870 char sbytes[FORMAT_BYTES_MAX];
872 r = sd_journal_get_usage(j, &bytes);
876 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
881 r = add_this_boot(j);
889 r = add_matches(j, argv + optind);
893 r = add_priorities(j);
901 r = sd_journal_query_unique(j, arg_field);
903 log_error("Failed to query unique data objects: %s", strerror(-r));
907 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
910 if (arg_lines > 0 && n_shown >= arg_lines)
913 eq = memchr(data, '=', size);
915 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
917 printf("%.*s\n", (int) size, (const char*) data);
927 r = sd_journal_seek_cursor(j, arg_cursor);
929 log_error("Failed to seek to cursor: %s", strerror(-r));
933 r = sd_journal_next(j);
935 } else if (arg_since_set) {
936 r = sd_journal_seek_realtime_usec(j, arg_since);
938 log_error("Failed to seek to date: %s", strerror(-r));
941 r = sd_journal_next(j);
943 } else if (arg_lines > 0) {
944 r = sd_journal_seek_tail(j);
946 log_error("Failed to seek to tail: %s", strerror(-r));
950 r = sd_journal_previous_skip(j, arg_lines);
953 r = sd_journal_seek_head(j);
955 log_error("Failed to seek to head: %s", strerror(-r));
959 r = sd_journal_next(j);
963 log_error("Failed to iterate through journal: %s", strerror(-r));
967 if (!arg_no_pager && !arg_follow)
972 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
974 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
976 log_error("Failed to get cutoff: %s", strerror(-r));
982 printf("-- Logs begin at %s. --\n",
983 format_timestamp(start_buf, sizeof(start_buf), start));
985 printf("-- Logs begin at %s, end at %s. --\n",
986 format_timestamp(start_buf, sizeof(start_buf), start),
987 format_timestamp(end_buf, sizeof(end_buf), end));
992 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
996 r = sd_journal_next(j);
998 log_error("Failed to iterate through journal: %s", strerror(-r));
1006 if (arg_until_set) {
1009 r = sd_journal_get_realtime_usec(j, &usec);
1011 log_error("Failed to determine timestamp: %s", strerror(-r));
1019 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1021 if (previous_boot_id_valid &&
1022 !sd_id128_equal(boot_id, previous_boot_id))
1023 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1025 previous_boot_id = boot_id;
1026 previous_boot_id_valid = true;
1031 arg_all * OUTPUT_SHOW_ALL |
1032 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1033 on_tty() * OUTPUT_COLOR;
1035 r = output_journal(stdout, j, arg_output, 0, flags);
1046 r = sd_journal_wait(j, (uint64_t) -1);
1048 log_error("Couldn't wait for journal event: %s", strerror(-r));
1055 sd_journal_close(j);
1059 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;