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);
205 puts(SYSTEMD_FEATURES);
217 arg_output = output_mode_from_string(optarg);
218 if (arg_output < 0) {
219 log_error("Unknown output format '%s'.", optarg);
223 if (arg_output == OUTPUT_EXPORT ||
224 arg_output == OUTPUT_JSON ||
225 arg_output == OUTPUT_JSON_PRETTY ||
226 arg_output == OUTPUT_JSON_SSE ||
227 arg_output == OUTPUT_CAT)
242 r = safe_atou(optarg, &arg_lines);
243 if (r < 0 || arg_lines <= 0) {
244 log_error("Failed to parse lines '%s'", optarg);
257 arg_action = ACTION_NEW_ID128;
269 arg_this_boot = true;
273 arg_directory = optarg;
281 arg_action = ACTION_PRINT_HEADER;
285 arg_action = ACTION_VERIFY;
289 arg_action = ACTION_DISK_USAGE;
294 arg_action = ACTION_SETUP_KEYS;
299 arg_action = ACTION_VERIFY;
300 arg_verify_key = optarg;
305 r = parse_usec(optarg, &arg_interval);
306 if (r < 0 || arg_interval <= 0) {
307 log_error("Failed to parse sealing key change interval: %s", optarg);
315 log_error("Forward-secure sealing not available.");
322 dots = strstr(optarg, "..");
328 a = strndup(optarg, dots - optarg);
332 from = log_level_from_string(a);
333 to = log_level_from_string(dots + 2);
336 if (from < 0 || to < 0) {
337 log_error("Failed to parse log level range %s", optarg);
344 for (i = from; i <= to; i++)
345 arg_priorities |= 1 << i;
347 for (i = to; i <= from; i++)
348 arg_priorities |= 1 << i;
354 p = log_level_from_string(optarg);
356 log_error("Unknown log level %s", optarg);
362 for (i = 0; i <= p; i++)
363 arg_priorities |= 1 << i;
370 r = parse_timestamp(optarg, &arg_since);
372 log_error("Failed to parse timestamp: %s", optarg);
375 arg_since_set = true;
379 r = parse_timestamp(optarg, &arg_until);
381 log_error("Failed to parse timestamp: %s", optarg);
384 arg_until_set = true;
402 case ARG_LIST_CATALOG:
403 arg_action = ACTION_LIST_CATALOG;
406 case ARG_UPDATE_CATALOG:
407 arg_action = ACTION_UPDATE_CATALOG;
411 log_error("Unknown option code %c", c);
416 if (arg_follow && !arg_no_tail && arg_lines <= 0)
419 if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
420 log_error("--since= must be before --until=.");
424 if (arg_cursor && arg_since_set) {
425 log_error("Please specify either --since= or --cursor=, not both.");
432 static int generate_new_id128(void) {
437 r = sd_id128_randomize(&id);
439 log_error("Failed to generate ID: %s", strerror(-r));
443 printf("As string:\n"
444 SD_ID128_FORMAT_STR "\n\n"
446 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
448 "#define MESSAGE_XYZ SD_ID128_MAKE(",
449 SD_ID128_FORMAT_VAL(id),
450 SD_ID128_FORMAT_VAL(id));
452 for (i = 0; i < 16; i++)
453 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
455 fputs(")\n", stdout);
460 static int add_matches(sd_journal *j, char **args) {
466 STRV_FOREACH(i, args) {
469 r = sd_journal_add_disjunction(j);
470 else if (path_is_absolute(*i)) {
475 p = canonicalize_file_name(*i);
478 if (stat(path, &st) < 0) {
480 log_error("Couldn't stat file: %m");
484 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
485 t = strappend("_EXE=", path);
486 else if (S_ISCHR(st.st_mode))
487 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
488 else if (S_ISBLK(st.st_mode))
489 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
492 log_error("File is not a device node, regular file or is not executable: %s", *i);
501 r = sd_journal_add_match(j, t, 0);
504 r = sd_journal_add_match(j, *i, 0);
507 log_error("Failed to add match '%s': %s", *i, strerror(-r));
515 static int add_this_boot(sd_journal *j) {
516 char match[9+32+1] = "_BOOT_ID=";
525 r = sd_id128_get_boot(&boot_id);
527 log_error("Failed to get boot id: %s", strerror(-r));
531 sd_id128_to_string(boot_id, match + 9);
532 r = sd_journal_add_match(j, match, strlen(match));
534 log_error("Failed to add match: %s", strerror(-r));
541 static int add_unit(sd_journal *j) {
542 _cleanup_free_ char *m = NULL, *u = NULL;
547 if (isempty(arg_unit))
550 u = unit_name_mangle(arg_unit);
554 m = strappend("_SYSTEMD_UNIT=", u);
558 r = sd_journal_add_match(j, m, strlen(m));
560 log_error("Failed to add match: %s", strerror(-r));
567 static int add_priorities(sd_journal *j) {
568 char match[] = "PRIORITY=0";
573 if (arg_priorities == 0xFF)
576 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
577 if (arg_priorities & (1 << i)) {
578 match[sizeof(match)-2] = '0' + i;
580 r = sd_journal_add_match(j, match, strlen(match));
582 log_error("Failed to add match: %s", strerror(-r));
590 static int setup_keys(void) {
592 size_t mpk_size, seed_size, state_size, i;
593 uint8_t *mpk, *seed, *state;
595 int fd = -1, r, attr = 0;
596 sd_id128_t machine, boot;
597 char *p = NULL, *k = NULL;
601 r = sd_id128_get_machine(&machine);
603 log_error("Failed to get machine ID: %s", strerror(-r));
607 r = sd_id128_get_boot(&boot);
609 log_error("Failed to get boot ID: %s", strerror(-r));
613 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
614 SD_ID128_FORMAT_VAL(machine)) < 0)
617 if (access(p, F_OK) >= 0) {
618 log_error("Sealing key file %s exists already.", p);
623 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
624 SD_ID128_FORMAT_VAL(machine)) < 0) {
629 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
630 mpk = alloca(mpk_size);
632 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
633 seed = alloca(seed_size);
635 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
636 state = alloca(state_size);
638 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
640 log_error("Failed to open /dev/random: %m");
645 log_info("Generating seed...");
646 l = loop_read(fd, seed, seed_size, true);
647 if (l < 0 || (size_t) l != seed_size) {
648 log_error("Failed to read random seed: %s", strerror(EIO));
653 log_info("Generating key pair...");
654 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
656 log_info("Generating sealing key...");
657 FSPRG_GenState0(state, mpk, seed, seed_size);
659 assert(arg_interval > 0);
661 n = now(CLOCK_REALTIME);
664 close_nointr_nofail(fd);
665 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
667 log_error("Failed to open %s: %m", k);
672 /* Enable secure remove, exclusion from dump, synchronous
673 * writing and in-place updating */
674 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
675 log_warning("FS_IOC_GETFLAGS failed: %m");
677 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
679 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
680 log_warning("FS_IOC_SETFLAGS failed: %m");
683 memcpy(h.signature, "KSHHRHLP", 8);
684 h.machine_id = machine;
686 h.header_size = htole64(sizeof(h));
687 h.start_usec = htole64(n * arg_interval);
688 h.interval_usec = htole64(arg_interval);
689 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
690 h.fsprg_state_size = htole64(state_size);
692 l = loop_write(fd, &h, sizeof(h), false);
693 if (l < 0 || (size_t) l != sizeof(h)) {
694 log_error("Failed to write header: %s", strerror(EIO));
699 l = loop_write(fd, state, state_size, false);
700 if (l < 0 || (size_t) l != state_size) {
701 log_error("Failed to write state: %s", strerror(EIO));
706 if (link(k, p) < 0) {
707 log_error("Failed to link file: %m");
715 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
716 "the following local file. This key file is automatically updated when the\n"
717 "sealing key is advanced. It should not be used on multiple hosts.\n"
721 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
722 "at a safe location and should not be saved locally on disk.\n"
723 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
726 for (i = 0; i < seed_size; i++) {
727 if (i > 0 && i % 3 == 0)
729 printf("%02x", ((uint8_t*) seed)[i]);
732 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
735 char tsb[FORMAT_TIMESPAN_MAX], *hn;
738 ANSI_HIGHLIGHT_OFF "\n"
739 "The sealing key is automatically changed every %s.\n",
740 format_timespan(tsb, sizeof(tsb), arg_interval));
742 hn = gethostname_malloc();
745 hostname_cleanup(hn);
746 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
748 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
751 /* If this is not an UTF-8 system don't print any QR codes */
752 if (is_locale_utf8()) {
753 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
754 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
764 close_nointr_nofail(fd);
775 log_error("Forward-secure sealing not available.");
780 static int verify(sd_journal *j) {
787 log_show_color(true);
789 HASHMAP_FOREACH(f, j->files, i) {
791 usec_t first, validated, last;
794 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
795 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
798 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
800 /* If the key was invalid give up right-away. */
803 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
806 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
807 log_info("PASS: %s", f->path);
809 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
811 log_info("=> Validated from %s to %s, final %s entries not sealed.",
812 format_timestamp(a, sizeof(a), first),
813 format_timestamp(b, sizeof(b), validated),
814 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
816 log_info("=> No sealing yet, %s of entries not sealed.",
817 format_timespan(c, sizeof(c), last - first));
819 log_info("=> No sealing yet, no entries in file.");
827 static int access_check(void) {
830 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
831 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
835 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
836 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
838 if (geteuid() != 0 && in_group("adm") <= 0) {
839 log_error("No access to messages. Only users in the group 'adm' can see messages.");
847 int main(int argc, char *argv[]) {
849 sd_journal *j = NULL;
850 bool need_seek = false;
851 sd_id128_t previous_boot_id;
852 bool previous_boot_id_valid = false;
853 unsigned n_shown = 0;
855 setlocale(LC_ALL, "");
856 log_parse_environment();
859 r = parse_argv(argc, argv);
863 signal(SIGWINCH, columns_lines_cache_reset);
865 if (arg_action == ACTION_NEW_ID128) {
866 r = generate_new_id128();
870 if (arg_action == ACTION_SETUP_KEYS) {
875 if (arg_action == ACTION_LIST_CATALOG) {
876 r = catalog_list(stdout);
878 log_error("Failed to list catalog: %s", strerror(-r));
882 if (arg_action == ACTION_UPDATE_CATALOG) {
883 r = catalog_update();
892 r = sd_journal_open_directory(&j, arg_directory, 0);
894 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
896 log_error("Failed to open journal: %s", strerror(-r));
900 if (arg_action == ACTION_VERIFY) {
905 if (arg_action == ACTION_PRINT_HEADER) {
906 journal_print_header(j);
911 if (arg_action == ACTION_DISK_USAGE) {
913 char sbytes[FORMAT_BYTES_MAX];
915 r = sd_journal_get_usage(j, &bytes);
919 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
924 r = add_this_boot(j);
932 r = add_matches(j, argv + optind);
936 r = add_priorities(j);
944 r = sd_journal_query_unique(j, arg_field);
946 log_error("Failed to query unique data objects: %s", strerror(-r));
950 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
953 if (arg_lines > 0 && n_shown >= arg_lines)
956 eq = memchr(data, '=', size);
958 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
960 printf("%.*s\n", (int) size, (const char*) data);
970 r = sd_journal_seek_cursor(j, arg_cursor);
972 log_error("Failed to seek to cursor: %s", strerror(-r));
976 r = sd_journal_next(j);
978 } else if (arg_since_set) {
979 r = sd_journal_seek_realtime_usec(j, arg_since);
981 log_error("Failed to seek to date: %s", strerror(-r));
984 r = sd_journal_next(j);
986 } else if (arg_lines > 0) {
987 r = sd_journal_seek_tail(j);
989 log_error("Failed to seek to tail: %s", strerror(-r));
993 r = sd_journal_previous_skip(j, arg_lines);
996 r = sd_journal_seek_head(j);
998 log_error("Failed to seek to head: %s", strerror(-r));
1002 r = sd_journal_next(j);
1006 log_error("Failed to iterate through journal: %s", strerror(-r));
1010 if (!arg_no_pager && !arg_follow)
1015 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1017 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1019 log_error("Failed to get cutoff: %s", strerror(-r));
1025 printf("-- Logs begin at %s. --\n",
1026 format_timestamp(start_buf, sizeof(start_buf), start));
1028 printf("-- Logs begin at %s, end at %s. --\n",
1029 format_timestamp(start_buf, sizeof(start_buf), start),
1030 format_timestamp(end_buf, sizeof(end_buf), end));
1035 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
1039 r = sd_journal_next(j);
1041 log_error("Failed to iterate through journal: %s", strerror(-r));
1049 if (arg_until_set) {
1052 r = sd_journal_get_realtime_usec(j, &usec);
1054 log_error("Failed to determine timestamp: %s", strerror(-r));
1062 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1064 if (previous_boot_id_valid &&
1065 !sd_id128_equal(boot_id, previous_boot_id))
1066 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1068 previous_boot_id = boot_id;
1069 previous_boot_id_valid = true;
1074 arg_all * OUTPUT_SHOW_ALL |
1075 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1076 on_tty() * OUTPUT_COLOR |
1077 arg_catalog * OUTPUT_CATALOG;
1079 r = output_journal(stdout, j, arg_output, 0, flags);
1080 if (r < 0 || ferror(stdout))
1090 r = sd_journal_wait(j, (uint64_t) -1);
1092 log_error("Couldn't wait for journal event: %s", strerror(-r));
1099 sd_journal_close(j);
1103 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;