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_full = false;
61 static bool arg_all = false;
62 static bool arg_no_pager = false;
63 static unsigned arg_lines = 0;
64 static bool arg_no_tail = false;
65 static bool arg_quiet = false;
66 static bool arg_merge = false;
67 static bool arg_this_boot = false;
68 static const char *arg_cursor = NULL;
69 static const char *arg_directory = NULL;
70 static int arg_priorities = 0xFF;
71 static const char *arg_verify_key = NULL;
73 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
75 static usec_t arg_since, arg_until;
76 static bool arg_since_set = false, arg_until_set = false;
77 static const char *arg_unit = NULL;
78 static const char *arg_field = NULL;
79 static bool arg_catalog = false;
90 } arg_action = ACTION_SHOW;
92 static int help(void) {
94 printf("%s [OPTIONS...] [MATCHES...]\n\n"
95 "Query the journal.\n\n"
97 " --since=DATE Start showing entries newer or of the specified date\n"
98 " --until=DATE Stop showing entries older or of the specified date\n"
99 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
100 " -b --this-boot Show data only from current boot\n"
101 " -u --unit=UNIT Show data only from the specified unit\n"
102 " -p --priority=RANGE Show only messages within the specified priority range\n"
103 " -f --follow Follow journal\n"
104 " -n --lines[=INTEGER] Number of journal entries to show\n"
105 " --no-tail Show all lines, even in follow mode\n"
106 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
107 " verbose, export, json, json-pretty, json-sse, cat)\n"
108 " -x --catalog Add message explanations where available\n"
109 " --full Do not ellipsize fields\n"
110 " -a --all Show all fields, including long and unprintable\n"
111 " -q --quiet Don't show privilege warning\n"
112 " --no-pager Do not pipe output into a pager\n"
113 " -m --merge Show entries from all available journals\n"
114 " -D --directory=PATH Show journal files from directory\n"
116 " --interval=TIME Time interval for changing the FSS sealing key\n"
117 " --verify-key=KEY Specify FSS verification key\n"
120 " -h --help Show this help\n"
121 " --version Show package version\n"
122 " --new-id128 Generate a new 128 Bit ID\n"
123 " --header Show journal header information\n"
124 " --disk-usage Show total disk usage\n"
125 " -F --field=FIELD List all values a certain field takes\n"
126 " --list-catalog Show message IDs of all entries in the message catalog\n"
127 " --update-catalog Update the message catalog database\n"
129 " --setup-keys Generate new FSS key pair\n"
130 " --verify Verify journal file consistency\n"
132 , program_invocation_short_name);
137 static int parse_argv(int argc, char *argv[]) {
157 static const struct option options[] = {
158 { "help", no_argument, NULL, 'h' },
159 { "version" , no_argument, NULL, ARG_VERSION },
160 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
161 { "follow", no_argument, NULL, 'f' },
162 { "output", required_argument, NULL, 'o' },
163 { "all", no_argument, NULL, 'a' },
164 { "full", no_argument, NULL, ARG_FULL },
165 { "lines", optional_argument, NULL, 'n' },
166 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
167 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
168 { "quiet", no_argument, NULL, 'q' },
169 { "merge", no_argument, NULL, 'm' },
170 { "this-boot", no_argument, NULL, 'b' },
171 { "directory", required_argument, NULL, 'D' },
172 { "header", no_argument, NULL, ARG_HEADER },
173 { "priority", required_argument, NULL, 'p' },
174 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
175 { "interval", required_argument, NULL, ARG_INTERVAL },
176 { "verify", no_argument, NULL, ARG_VERIFY },
177 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
178 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
179 { "cursor", required_argument, NULL, 'c' },
180 { "since", required_argument, NULL, ARG_SINCE },
181 { "until", required_argument, NULL, ARG_UNTIL },
182 { "unit", required_argument, NULL, 'u' },
183 { "field", required_argument, NULL, 'F' },
184 { "catalog", no_argument, NULL, 'x' },
185 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
186 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
195 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:x", options, NULL)) >= 0) {
204 puts(PACKAGE_STRING);
206 puts(SYSTEMD_FEATURES);
218 arg_output = output_mode_from_string(optarg);
219 if (arg_output < 0) {
220 log_error("Unknown output format '%s'.", optarg);
224 if (arg_output == OUTPUT_EXPORT ||
225 arg_output == OUTPUT_JSON ||
226 arg_output == OUTPUT_JSON_PRETTY ||
227 arg_output == OUTPUT_JSON_SSE ||
228 arg_output == OUTPUT_CAT)
243 r = safe_atou(optarg, &arg_lines);
244 if (r < 0 || arg_lines <= 0) {
245 log_error("Failed to parse lines '%s'", optarg);
258 arg_action = ACTION_NEW_ID128;
270 arg_this_boot = true;
274 arg_directory = optarg;
282 arg_action = ACTION_PRINT_HEADER;
286 arg_action = ACTION_VERIFY;
290 arg_action = ACTION_DISK_USAGE;
295 arg_action = ACTION_SETUP_KEYS;
300 arg_action = ACTION_VERIFY;
301 arg_verify_key = optarg;
306 r = parse_usec(optarg, &arg_interval);
307 if (r < 0 || arg_interval <= 0) {
308 log_error("Failed to parse sealing key change interval: %s", optarg);
316 log_error("Forward-secure sealing not available.");
323 dots = strstr(optarg, "..");
329 a = strndup(optarg, dots - optarg);
333 from = log_level_from_string(a);
334 to = log_level_from_string(dots + 2);
337 if (from < 0 || to < 0) {
338 log_error("Failed to parse log level range %s", optarg);
345 for (i = from; i <= to; i++)
346 arg_priorities |= 1 << i;
348 for (i = to; i <= from; i++)
349 arg_priorities |= 1 << i;
355 p = log_level_from_string(optarg);
357 log_error("Unknown log level %s", optarg);
363 for (i = 0; i <= p; i++)
364 arg_priorities |= 1 << i;
371 r = parse_timestamp(optarg, &arg_since);
373 log_error("Failed to parse timestamp: %s", optarg);
376 arg_since_set = true;
380 r = parse_timestamp(optarg, &arg_until);
382 log_error("Failed to parse timestamp: %s", optarg);
385 arg_until_set = true;
403 case ARG_LIST_CATALOG:
404 arg_action = ACTION_LIST_CATALOG;
407 case ARG_UPDATE_CATALOG:
408 arg_action = ACTION_UPDATE_CATALOG;
412 log_error("Unknown option code %c", c);
417 if (arg_follow && !arg_no_tail && arg_lines <= 0)
420 if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
421 log_error("--since= must be before --until=.");
425 if (arg_cursor && arg_since_set) {
426 log_error("Please specify either --since= or --cursor=, not both.");
433 static int generate_new_id128(void) {
438 r = sd_id128_randomize(&id);
440 log_error("Failed to generate ID: %s", strerror(-r));
444 printf("As string:\n"
445 SD_ID128_FORMAT_STR "\n\n"
447 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
449 "#define MESSAGE_XYZ SD_ID128_MAKE(",
450 SD_ID128_FORMAT_VAL(id),
451 SD_ID128_FORMAT_VAL(id));
453 for (i = 0; i < 16; i++)
454 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
456 fputs(")\n", stdout);
461 static int add_matches(sd_journal *j, char **args) {
467 STRV_FOREACH(i, args) {
470 r = sd_journal_add_disjunction(j);
471 else if (path_is_absolute(*i)) {
476 p = canonicalize_file_name(*i);
479 if (stat(path, &st) < 0) {
481 log_error("Couldn't stat file: %m");
485 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
486 t = strappend("_EXE=", path);
487 else if (S_ISCHR(st.st_mode))
488 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
489 else if (S_ISBLK(st.st_mode))
490 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
493 log_error("File is not a device node, regular file or is not executable: %s", *i);
502 r = sd_journal_add_match(j, t, 0);
505 r = sd_journal_add_match(j, *i, 0);
508 log_error("Failed to add match '%s': %s", *i, strerror(-r));
516 static int add_this_boot(sd_journal *j) {
517 char match[9+32+1] = "_BOOT_ID=";
526 r = sd_id128_get_boot(&boot_id);
528 log_error("Failed to get boot id: %s", strerror(-r));
532 sd_id128_to_string(boot_id, match + 9);
533 r = sd_journal_add_match(j, match, strlen(match));
535 log_error("Failed to add match: %s", strerror(-r));
542 static int add_unit(sd_journal *j) {
543 _cleanup_free_ char *m = NULL, *u = NULL;
548 if (isempty(arg_unit))
551 u = unit_name_mangle(arg_unit);
555 m = strappend("_SYSTEMD_UNIT=", u);
559 r = sd_journal_add_match(j, m, strlen(m));
561 log_error("Failed to add match: %s", strerror(-r));
568 static int add_priorities(sd_journal *j) {
569 char match[] = "PRIORITY=0";
574 if (arg_priorities == 0xFF)
577 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
578 if (arg_priorities & (1 << i)) {
579 match[sizeof(match)-2] = '0' + i;
581 r = sd_journal_add_match(j, match, strlen(match));
583 log_error("Failed to add match: %s", strerror(-r));
591 static int setup_keys(void) {
593 size_t mpk_size, seed_size, state_size, i;
594 uint8_t *mpk, *seed, *state;
596 int fd = -1, r, attr = 0;
597 sd_id128_t machine, boot;
598 char *p = NULL, *k = NULL;
602 r = sd_id128_get_machine(&machine);
604 log_error("Failed to get machine ID: %s", strerror(-r));
608 r = sd_id128_get_boot(&boot);
610 log_error("Failed to get boot ID: %s", strerror(-r));
614 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
615 SD_ID128_FORMAT_VAL(machine)) < 0)
618 if (access(p, F_OK) >= 0) {
619 log_error("Sealing key file %s exists already.", p);
624 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
625 SD_ID128_FORMAT_VAL(machine)) < 0) {
630 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
631 mpk = alloca(mpk_size);
633 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
634 seed = alloca(seed_size);
636 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
637 state = alloca(state_size);
639 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
641 log_error("Failed to open /dev/random: %m");
646 log_info("Generating seed...");
647 l = loop_read(fd, seed, seed_size, true);
648 if (l < 0 || (size_t) l != seed_size) {
649 log_error("Failed to read random seed: %s", strerror(EIO));
654 log_info("Generating key pair...");
655 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
657 log_info("Generating sealing key...");
658 FSPRG_GenState0(state, mpk, seed, seed_size);
660 assert(arg_interval > 0);
662 n = now(CLOCK_REALTIME);
665 close_nointr_nofail(fd);
666 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
668 log_error("Failed to open %s: %m", k);
673 /* Enable secure remove, exclusion from dump, synchronous
674 * writing and in-place updating */
675 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
676 log_warning("FS_IOC_GETFLAGS failed: %m");
678 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
680 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
681 log_warning("FS_IOC_SETFLAGS failed: %m");
684 memcpy(h.signature, "KSHHRHLP", 8);
685 h.machine_id = machine;
687 h.header_size = htole64(sizeof(h));
688 h.start_usec = htole64(n * arg_interval);
689 h.interval_usec = htole64(arg_interval);
690 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
691 h.fsprg_state_size = htole64(state_size);
693 l = loop_write(fd, &h, sizeof(h), false);
694 if (l < 0 || (size_t) l != sizeof(h)) {
695 log_error("Failed to write header: %s", strerror(EIO));
700 l = loop_write(fd, state, state_size, false);
701 if (l < 0 || (size_t) l != state_size) {
702 log_error("Failed to write state: %s", strerror(EIO));
707 if (link(k, p) < 0) {
708 log_error("Failed to link file: %m");
716 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
717 "the following local file. This key file is automatically updated when the\n"
718 "sealing key is advanced. It should not be used on multiple hosts.\n"
722 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
723 "at a safe location and should not be saved locally on disk.\n"
724 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
727 for (i = 0; i < seed_size; i++) {
728 if (i > 0 && i % 3 == 0)
730 printf("%02x", ((uint8_t*) seed)[i]);
733 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
736 char tsb[FORMAT_TIMESPAN_MAX], *hn;
739 ANSI_HIGHLIGHT_OFF "\n"
740 "The sealing key is automatically changed every %s.\n",
741 format_timespan(tsb, sizeof(tsb), arg_interval));
743 hn = gethostname_malloc();
746 hostname_cleanup(hn);
747 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
749 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
752 /* If this is not an UTF-8 system don't print any QR codes */
753 if (is_locale_utf8()) {
754 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
755 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
765 close_nointr_nofail(fd);
776 log_error("Forward-secure sealing not available.");
781 static int verify(sd_journal *j) {
788 log_show_color(true);
790 HASHMAP_FOREACH(f, j->files, i) {
792 usec_t first, validated, last;
795 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
796 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
799 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
801 /* If the key was invalid give up right-away. */
804 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
807 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
808 log_info("PASS: %s", f->path);
810 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
812 log_info("=> Validated from %s to %s, final %s entries not sealed.",
813 format_timestamp(a, sizeof(a), first),
814 format_timestamp(b, sizeof(b), validated),
815 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
817 log_info("=> No sealing yet, %s of entries not sealed.",
818 format_timespan(c, sizeof(c), last - first));
820 log_info("=> No sealing yet, no entries in file.");
828 static int access_check(void) {
831 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
832 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
836 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
837 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
839 if (geteuid() != 0 && in_group("adm") <= 0) {
840 log_error("No access to messages. Only users in the group 'adm' can see messages.");
848 int main(int argc, char *argv[]) {
850 sd_journal *j = NULL;
851 bool need_seek = false;
852 sd_id128_t previous_boot_id;
853 bool previous_boot_id_valid = false;
854 unsigned n_shown = 0;
856 setlocale(LC_ALL, "");
857 log_parse_environment();
860 r = parse_argv(argc, argv);
864 signal(SIGWINCH, columns_lines_cache_reset);
866 if (arg_action == ACTION_NEW_ID128) {
867 r = generate_new_id128();
871 if (arg_action == ACTION_SETUP_KEYS) {
876 if (arg_action == ACTION_LIST_CATALOG) {
877 r = catalog_list(stdout);
879 log_error("Failed to list catalog: %s", strerror(-r));
883 if (arg_action == ACTION_UPDATE_CATALOG) {
884 r = catalog_update();
893 r = sd_journal_open_directory(&j, arg_directory, 0);
895 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
897 log_error("Failed to open journal: %s", strerror(-r));
901 if (arg_action == ACTION_VERIFY) {
906 if (arg_action == ACTION_PRINT_HEADER) {
907 journal_print_header(j);
912 if (arg_action == ACTION_DISK_USAGE) {
914 char sbytes[FORMAT_BYTES_MAX];
916 r = sd_journal_get_usage(j, &bytes);
920 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
925 r = add_this_boot(j);
933 r = add_matches(j, argv + optind);
937 r = add_priorities(j);
945 r = sd_journal_query_unique(j, arg_field);
947 log_error("Failed to query unique data objects: %s", strerror(-r));
951 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
954 if (arg_lines > 0 && n_shown >= arg_lines)
957 eq = memchr(data, '=', size);
959 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
961 printf("%.*s\n", (int) size, (const char*) data);
971 r = sd_journal_seek_cursor(j, arg_cursor);
973 log_error("Failed to seek to cursor: %s", strerror(-r));
977 r = sd_journal_next(j);
979 } else if (arg_since_set) {
980 r = sd_journal_seek_realtime_usec(j, arg_since);
982 log_error("Failed to seek to date: %s", strerror(-r));
985 r = sd_journal_next(j);
987 } else if (arg_lines > 0) {
988 r = sd_journal_seek_tail(j);
990 log_error("Failed to seek to tail: %s", strerror(-r));
994 r = sd_journal_previous_skip(j, arg_lines);
997 r = sd_journal_seek_head(j);
999 log_error("Failed to seek to head: %s", strerror(-r));
1003 r = sd_journal_next(j);
1007 log_error("Failed to iterate through journal: %s", strerror(-r));
1011 if (!arg_no_pager && !arg_follow)
1016 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1018 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1020 log_error("Failed to get cutoff: %s", strerror(-r));
1026 printf("-- Logs begin at %s. --\n",
1027 format_timestamp(start_buf, sizeof(start_buf), start));
1029 printf("-- Logs begin at %s, end at %s. --\n",
1030 format_timestamp(start_buf, sizeof(start_buf), start),
1031 format_timestamp(end_buf, sizeof(end_buf), end));
1036 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
1040 r = sd_journal_next(j);
1042 log_error("Failed to iterate through journal: %s", strerror(-r));
1050 if (arg_until_set) {
1053 r = sd_journal_get_realtime_usec(j, &usec);
1055 log_error("Failed to determine timestamp: %s", strerror(-r));
1063 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1065 if (previous_boot_id_valid &&
1066 !sd_id128_equal(boot_id, previous_boot_id))
1067 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1069 previous_boot_id = boot_id;
1070 previous_boot_id_valid = true;
1075 arg_all * OUTPUT_SHOW_ALL |
1076 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1077 on_tty() * OUTPUT_COLOR |
1078 arg_catalog * OUTPUT_CATALOG;
1080 r = output_journal(stdout, j, arg_output, 0, flags);
1091 r = sd_journal_wait(j, (uint64_t) -1);
1093 log_error("Couldn't wait for journal event: %s", strerror(-r));
1100 sd_journal_close(j);
1104 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;