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"
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;
78 static bool arg_catalog = false;
89 } arg_action = ACTION_SHOW;
91 static int help(void) {
93 printf("%s [OPTIONS...] [MATCHES...]\n\n"
94 "Query the journal.\n\n"
96 " --since=DATE Start showing entries newer or of the specified date\n"
97 " --until=DATE Stop showing entries older or of the specified date\n"
98 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
99 " -b --this-boot Show data only from current boot\n"
100 " -u --unit=UNIT Show data only from the specified unit\n"
101 " -p --priority=RANGE Show only messages within the specified priority range\n"
102 " -f --follow Follow journal\n"
103 " -n --lines[=INTEGER] Number of journal entries to show\n"
104 " --no-tail Show all lines, even in follow mode\n"
105 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
106 " verbose, export, json, json-pretty, json-sse, cat)\n"
107 " -x --catalog Add message explanations where available\n"
108 " -a --all Show all fields, including long and unprintable\n"
109 " -q --quiet Don't show privilege warning\n"
110 " --no-pager Do not pipe output into a pager\n"
111 " -m --merge Show entries from all available journals\n"
112 " -D --directory=PATH Show journal files from directory\n"
114 " --interval=TIME Time interval for changing the FSS sealing key\n"
115 " --verify-key=KEY Specify FSS verification key\n"
118 " -h --help Show this help\n"
119 " --version Show package version\n"
120 " --new-id128 Generate a new 128 Bit ID\n"
121 " --header Show journal header information\n"
122 " --disk-usage Show total disk usage\n"
123 " -F --field=FIELD List all values a certain field takes\n"
124 " --list-catalog Show message IDs of all entries in the message catalog\n"
125 " --update-catalog Update the message catalog database\n"
127 " --setup-keys Generate new FSS key pair\n"
128 " --verify Verify journal file consistency\n"
130 , program_invocation_short_name);
135 static int parse_argv(int argc, char *argv[]) {
154 static const struct option options[] = {
155 { "help", no_argument, NULL, 'h' },
156 { "version" , no_argument, NULL, ARG_VERSION },
157 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
158 { "follow", no_argument, NULL, 'f' },
159 { "output", required_argument, NULL, 'o' },
160 { "all", no_argument, NULL, 'a' },
161 { "lines", optional_argument, NULL, 'n' },
162 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
163 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
164 { "quiet", no_argument, NULL, 'q' },
165 { "merge", no_argument, NULL, 'm' },
166 { "this-boot", no_argument, NULL, 'b' },
167 { "directory", required_argument, NULL, 'D' },
168 { "header", no_argument, NULL, ARG_HEADER },
169 { "priority", required_argument, NULL, 'p' },
170 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
171 { "interval", required_argument, NULL, ARG_INTERVAL },
172 { "verify", no_argument, NULL, ARG_VERIFY },
173 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
174 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
175 { "cursor", required_argument, NULL, 'c' },
176 { "since", required_argument, NULL, ARG_SINCE },
177 { "until", required_argument, NULL, ARG_UNTIL },
178 { "unit", required_argument, NULL, 'u' },
179 { "field", required_argument, NULL, 'F' },
180 { "catalog", no_argument, NULL, 'x' },
181 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
182 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
191 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:x", options, NULL)) >= 0) {
200 puts(PACKAGE_STRING);
202 puts(SYSTEMD_FEATURES);
214 arg_output = output_mode_from_string(optarg);
215 if (arg_output < 0) {
216 log_error("Unknown output format '%s'.", optarg);
220 if (arg_output == OUTPUT_EXPORT ||
221 arg_output == OUTPUT_JSON ||
222 arg_output == OUTPUT_JSON_PRETTY ||
223 arg_output == OUTPUT_JSON_SSE ||
224 arg_output == OUTPUT_CAT)
235 r = safe_atou(optarg, &arg_lines);
236 if (r < 0 || arg_lines <= 0) {
237 log_error("Failed to parse lines '%s'", optarg);
250 arg_action = ACTION_NEW_ID128;
262 arg_this_boot = true;
266 arg_directory = optarg;
274 arg_action = ACTION_PRINT_HEADER;
278 arg_action = ACTION_VERIFY;
282 arg_action = ACTION_DISK_USAGE;
287 arg_action = ACTION_SETUP_KEYS;
292 arg_action = ACTION_VERIFY;
293 arg_verify_key = optarg;
298 r = parse_usec(optarg, &arg_interval);
299 if (r < 0 || arg_interval <= 0) {
300 log_error("Failed to parse sealing key change interval: %s", optarg);
308 log_error("Forward-secure sealing not available.");
315 dots = strstr(optarg, "..");
321 a = strndup(optarg, dots - optarg);
325 from = log_level_from_string(a);
326 to = log_level_from_string(dots + 2);
329 if (from < 0 || to < 0) {
330 log_error("Failed to parse log level range %s", optarg);
337 for (i = from; i <= to; i++)
338 arg_priorities |= 1 << i;
340 for (i = to; i <= from; i++)
341 arg_priorities |= 1 << i;
347 p = log_level_from_string(optarg);
349 log_error("Unknown log level %s", optarg);
355 for (i = 0; i <= p; i++)
356 arg_priorities |= 1 << i;
363 r = parse_timestamp(optarg, &arg_since);
365 log_error("Failed to parse timestamp: %s", optarg);
368 arg_since_set = true;
372 r = parse_timestamp(optarg, &arg_until);
374 log_error("Failed to parse timestamp: %s", optarg);
377 arg_until_set = true;
395 case ARG_LIST_CATALOG:
396 arg_action = ACTION_LIST_CATALOG;
399 case ARG_UPDATE_CATALOG:
400 arg_action = ACTION_UPDATE_CATALOG;
404 log_error("Unknown option code %c", c);
409 if (arg_follow && !arg_no_tail && arg_lines <= 0)
412 if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
413 log_error("--since= must be before --until=.");
417 if (arg_cursor && arg_since_set) {
418 log_error("Please specify either --since= or --cursor=, not both.");
425 static int generate_new_id128(void) {
430 r = sd_id128_randomize(&id);
432 log_error("Failed to generate ID: %s", strerror(-r));
436 printf("As string:\n"
437 SD_ID128_FORMAT_STR "\n\n"
439 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
441 "#define MESSAGE_XYZ SD_ID128_MAKE(",
442 SD_ID128_FORMAT_VAL(id),
443 SD_ID128_FORMAT_VAL(id));
445 for (i = 0; i < 16; i++)
446 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
448 fputs(")\n", stdout);
453 static int add_matches(sd_journal *j, char **args) {
459 STRV_FOREACH(i, args) {
462 r = sd_journal_add_disjunction(j);
463 else if (path_is_absolute(*i)) {
468 p = canonicalize_file_name(*i);
471 if (stat(path, &st) < 0) {
473 log_error("Couldn't stat file: %m");
477 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
478 t = strappend("_EXE=", path);
479 else if (S_ISCHR(st.st_mode))
480 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
481 else if (S_ISBLK(st.st_mode))
482 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
485 log_error("File is not a device node, regular file or is not executable: %s", *i);
494 r = sd_journal_add_match(j, t, 0);
497 r = sd_journal_add_match(j, *i, 0);
500 log_error("Failed to add match '%s': %s", *i, strerror(-r));
508 static int add_this_boot(sd_journal *j) {
509 char match[9+32+1] = "_BOOT_ID=";
518 r = sd_id128_get_boot(&boot_id);
520 log_error("Failed to get boot id: %s", strerror(-r));
524 sd_id128_to_string(boot_id, match + 9);
525 r = sd_journal_add_match(j, match, strlen(match));
527 log_error("Failed to add match: %s", strerror(-r));
534 static int add_unit(sd_journal *j) {
535 _cleanup_free_ char *m = NULL, *u = NULL;
540 if (isempty(arg_unit))
543 u = unit_name_mangle(arg_unit);
547 m = strappend("_SYSTEMD_UNIT=", u);
551 r = sd_journal_add_match(j, m, strlen(m));
553 log_error("Failed to add match: %s", strerror(-r));
560 static int add_priorities(sd_journal *j) {
561 char match[] = "PRIORITY=0";
566 if (arg_priorities == 0xFF)
569 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
570 if (arg_priorities & (1 << i)) {
571 match[sizeof(match)-2] = '0' + i;
573 r = sd_journal_add_match(j, match, strlen(match));
575 log_error("Failed to add match: %s", strerror(-r));
583 static int setup_keys(void) {
585 size_t mpk_size, seed_size, state_size, i;
586 uint8_t *mpk, *seed, *state;
588 int fd = -1, r, attr = 0;
589 sd_id128_t machine, boot;
590 char *p = NULL, *k = NULL;
594 r = sd_id128_get_machine(&machine);
596 log_error("Failed to get machine ID: %s", strerror(-r));
600 r = sd_id128_get_boot(&boot);
602 log_error("Failed to get boot ID: %s", strerror(-r));
606 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
607 SD_ID128_FORMAT_VAL(machine)) < 0)
610 if (access(p, F_OK) >= 0) {
611 log_error("Sealing key file %s exists already.", p);
616 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
617 SD_ID128_FORMAT_VAL(machine)) < 0) {
622 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
623 mpk = alloca(mpk_size);
625 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
626 seed = alloca(seed_size);
628 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
629 state = alloca(state_size);
631 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
633 log_error("Failed to open /dev/random: %m");
638 log_info("Generating seed...");
639 l = loop_read(fd, seed, seed_size, true);
640 if (l < 0 || (size_t) l != seed_size) {
641 log_error("Failed to read random seed: %s", strerror(EIO));
646 log_info("Generating key pair...");
647 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
649 log_info("Generating sealing key...");
650 FSPRG_GenState0(state, mpk, seed, seed_size);
652 assert(arg_interval > 0);
654 n = now(CLOCK_REALTIME);
657 close_nointr_nofail(fd);
658 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
660 log_error("Failed to open %s: %m", k);
665 /* Enable secure remove, exclusion from dump, synchronous
666 * writing and in-place updating */
667 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
668 log_warning("FS_IOC_GETFLAGS failed: %m");
670 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
672 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
673 log_warning("FS_IOC_SETFLAGS failed: %m");
676 memcpy(h.signature, "KSHHRHLP", 8);
677 h.machine_id = machine;
679 h.header_size = htole64(sizeof(h));
680 h.start_usec = htole64(n * arg_interval);
681 h.interval_usec = htole64(arg_interval);
682 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
683 h.fsprg_state_size = htole64(state_size);
685 l = loop_write(fd, &h, sizeof(h), false);
686 if (l < 0 || (size_t) l != sizeof(h)) {
687 log_error("Failed to write header: %s", strerror(EIO));
692 l = loop_write(fd, state, state_size, false);
693 if (l < 0 || (size_t) l != state_size) {
694 log_error("Failed to write state: %s", strerror(EIO));
699 if (link(k, p) < 0) {
700 log_error("Failed to link file: %m");
708 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
709 "the following local file. This key file is automatically updated when the\n"
710 "sealing key is advanced. It should not be used on multiple hosts.\n"
714 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
715 "at a safe location and should not be saved locally on disk.\n"
716 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
719 for (i = 0; i < seed_size; i++) {
720 if (i > 0 && i % 3 == 0)
722 printf("%02x", ((uint8_t*) seed)[i]);
725 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
728 char tsb[FORMAT_TIMESPAN_MAX], *hn;
731 ANSI_HIGHLIGHT_OFF "\n"
732 "The sealing key is automatically changed every %s.\n",
733 format_timespan(tsb, sizeof(tsb), arg_interval));
735 hn = gethostname_malloc();
738 hostname_cleanup(hn);
739 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
741 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
744 /* If this is not an UTF-8 system don't print any QR codes */
745 if (is_locale_utf8()) {
746 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
747 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
757 close_nointr_nofail(fd);
768 log_error("Forward-secure sealing not available.");
773 static int verify(sd_journal *j) {
780 log_show_color(true);
782 HASHMAP_FOREACH(f, j->files, i) {
784 usec_t first, validated, last;
787 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
788 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
791 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
793 /* If the key was invalid give up right-away. */
796 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
799 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
800 log_info("PASS: %s", f->path);
802 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
804 log_info("=> Validated from %s to %s, final %s entries not sealed.",
805 format_timestamp(a, sizeof(a), first),
806 format_timestamp(b, sizeof(b), validated),
807 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
809 log_info("=> No sealing yet, %s of entries not sealed.",
810 format_timespan(c, sizeof(c), last - first));
812 log_info("=> No sealing yet, no entries in file.");
820 static int access_check(void) {
823 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
824 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
828 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
829 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
831 if (geteuid() != 0 && in_group("adm") <= 0) {
832 log_error("No access to messages. Only users in the group 'adm' can see messages.");
840 int main(int argc, char *argv[]) {
842 sd_journal *j = NULL;
843 bool need_seek = false;
844 sd_id128_t previous_boot_id;
845 bool previous_boot_id_valid = false;
846 unsigned n_shown = 0;
848 setlocale(LC_ALL, "");
849 log_parse_environment();
852 r = parse_argv(argc, argv);
856 signal(SIGWINCH, columns_lines_cache_reset);
858 if (arg_action == ACTION_NEW_ID128) {
859 r = generate_new_id128();
863 if (arg_action == ACTION_SETUP_KEYS) {
868 if (arg_action == ACTION_LIST_CATALOG) {
869 r = catalog_list(stdout);
871 log_error("Failed to list catalog: %s", strerror(-r));
875 if (arg_action == ACTION_UPDATE_CATALOG) {
876 r = catalog_update();
885 r = sd_journal_open_directory(&j, arg_directory, 0);
887 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
889 log_error("Failed to open journal: %s", strerror(-r));
893 if (arg_action == ACTION_VERIFY) {
898 if (arg_action == ACTION_PRINT_HEADER) {
899 journal_print_header(j);
904 if (arg_action == ACTION_DISK_USAGE) {
906 char sbytes[FORMAT_BYTES_MAX];
908 r = sd_journal_get_usage(j, &bytes);
912 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
917 r = add_this_boot(j);
925 r = add_matches(j, argv + optind);
929 r = add_priorities(j);
937 r = sd_journal_query_unique(j, arg_field);
939 log_error("Failed to query unique data objects: %s", strerror(-r));
943 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
946 if (arg_lines > 0 && n_shown >= arg_lines)
949 eq = memchr(data, '=', size);
951 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
953 printf("%.*s\n", (int) size, (const char*) data);
963 r = sd_journal_seek_cursor(j, arg_cursor);
965 log_error("Failed to seek to cursor: %s", strerror(-r));
969 r = sd_journal_next(j);
971 } else if (arg_since_set) {
972 r = sd_journal_seek_realtime_usec(j, arg_since);
974 log_error("Failed to seek to date: %s", strerror(-r));
977 r = sd_journal_next(j);
979 } else if (arg_lines > 0) {
980 r = sd_journal_seek_tail(j);
982 log_error("Failed to seek to tail: %s", strerror(-r));
986 r = sd_journal_previous_skip(j, arg_lines);
989 r = sd_journal_seek_head(j);
991 log_error("Failed to seek to head: %s", strerror(-r));
995 r = sd_journal_next(j);
999 log_error("Failed to iterate through journal: %s", strerror(-r));
1003 if (!arg_no_pager && !arg_follow)
1008 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1010 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1012 log_error("Failed to get cutoff: %s", strerror(-r));
1018 printf("-- Logs begin at %s. --\n",
1019 format_timestamp(start_buf, sizeof(start_buf), start));
1021 printf("-- Logs begin at %s, end at %s. --\n",
1022 format_timestamp(start_buf, sizeof(start_buf), start),
1023 format_timestamp(end_buf, sizeof(end_buf), end));
1028 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
1032 r = sd_journal_next(j);
1034 log_error("Failed to iterate through journal: %s", strerror(-r));
1042 if (arg_until_set) {
1045 r = sd_journal_get_realtime_usec(j, &usec);
1047 log_error("Failed to determine timestamp: %s", strerror(-r));
1055 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1057 if (previous_boot_id_valid &&
1058 !sd_id128_equal(boot_id, previous_boot_id))
1059 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1061 previous_boot_id = boot_id;
1062 previous_boot_id_valid = true;
1067 arg_all * OUTPUT_SHOW_ALL |
1068 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1069 on_tty() * OUTPUT_COLOR |
1070 arg_catalog * OUTPUT_CATALOG;
1072 r = output_journal(stdout, j, arg_output, 0, flags);
1083 r = sd_journal_wait(j, (uint64_t) -1);
1085 log_error("Couldn't wait for journal event: %s", strerror(-r));
1092 sd_journal_close(j);
1096 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;