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>
37 #include <systemd/sd-journal.h>
41 #include "path-util.h"
44 #include "logs-show.h"
46 #include "journal-internal.h"
47 #include "journal-def.h"
48 #include "journal-verify.h"
49 #include "journal-authenticate.h"
50 #include "journal-qrcode.h"
52 #include "unit-name.h"
54 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
56 static OutputMode arg_output = OUTPUT_SHORT;
57 static bool arg_follow = false;
58 static bool arg_all = false;
59 static bool arg_no_pager = false;
60 static unsigned arg_lines = 0;
61 static bool arg_no_tail = false;
62 static bool arg_quiet = false;
63 static bool arg_merge = false;
64 static bool arg_this_boot = false;
65 static const char *arg_cursor = NULL;
66 static const char *arg_directory = NULL;
67 static int arg_priorities = 0xFF;
68 static const char *arg_verify_key = NULL;
70 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
72 static usec_t arg_since, arg_until;
73 static bool arg_since_set = false, arg_until_set = false;
74 static const char *arg_unit = NULL;
75 static const char *arg_field = NULL;
84 } arg_action = ACTION_SHOW;
86 static int help(void) {
88 printf("%s [OPTIONS...] [MATCHES...]\n\n"
89 "Query the journal.\n\n"
91 " --since=DATE Start showing entries newer or of the specified date\n"
92 " --until=DATE Stop showing entries older or of the specified date\n"
93 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
94 " -b --this-boot Show data only from current boot\n"
95 " -u --unit=UNIT Show data only from the specified unit\n"
96 " -p --priority=RANGE Show only messages within the specified priority range\n"
97 " -f --follow Follow journal\n"
98 " -n --lines[=INTEGER] Number of journal entries to show\n"
99 " --no-tail Show all lines, even in follow mode\n"
100 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
101 " verbose, export, json, json-pretty, json-sse, cat)\n"
102 " -a --all Show all fields, including long and unprintable\n"
103 " -q --quiet Don't show privilege warning\n"
104 " --no-pager Do not pipe output into a pager\n"
105 " -m --merge Show entries from all available journals\n"
106 " -D --directory=PATH Show journal files from directory\n"
108 " --interval=TIME Time interval for changing the FSS sealing key\n"
109 " --verify-key=KEY Specify FSS verification key\n"
112 " -h --help Show this help\n"
113 " --version Show package version\n"
114 " --new-id128 Generate a new 128 Bit ID\n"
115 " --header Show journal header information\n"
116 " --disk-usage Show total disk usage\n"
117 " -F --field=FIELD List all values a certain field takes\n"
119 " --setup-keys Generate new FSS key pair\n"
120 " --verify Verify journal file consistency\n"
122 , program_invocation_short_name);
127 static int parse_argv(int argc, char *argv[]) {
144 static const struct option options[] = {
145 { "help", no_argument, NULL, 'h' },
146 { "version" , no_argument, NULL, ARG_VERSION },
147 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
148 { "follow", no_argument, NULL, 'f' },
149 { "output", required_argument, NULL, 'o' },
150 { "all", no_argument, NULL, 'a' },
151 { "lines", optional_argument, NULL, 'n' },
152 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
153 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
154 { "quiet", no_argument, NULL, 'q' },
155 { "merge", no_argument, NULL, 'm' },
156 { "this-boot", no_argument, NULL, 'b' },
157 { "directory", required_argument, NULL, 'D' },
158 { "header", no_argument, NULL, ARG_HEADER },
159 { "priority", no_argument, NULL, 'p' },
160 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
161 { "interval", required_argument, NULL, ARG_INTERVAL },
162 { "verify", no_argument, NULL, ARG_VERIFY },
163 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
164 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
165 { "cursor", required_argument, NULL, 'c' },
166 { "since", required_argument, NULL, ARG_SINCE },
167 { "until", required_argument, NULL, ARG_UNTIL },
168 { "unit", required_argument, NULL, 'u' },
169 { "field", required_argument, NULL, 'F' },
178 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:", options, NULL)) >= 0) {
187 puts(PACKAGE_STRING);
189 puts(SYSTEMD_FEATURES);
201 arg_output = output_mode_from_string(optarg);
202 if (arg_output < 0) {
203 log_error("Unknown output format '%s'.", optarg);
207 if (arg_output == OUTPUT_EXPORT ||
208 arg_output == OUTPUT_JSON ||
209 arg_output == OUTPUT_JSON_PRETTY ||
210 arg_output == OUTPUT_JSON_SSE ||
211 arg_output == OUTPUT_CAT)
222 r = safe_atou(optarg, &arg_lines);
223 if (r < 0 || arg_lines <= 0) {
224 log_error("Failed to parse lines '%s'", optarg);
237 arg_action = ACTION_NEW_ID128;
249 arg_this_boot = true;
253 arg_directory = optarg;
261 arg_action = ACTION_PRINT_HEADER;
265 arg_action = ACTION_VERIFY;
269 arg_action = ACTION_DISK_USAGE;
274 arg_action = ACTION_SETUP_KEYS;
279 arg_action = ACTION_VERIFY;
280 arg_verify_key = optarg;
285 r = parse_usec(optarg, &arg_interval);
286 if (r < 0 || arg_interval <= 0) {
287 log_error("Failed to parse sealing key change interval: %s", optarg);
295 log_error("Forward-secure sealing not available.");
302 dots = strstr(optarg, "..");
308 a = strndup(optarg, dots - optarg);
312 from = log_level_from_string(a);
313 to = log_level_from_string(dots + 2);
316 if (from < 0 || to < 0) {
317 log_error("Failed to parse log level range %s", optarg);
324 for (i = from; i <= to; i++)
325 arg_priorities |= 1 << i;
327 for (i = to; i <= from; i++)
328 arg_priorities |= 1 << i;
334 p = log_level_from_string(optarg);
336 log_error("Unknown log level %s", optarg);
342 for (i = 0; i <= p; i++)
343 arg_priorities |= 1 << i;
350 r = parse_timestamp(optarg, &arg_since);
352 log_error("Failed to parse timestamp: %s", optarg);
355 arg_since_set = true;
359 r = parse_timestamp(optarg, &arg_until);
361 log_error("Failed to parse timestamp: %s", optarg);
364 arg_until_set = true;
379 log_error("Unknown option code %c", c);
384 if (arg_follow && !arg_no_tail && arg_lines <= 0)
387 if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
388 log_error("--since= must be before --until=.");
392 if (arg_cursor && arg_since_set) {
393 log_error("Please specify either --since= or --cursor=, not both.");
400 static int generate_new_id128(void) {
405 r = sd_id128_randomize(&id);
407 log_error("Failed to generate ID: %s", strerror(-r));
411 printf("As string:\n"
412 SD_ID128_FORMAT_STR "\n\n"
414 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
416 "#define MESSAGE_XYZ SD_ID128_MAKE(",
417 SD_ID128_FORMAT_VAL(id),
418 SD_ID128_FORMAT_VAL(id));
420 for (i = 0; i < 16; i++)
421 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
423 fputs(")\n", stdout);
428 static int add_matches(sd_journal *j, char **args) {
434 STRV_FOREACH(i, args) {
437 r = sd_journal_add_disjunction(j);
438 else if (path_is_absolute(*i)) {
443 p = canonicalize_file_name(*i);
446 if (stat(path, &st) < 0) {
448 log_error("Couldn't stat file: %m");
452 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
453 t = strappend("_EXE=", path);
454 else if (S_ISCHR(st.st_mode))
455 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
456 else if (S_ISBLK(st.st_mode))
457 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
460 log_error("File is not a device node, regular file or is not executable: %s", *i);
469 r = sd_journal_add_match(j, t, 0);
472 r = sd_journal_add_match(j, *i, 0);
475 log_error("Failed to add match '%s': %s", *i, strerror(-r));
483 static int add_this_boot(sd_journal *j) {
484 char match[9+32+1] = "_BOOT_ID=";
493 r = sd_id128_get_boot(&boot_id);
495 log_error("Failed to get boot id: %s", strerror(-r));
499 sd_id128_to_string(boot_id, match + 9);
500 r = sd_journal_add_match(j, match, strlen(match));
502 log_error("Failed to add match: %s", strerror(-r));
509 static int add_unit(sd_journal *j) {
510 _cleanup_free_ char *m = NULL, *u = NULL;
515 if (isempty(arg_unit))
518 u = unit_name_mangle(arg_unit);
522 m = strappend("_SYSTEMD_UNIT=", u);
526 r = sd_journal_add_match(j, m, strlen(m));
528 log_error("Failed to add match: %s", strerror(-r));
535 static int add_priorities(sd_journal *j) {
536 char match[] = "PRIORITY=0";
541 if (arg_priorities == 0xFF)
544 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
545 if (arg_priorities & (1 << i)) {
546 match[sizeof(match)-2] = '0' + i;
548 r = sd_journal_add_match(j, match, strlen(match));
550 log_error("Failed to add match: %s", strerror(-r));
558 static int setup_keys(void) {
560 size_t mpk_size, seed_size, state_size, i;
561 uint8_t *mpk, *seed, *state;
563 int fd = -1, r, attr = 0;
564 sd_id128_t machine, boot;
565 char *p = NULL, *k = NULL;
569 r = sd_id128_get_machine(&machine);
571 log_error("Failed to get machine ID: %s", strerror(-r));
575 r = sd_id128_get_boot(&boot);
577 log_error("Failed to get boot ID: %s", strerror(-r));
581 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
582 SD_ID128_FORMAT_VAL(machine)) < 0)
585 if (access(p, F_OK) >= 0) {
586 log_error("Sealing key file %s exists already.", p);
591 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
592 SD_ID128_FORMAT_VAL(machine)) < 0) {
597 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
598 mpk = alloca(mpk_size);
600 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
601 seed = alloca(seed_size);
603 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
604 state = alloca(state_size);
606 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
608 log_error("Failed to open /dev/random: %m");
613 log_info("Generating seed...");
614 l = loop_read(fd, seed, seed_size, true);
615 if (l < 0 || (size_t) l != seed_size) {
616 log_error("Failed to read random seed: %s", strerror(EIO));
621 log_info("Generating key pair...");
622 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
624 log_info("Generating sealing key...");
625 FSPRG_GenState0(state, mpk, seed, seed_size);
627 assert(arg_interval > 0);
629 n = now(CLOCK_REALTIME);
632 close_nointr_nofail(fd);
633 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
635 log_error("Failed to open %s: %m", k);
640 /* Enable secure remove, exclusion from dump, synchronous
641 * writing and in-place updating */
642 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
643 log_warning("FS_IOC_GETFLAGS failed: %m");
645 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
647 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
648 log_warning("FS_IOC_SETFLAGS failed: %m");
651 memcpy(h.signature, "KSHHRHLP", 8);
652 h.machine_id = machine;
654 h.header_size = htole64(sizeof(h));
655 h.start_usec = htole64(n * arg_interval);
656 h.interval_usec = htole64(arg_interval);
657 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
658 h.fsprg_state_size = htole64(state_size);
660 l = loop_write(fd, &h, sizeof(h), false);
661 if (l < 0 || (size_t) l != sizeof(h)) {
662 log_error("Failed to write header: %s", strerror(EIO));
667 l = loop_write(fd, state, state_size, false);
668 if (l < 0 || (size_t) l != state_size) {
669 log_error("Failed to write state: %s", strerror(EIO));
674 if (link(k, p) < 0) {
675 log_error("Failed to link file: %m");
683 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
684 "the following local file. This key file is automatically updated when the\n"
685 "sealing key is advanced. It should not be used on multiple hosts.\n"
689 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
690 "at a safe location and should not be saved locally on disk.\n"
691 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
694 for (i = 0; i < seed_size; i++) {
695 if (i > 0 && i % 3 == 0)
697 printf("%02x", ((uint8_t*) seed)[i]);
700 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
703 char tsb[FORMAT_TIMESPAN_MAX], *hn;
706 ANSI_HIGHLIGHT_OFF "\n"
707 "The sealing key is automatically changed every %s.\n",
708 format_timespan(tsb, sizeof(tsb), arg_interval));
710 hn = gethostname_malloc();
713 hostname_cleanup(hn);
714 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
716 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
719 /* If this is not an UTF-8 system don't print any QR codes */
720 if (is_locale_utf8()) {
721 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
722 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
732 close_nointr_nofail(fd);
743 log_error("Forward-secure sealing not available.");
748 static int verify(sd_journal *j) {
755 log_show_color(true);
757 HASHMAP_FOREACH(f, j->files, i) {
759 usec_t first, validated, last;
762 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
763 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
766 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
768 /* If the key was invalid give up right-away. */
771 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
774 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
775 log_info("PASS: %s", f->path);
777 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
779 log_info("=> Validated from %s to %s, final %s entries not sealed.",
780 format_timestamp(a, sizeof(a), first),
781 format_timestamp(b, sizeof(b), validated),
782 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
784 log_info("=> No sealing yet, %s of entries not sealed.",
785 format_timespan(c, sizeof(c), last - first));
787 log_info("=> No sealing yet, no entries in file.");
795 static int access_check(void) {
798 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
799 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
803 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
804 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
806 if (geteuid() != 0 && in_group("adm") <= 0) {
807 log_error("No access to messages. Only users in the group 'adm' can see messages.");
815 int main(int argc, char *argv[]) {
817 sd_journal *j = NULL;
818 bool need_seek = false;
819 sd_id128_t previous_boot_id;
820 bool previous_boot_id_valid = false;
821 unsigned n_shown = 0;
823 log_parse_environment();
826 r = parse_argv(argc, argv);
830 signal(SIGWINCH, columns_lines_cache_reset);
832 if (arg_action == ACTION_NEW_ID128) {
833 r = generate_new_id128();
837 if (arg_action == ACTION_SETUP_KEYS) {
847 r = sd_journal_open_directory(&j, arg_directory, 0);
849 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
851 log_error("Failed to open journal: %s", strerror(-r));
855 if (arg_action == ACTION_VERIFY) {
860 if (arg_action == ACTION_PRINT_HEADER) {
861 journal_print_header(j);
866 if (arg_action == ACTION_DISK_USAGE) {
868 char sbytes[FORMAT_BYTES_MAX];
870 r = sd_journal_get_usage(j, &bytes);
874 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
879 r = add_this_boot(j);
887 r = add_matches(j, argv + optind);
891 r = add_priorities(j);
899 r = sd_journal_query_unique(j, arg_field);
901 log_error("Failed to query unique data objects: %s", strerror(-r));
905 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
908 if (arg_lines > 0 && n_shown >= arg_lines)
911 eq = memchr(data, '=', size);
913 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
915 printf("%.*s\n", (int) size, (const char*) data);
925 r = sd_journal_seek_cursor(j, arg_cursor);
927 log_error("Failed to seek to cursor: %s", strerror(-r));
931 r = sd_journal_next(j);
933 } else if (arg_since_set) {
934 r = sd_journal_seek_realtime_usec(j, arg_since);
936 log_error("Failed to seek to date: %s", strerror(-r));
939 r = sd_journal_next(j);
941 } else if (arg_lines > 0) {
942 r = sd_journal_seek_tail(j);
944 log_error("Failed to seek to tail: %s", strerror(-r));
948 r = sd_journal_previous_skip(j, arg_lines);
951 r = sd_journal_seek_head(j);
953 log_error("Failed to seek to head: %s", strerror(-r));
957 r = sd_journal_next(j);
961 log_error("Failed to iterate through journal: %s", strerror(-r));
965 if (!arg_no_pager && !arg_follow)
970 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
972 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
974 log_error("Failed to get cutoff: %s", strerror(-r));
980 printf("-- Logs begin at %s. --\n",
981 format_timestamp(start_buf, sizeof(start_buf), start));
983 printf("-- Logs begin at %s, end at %s. --\n",
984 format_timestamp(start_buf, sizeof(start_buf), start),
985 format_timestamp(end_buf, sizeof(end_buf), end));
990 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
994 r = sd_journal_next(j);
996 log_error("Failed to iterate through journal: %s", strerror(-r));
1004 if (arg_until_set) {
1007 r = sd_journal_get_realtime_usec(j, &usec);
1009 log_error("Failed to determine timestamp: %s", strerror(-r));
1017 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1019 if (previous_boot_id_valid &&
1020 !sd_id128_equal(boot_id, previous_boot_id))
1021 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1023 previous_boot_id = boot_id;
1024 previous_boot_id_valid = true;
1029 arg_all * OUTPUT_SHOW_ALL |
1030 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1031 on_tty() * OUTPUT_COLOR;
1033 r = output_journal(stdout, j, arg_output, 0, flags);
1044 r = sd_journal_wait(j, (uint64_t) -1);
1046 log_error("Couldn't wait for journal event: %s", strerror(-r));
1053 sd_journal_close(j);
1057 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;