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>
42 #include <systemd/sd-journal.h>
45 #include "logs-show.h"
47 #include "path-util.h"
50 #include "logs-show.h"
52 #include "journal-internal.h"
53 #include "journal-def.h"
54 #include "journal-verify.h"
55 #include "journal-authenticate.h"
56 #include "journal-qrcode.h"
58 #include "unit-name.h"
61 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
63 static OutputMode arg_output = OUTPUT_SHORT;
64 static bool arg_pager_end = false;
65 static bool arg_follow = false;
66 static bool arg_full = false;
67 static bool arg_all = false;
68 static bool arg_no_pager = false;
69 static int arg_lines = -1;
70 static bool arg_no_tail = false;
71 static bool arg_quiet = false;
72 static bool arg_merge = false;
73 static bool arg_boot_id = false;
74 static char *arg_boot_id_descriptor = NULL;
75 static bool arg_dmesg = false;
76 static const char *arg_cursor = NULL;
77 static const char *arg_after_cursor = NULL;
78 static bool arg_show_cursor = false;
79 static const char *arg_directory = NULL;
80 static char **arg_file = NULL;
81 static int arg_priorities = 0xFF;
82 static const char *arg_verify_key = NULL;
84 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
85 static bool arg_force = false;
87 static usec_t arg_since, arg_until;
88 static bool arg_since_set = false, arg_until_set = false;
89 static char **arg_system_units = NULL;
90 static char **arg_user_units = NULL;
91 static const char *arg_field = NULL;
92 static bool arg_catalog = false;
93 static bool arg_reverse = false;
94 static int arg_journal_type = 0;
95 static const char *arg_root = NULL;
106 ACTION_UPDATE_CATALOG
107 } arg_action = ACTION_SHOW;
109 typedef struct boot_id_t {
114 static int help(void) {
116 printf("%s [OPTIONS...] [MATCHES...]\n\n"
117 "Query the journal.\n\n"
119 " --system Show only the system journal\n"
120 " --user Show only the user journal for current user\n"
121 " --since=DATE Start showing entries newer or of the specified date\n"
122 " --until=DATE Stop showing entries older or of the specified date\n"
123 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
124 " --after-cursor=CURSOR Start showing entries from specified cursor\n"
125 " --show-cursor Print the cursor after all the entries\n"
126 " -b --boot[=ID] Show data only from ID or current boot if unspecified\n"
127 " -k --dmesg Show kernel message log from current boot\n"
128 " -u --unit=UNIT Show data only from the specified unit\n"
129 " --user-unit=UNIT Show data only from the specified user session unit\n"
130 " -p --priority=RANGE Show only messages within the specified priority range\n"
131 " -e --pager-end Immediately jump to end of the journal in the pager\n"
132 " -f --follow Follow journal\n"
133 " -n --lines[=INTEGER] Number of journal entries to show\n"
134 " --no-tail Show all lines, even in follow mode\n"
135 " -r --reverse Show the newest entries first\n"
136 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
137 " verbose, export, json, json-pretty, json-sse, cat)\n"
138 " -x --catalog Add message explanations where available\n"
139 " -l --full Do not ellipsize fields\n"
140 " -a --all Show all fields, including long and unprintable\n"
141 " -q --quiet Don't show privilege warning\n"
142 " --no-pager Do not pipe output into a pager\n"
143 " -m --merge Show entries from all available journals\n"
144 " -D --directory=PATH Show journal files from directory\n"
145 " --file=PATH Show journal file\n"
146 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
148 " --interval=TIME Time interval for changing the FSS sealing key\n"
149 " --verify-key=KEY Specify FSS verification key\n"
150 " --force Force overriding new FSS key pair with --setup-keys\n"
153 " -h --help Show this help\n"
154 " --version Show package version\n"
155 " --new-id128 Generate a new 128 Bit ID\n"
156 " --header Show journal header information\n"
157 " --disk-usage Show total disk usage\n"
158 " -F --field=FIELD List all values a certain field takes\n"
159 " --list-catalog Show message IDs of all entries in the message catalog\n"
160 " --dump-catalog Show entries in the message catalog\n"
161 " --update-catalog Update the message catalog database\n"
163 " --setup-keys Generate new FSS key pair\n"
164 " --verify Verify journal file consistency\n"
166 , program_invocation_short_name);
171 static int parse_argv(int argc, char *argv[]) {
199 static const struct option options[] = {
200 { "help", no_argument, NULL, 'h' },
201 { "version" , no_argument, NULL, ARG_VERSION },
202 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
203 { "pager-end", no_argument, NULL, 'e' },
204 { "follow", no_argument, NULL, 'f' },
205 { "force", no_argument, NULL, ARG_FORCE },
206 { "output", required_argument, NULL, 'o' },
207 { "all", no_argument, NULL, 'a' },
208 { "full", no_argument, NULL, 'l' },
209 { "lines", optional_argument, NULL, 'n' },
210 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
211 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
212 { "quiet", no_argument, NULL, 'q' },
213 { "merge", no_argument, NULL, 'm' },
214 { "boot", optional_argument, NULL, 'b' },
215 { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */
216 { "dmesg", no_argument, NULL, 'k' },
217 { "system", no_argument, NULL, ARG_SYSTEM },
218 { "user", no_argument, NULL, ARG_USER },
219 { "directory", required_argument, NULL, 'D' },
220 { "file", required_argument, NULL, ARG_FILE },
221 { "root", required_argument, NULL, ARG_ROOT },
222 { "header", no_argument, NULL, ARG_HEADER },
223 { "priority", required_argument, NULL, 'p' },
224 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
225 { "interval", required_argument, NULL, ARG_INTERVAL },
226 { "verify", no_argument, NULL, ARG_VERIFY },
227 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
228 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
229 { "cursor", required_argument, NULL, 'c' },
230 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
231 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
232 { "since", required_argument, NULL, ARG_SINCE },
233 { "until", required_argument, NULL, ARG_UNTIL },
234 { "unit", required_argument, NULL, 'u' },
235 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
236 { "field", required_argument, NULL, 'F' },
237 { "catalog", no_argument, NULL, 'x' },
238 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
239 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
240 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
241 { "reverse", no_argument, NULL, 'r' },
250 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xr", options, NULL)) >= 0) {
259 puts(PACKAGE_STRING);
260 puts(SYSTEMD_FEATURES);
268 arg_pager_end = true;
280 arg_output = output_mode_from_string(optarg);
281 if (arg_output < 0) {
282 log_error("Unknown output format '%s'.", optarg);
286 if (arg_output == OUTPUT_EXPORT ||
287 arg_output == OUTPUT_JSON ||
288 arg_output == OUTPUT_JSON_PRETTY ||
289 arg_output == OUTPUT_JSON_SSE ||
290 arg_output == OUTPUT_CAT)
305 r = safe_atoi(optarg, &arg_lines);
306 if (r < 0 || arg_lines < 0) {
307 log_error("Failed to parse lines '%s'", optarg);
313 /* Hmm, no argument? Maybe the next
314 * word on the command line is
315 * supposed to be the argument? Let's
316 * see if there is one, and is
317 * parsable as a positive
321 safe_atoi(argv[optind], &n) >= 0 &&
337 arg_action = ACTION_NEW_ID128;
350 arg_boot_id_descriptor = optarg;
351 else if (optind < argc && argv[optind][0] != '-') {
352 arg_boot_id_descriptor = argv[optind];
359 arg_boot_id = arg_dmesg = true;
363 arg_journal_type |= SD_JOURNAL_SYSTEM;
367 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
371 arg_directory = optarg;
375 r = glob_extend(&arg_file, optarg);
377 log_error("Failed to add paths: %s", strerror(-r));
390 case ARG_AFTER_CURSOR:
391 arg_after_cursor = optarg;
394 case ARG_SHOW_CURSOR:
395 arg_show_cursor = true;
399 arg_action = ACTION_PRINT_HEADER;
403 arg_action = ACTION_VERIFY;
407 arg_action = ACTION_DISK_USAGE;
416 arg_action = ACTION_SETUP_KEYS;
421 arg_action = ACTION_VERIFY;
422 arg_verify_key = optarg;
427 r = parse_sec(optarg, &arg_interval);
428 if (r < 0 || arg_interval <= 0) {
429 log_error("Failed to parse sealing key change interval: %s", optarg);
438 log_error("Forward-secure sealing not available.");
445 dots = strstr(optarg, "..");
451 a = strndup(optarg, dots - optarg);
455 from = log_level_from_string(a);
456 to = log_level_from_string(dots + 2);
459 if (from < 0 || to < 0) {
460 log_error("Failed to parse log level range %s", optarg);
467 for (i = from; i <= to; i++)
468 arg_priorities |= 1 << i;
470 for (i = to; i <= from; i++)
471 arg_priorities |= 1 << i;
477 p = log_level_from_string(optarg);
479 log_error("Unknown log level %s", optarg);
485 for (i = 0; i <= p; i++)
486 arg_priorities |= 1 << i;
493 r = parse_timestamp(optarg, &arg_since);
495 log_error("Failed to parse timestamp: %s", optarg);
498 arg_since_set = true;
502 r = parse_timestamp(optarg, &arg_until);
504 log_error("Failed to parse timestamp: %s", optarg);
507 arg_until_set = true;
511 r = strv_extend(&arg_system_units, optarg);
517 r = strv_extend(&arg_user_units, optarg);
533 case ARG_LIST_CATALOG:
534 arg_action = ACTION_LIST_CATALOG;
537 case ARG_DUMP_CATALOG:
538 arg_action = ACTION_DUMP_CATALOG;
541 case ARG_UPDATE_CATALOG:
542 arg_action = ACTION_UPDATE_CATALOG;
550 log_error("Unknown option code %c", c);
555 if (arg_follow && !arg_no_tail && arg_lines < 0)
558 if (arg_directory && arg_file) {
559 log_error("Please specify either -D/--directory= or --file=, not both.");
563 if (arg_since_set && arg_until_set && arg_since > arg_until) {
564 log_error("--since= must be before --until=.");
568 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
569 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
573 if (arg_follow && arg_reverse) {
574 log_error("Please specify either --reverse= or --follow=, not both.");
581 static int generate_new_id128(void) {
586 r = sd_id128_randomize(&id);
588 log_error("Failed to generate ID: %s", strerror(-r));
592 printf("As string:\n"
593 SD_ID128_FORMAT_STR "\n\n"
595 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
597 "#define MESSAGE_XYZ SD_ID128_MAKE(",
598 SD_ID128_FORMAT_VAL(id),
599 SD_ID128_FORMAT_VAL(id));
600 for (i = 0; i < 16; i++)
601 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
602 fputs(")\n\n", stdout);
604 printf("As Python constant:\n"
606 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
607 SD_ID128_FORMAT_VAL(id));
612 static int add_matches(sd_journal *j, char **args) {
617 STRV_FOREACH(i, args) {
621 r = sd_journal_add_disjunction(j);
622 else if (path_is_absolute(*i)) {
623 _cleanup_free_ char *p, *t = NULL;
627 p = canonicalize_file_name(*i);
630 if (stat(path, &st) < 0) {
631 log_error("Couldn't stat file: %m");
635 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
636 t = strappend("_EXE=", path);
637 else if (S_ISCHR(st.st_mode))
638 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
639 else if (S_ISBLK(st.st_mode))
640 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
642 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
649 r = sd_journal_add_match(j, t, 0);
651 r = sd_journal_add_match(j, *i, 0);
654 log_error("Failed to add match '%s': %s", *i, strerror(-r));
662 static int boot_id_cmp(const void *a, const void *b) {
665 _a = ((const boot_id_t *)a)->timestamp;
666 _b = ((const boot_id_t *)b)->timestamp;
668 return _a < _b ? -1 : (_a > _b ? 1 : 0);
671 static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
674 unsigned int id_count = 0;
675 size_t length, allocated = 0;
676 boot_id_t ref_boot_id, *id;
677 _cleanup_free_ boot_id_t *all_ids = NULL;
678 bool find_first_boot = false, ref_boot_found = false;
686 if (sd_id128_equal(*boot_id, SD_ID128_NULL) && relative > 0) {
687 find_first_boot = true;
691 r = sd_journal_query_unique(j, "_BOOT_ID");
695 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
696 if (length < strlen("_BOOT_ID="))
699 if (!GREEDY_REALLOC(all_ids, allocated, id_count + 1))
702 id = &all_ids[id_count];
704 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
709 sd_journal_flush_matches(j);
710 r = sd_journal_add_match(j, data, length);
714 r = sd_journal_seek_head(j);
718 r = sd_journal_next(j);
722 r = sd_journal_get_realtime_usec(j, &id->timestamp);
726 if (!find_first_boot && sd_id128_equal(id->id, *boot_id)) {
728 ref_boot_found = true;
734 *boot_id = SD_ID128_NULL;
735 sd_journal_flush_matches(j);
737 if (id_count == 0 || (!find_first_boot && !ref_boot_found))
740 qsort(all_ids, id_count, sizeof(boot_id_t), boot_id_cmp);
744 id = bsearch(&ref_boot_id, all_ids, id_count, sizeof(boot_id_t), boot_id_cmp);
746 if (!id || (relative < 0 && ((id - all_ids) + relative) < 0) ||
747 (relative >= 0 && (unsigned long)((id - all_ids) + relative) >= id_count))
755 static int add_boot(sd_journal *j) {
756 char match[9+32+1] = "_BOOT_ID=";
766 if (arg_boot_id_descriptor) {
767 marker = strchr(arg_boot_id_descriptor, ':');
775 r = safe_atoi(marker, &relative);
777 log_error("Failed to parse relative boot ID number '%s'", marker);
784 if (isempty(arg_boot_id_descriptor)) {
786 /* We cannot look into the future. Instead, we look
787 * into the past (starting from first boot). The ID
788 * will be looked up later */
789 boot_id = SD_ID128_NULL;
791 r = sd_id128_get_boot(&boot_id);
793 log_error("Failed to get boot ID: %s", strerror(-r));
798 r = sd_id128_from_string(arg_boot_id_descriptor, &boot_id);
800 log_error("Failed to parse boot ID: %s", strerror(-r));
805 r = get_relative_boot_id(j, &boot_id, relative);
807 log_error("Failed to look up boot ID: %s", strerror(-r));
809 } else if (sd_id128_equal(boot_id, SD_ID128_NULL)) {
810 log_error("Failed to find boot ID");
814 sd_id128_to_string(boot_id, match + 9);
815 r = sd_journal_add_match(j, match, strlen(match));
817 log_error("Failed to add match: %s", strerror(-r));
821 r = sd_journal_add_conjunction(j);
828 static int add_dmesg(sd_journal *j) {
835 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
837 log_error("Failed to add match: %s", strerror(-r));
841 r = sd_journal_add_conjunction(j);
848 static int add_units(sd_journal *j) {
849 _cleanup_free_ char *u = NULL;
855 STRV_FOREACH(i, arg_system_units) {
856 u = unit_name_mangle(*i);
859 r = add_matches_for_unit(j, u);
862 r = sd_journal_add_disjunction(j);
867 STRV_FOREACH(i, arg_user_units) {
868 u = unit_name_mangle(*i);
872 r = add_matches_for_user_unit(j, u, getuid());
876 r = sd_journal_add_disjunction(j);
882 r = sd_journal_add_conjunction(j);
889 static int add_priorities(sd_journal *j) {
890 char match[] = "PRIORITY=0";
894 if (arg_priorities == 0xFF)
897 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
898 if (arg_priorities & (1 << i)) {
899 match[sizeof(match)-2] = '0' + i;
901 r = sd_journal_add_match(j, match, strlen(match));
903 log_error("Failed to add match: %s", strerror(-r));
908 r = sd_journal_add_conjunction(j);
915 static int setup_keys(void) {
917 size_t mpk_size, seed_size, state_size, i;
918 uint8_t *mpk, *seed, *state;
920 int fd = -1, r, attr = 0;
921 sd_id128_t machine, boot;
922 char *p = NULL, *k = NULL;
927 r = stat("/var/log/journal", &st);
928 if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
929 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
933 if (r < 0 || !S_ISDIR(st.st_mode)) {
934 log_error("%s is not a directory, must be using persistent logging for FSS.",
936 return r < 0 ? -errno : -ENOTDIR;
939 r = sd_id128_get_machine(&machine);
941 log_error("Failed to get machine ID: %s", strerror(-r));
945 r = sd_id128_get_boot(&boot);
947 log_error("Failed to get boot ID: %s", strerror(-r));
951 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
952 SD_ID128_FORMAT_VAL(machine)) < 0)
955 if (access(p, F_OK) >= 0) {
959 log_error("unlink(\"%s\") failed: %m", p);
964 log_error("Sealing key file %s exists already. (--force to recreate)", p);
970 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
971 SD_ID128_FORMAT_VAL(machine)) < 0) {
976 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
977 mpk = alloca(mpk_size);
979 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
980 seed = alloca(seed_size);
982 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
983 state = alloca(state_size);
985 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
987 log_error("Failed to open /dev/random: %m");
992 log_info("Generating seed...");
993 l = loop_read(fd, seed, seed_size, true);
994 if (l < 0 || (size_t) l != seed_size) {
995 log_error("Failed to read random seed: %s", strerror(EIO));
1000 log_info("Generating key pair...");
1001 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1003 log_info("Generating sealing key...");
1004 FSPRG_GenState0(state, mpk, seed, seed_size);
1006 assert(arg_interval > 0);
1008 n = now(CLOCK_REALTIME);
1011 close_nointr_nofail(fd);
1012 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
1014 log_error("Failed to open %s: %m", k);
1019 /* Enable secure remove, exclusion from dump, synchronous
1020 * writing and in-place updating */
1021 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
1022 log_warning("FS_IOC_GETFLAGS failed: %m");
1024 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
1026 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
1027 log_warning("FS_IOC_SETFLAGS failed: %m");
1030 memcpy(h.signature, "KSHHRHLP", 8);
1031 h.machine_id = machine;
1033 h.header_size = htole64(sizeof(h));
1034 h.start_usec = htole64(n * arg_interval);
1035 h.interval_usec = htole64(arg_interval);
1036 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1037 h.fsprg_state_size = htole64(state_size);
1039 l = loop_write(fd, &h, sizeof(h), false);
1040 if (l < 0 || (size_t) l != sizeof(h)) {
1041 log_error("Failed to write header: %s", strerror(EIO));
1046 l = loop_write(fd, state, state_size, false);
1047 if (l < 0 || (size_t) l != state_size) {
1048 log_error("Failed to write state: %s", strerror(EIO));
1053 if (link(k, p) < 0) {
1054 log_error("Failed to link file: %m");
1062 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
1063 "the following local file. This key file is automatically updated when the\n"
1064 "sealing key is advanced. It should not be used on multiple hosts.\n"
1068 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1069 "at a safe location and should not be saved locally on disk.\n"
1070 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1073 for (i = 0; i < seed_size; i++) {
1074 if (i > 0 && i % 3 == 0)
1076 printf("%02x", ((uint8_t*) seed)[i]);
1079 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1082 char tsb[FORMAT_TIMESPAN_MAX], *hn;
1085 ANSI_HIGHLIGHT_OFF "\n"
1086 "The sealing key is automatically changed every %s.\n",
1087 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
1089 hn = gethostname_malloc();
1092 hostname_cleanup(hn, false);
1093 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
1095 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
1097 #ifdef HAVE_QRENCODE
1098 /* If this is not an UTF-8 system don't print any QR codes */
1099 if (is_locale_utf8()) {
1100 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1101 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1111 close_nointr_nofail(fd);
1122 log_error("Forward-secure sealing not available.");
1127 static int verify(sd_journal *j) {
1134 log_show_color(true);
1136 HASHMAP_FOREACH(f, j->files, i) {
1138 usec_t first, validated, last;
1141 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
1142 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
1145 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
1147 /* If the key was invalid give up right-away. */
1150 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
1153 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
1154 log_info("PASS: %s", f->path);
1156 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
1157 if (validated > 0) {
1158 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1159 format_timestamp(a, sizeof(a), first),
1160 format_timestamp(b, sizeof(b), validated),
1161 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
1162 } else if (last > 0)
1163 log_info("=> No sealing yet, %s of entries not sealed.",
1164 format_timespan(c, sizeof(c), last - first, 0));
1166 log_info("=> No sealing yet, no entries in file.");
1175 static int access_check_var_log_journal(sd_journal *j) {
1176 _cleanup_strv_free_ char **g = NULL;
1182 have_access = in_group("systemd-journal") > 0;
1185 /* Let's enumerate all groups from the default ACL of
1186 * the directory, which generally should allow access
1187 * to most journal files too */
1188 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
1195 if (strv_isempty(g))
1196 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1197 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1198 " turn off this notice.");
1200 _cleanup_free_ char *s = NULL;
1202 r = strv_extend(&g, "systemd-journal");
1209 s = strv_join(g, "', '");
1213 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1214 " Users in the groups '%s' can see all messages.\n"
1215 " Pass -q to turn off this notice.", s);
1223 static int access_check(sd_journal *j) {
1230 if (set_isempty(j->errors)) {
1231 if (hashmap_isempty(j->files))
1232 log_notice("No journal files were found.");
1236 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
1238 /* If /var/log/journal doesn't even exist,
1239 * unprivileged users have no access at all */
1240 if (access("/var/log/journal", F_OK) < 0 &&
1242 in_group("systemd-journal") <= 0) {
1243 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1244 "enabled. Users in the 'systemd-journal' group may always access messages.");
1248 /* If /var/log/journal exists, try to pring a nice
1249 notice if the user lacks access to it */
1250 if (!arg_quiet && geteuid() != 0) {
1251 r = access_check_var_log_journal(j);
1256 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1257 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1258 "group may access messages.");
1263 if (hashmap_isempty(j->files)) {
1264 log_error("No journal files were opened due to insufficient permissions.");
1269 SET_FOREACH(code, j->errors, it) {
1272 err = -PTR_TO_INT(code);
1276 log_warning("Error was encountered while opening journal files: %s",
1283 int main(int argc, char *argv[]) {
1285 _cleanup_journal_close_ sd_journal*j = NULL;
1286 bool need_seek = false;
1287 sd_id128_t previous_boot_id;
1288 bool previous_boot_id_valid = false, first_line = true;
1291 setlocale(LC_ALL, "");
1292 log_parse_environment();
1295 r = parse_argv(argc, argv);
1299 signal(SIGWINCH, columns_lines_cache_reset);
1301 if (arg_action == ACTION_NEW_ID128) {
1302 r = generate_new_id128();
1306 if (arg_action == ACTION_SETUP_KEYS) {
1311 if (arg_action == ACTION_UPDATE_CATALOG ||
1312 arg_action == ACTION_LIST_CATALOG ||
1313 arg_action == ACTION_DUMP_CATALOG) {
1315 const char* database = CATALOG_DATABASE;
1316 _cleanup_free_ char *copy = NULL;
1318 copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1323 path_kill_slashes(copy);
1327 if (arg_action == ACTION_UPDATE_CATALOG) {
1328 r = catalog_update(database, arg_root, catalog_file_dirs);
1330 log_error("Failed to list catalog: %s", strerror(-r));
1332 bool oneline = arg_action == ACTION_LIST_CATALOG;
1335 r = catalog_list_items(stdout, database,
1336 oneline, argv + optind);
1338 r = catalog_list(stdout, database, oneline);
1340 log_error("Failed to list catalog: %s", strerror(-r));
1347 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
1349 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
1351 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
1353 log_error("Failed to open %s: %s",
1354 arg_directory ? arg_directory : arg_file ? "files" : "journal",
1356 return EXIT_FAILURE;
1359 r = access_check(j);
1361 return EXIT_FAILURE;
1363 if (arg_action == ACTION_VERIFY) {
1368 if (arg_action == ACTION_PRINT_HEADER) {
1369 journal_print_header(j);
1370 return EXIT_SUCCESS;
1373 if (arg_action == ACTION_DISK_USAGE) {
1375 char sbytes[FORMAT_BYTES_MAX];
1377 r = sd_journal_get_usage(j, &bytes);
1379 return EXIT_FAILURE;
1381 printf("Journals take up %s on disk.\n",
1382 format_bytes(sbytes, sizeof(sbytes), bytes));
1383 return EXIT_SUCCESS;
1386 /* add_boot() must be called first!
1387 * It may need to seek the journal to find parent boot IDs. */
1390 return EXIT_FAILURE;
1394 return EXIT_FAILURE;
1397 strv_free(arg_system_units);
1398 strv_free(arg_user_units);
1401 return EXIT_FAILURE;
1403 r = add_priorities(j);
1405 return EXIT_FAILURE;
1407 r = add_matches(j, argv + optind);
1409 return EXIT_FAILURE;
1411 log_debug("Journal filter: %s", j->level0 ? journal_make_match_string(j) : "none");
1417 r = sd_journal_set_data_threshold(j, 0);
1419 log_error("Failed to unset data size threshold");
1420 return EXIT_FAILURE;
1423 r = sd_journal_query_unique(j, arg_field);
1425 log_error("Failed to query unique data objects: %s", strerror(-r));
1426 return EXIT_FAILURE;
1429 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1432 if (arg_lines >= 0 && n_shown >= arg_lines)
1435 eq = memchr(data, '=', size);
1437 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1439 printf("%.*s\n", (int) size, (const char*) data);
1444 return EXIT_SUCCESS;
1447 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1449 r = sd_journal_get_fd(j);
1451 return EXIT_FAILURE;
1454 if (arg_cursor || arg_after_cursor) {
1455 r = sd_journal_seek_cursor(j, arg_cursor ? arg_cursor : arg_after_cursor);
1457 log_error("Failed to seek to cursor: %s", strerror(-r));
1458 return EXIT_FAILURE;
1461 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
1463 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
1465 if (arg_after_cursor && r < 2 && !arg_follow)
1466 /* We couldn't find the next entry after the cursor. */
1469 } else if (arg_since_set && !arg_reverse) {
1470 r = sd_journal_seek_realtime_usec(j, arg_since);
1472 log_error("Failed to seek to date: %s", strerror(-r));
1473 return EXIT_FAILURE;
1475 r = sd_journal_next(j);
1477 } else if (arg_until_set && arg_reverse) {
1478 r = sd_journal_seek_realtime_usec(j, arg_until);
1480 log_error("Failed to seek to date: %s", strerror(-r));
1481 return EXIT_FAILURE;
1483 r = sd_journal_previous(j);
1485 } else if (arg_lines >= 0) {
1486 r = sd_journal_seek_tail(j);
1488 log_error("Failed to seek to tail: %s", strerror(-r));
1489 return EXIT_FAILURE;
1492 r = sd_journal_previous_skip(j, arg_lines);
1494 } else if (arg_reverse) {
1495 r = sd_journal_seek_tail(j);
1497 log_error("Failed to seek to tail: %s", strerror(-r));
1498 return EXIT_FAILURE;
1501 r = sd_journal_previous(j);
1504 r = sd_journal_seek_head(j);
1506 log_error("Failed to seek to head: %s", strerror(-r));
1507 return EXIT_FAILURE;
1510 r = sd_journal_next(j);
1514 log_error("Failed to iterate through journal: %s", strerror(-r));
1515 return EXIT_FAILURE;
1518 if (!arg_no_pager && !arg_follow)
1519 pager_open(arg_pager_end);
1523 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1525 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1527 log_error("Failed to get cutoff: %s", strerror(-r));
1533 printf("-- Logs begin at %s. --\n",
1534 format_timestamp(start_buf, sizeof(start_buf), start));
1536 printf("-- Logs begin at %s, end at %s. --\n",
1537 format_timestamp(start_buf, sizeof(start_buf), start),
1538 format_timestamp(end_buf, sizeof(end_buf), end));
1543 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1548 r = sd_journal_next(j);
1550 r = sd_journal_previous(j);
1552 log_error("Failed to iterate through journal: %s", strerror(-r));
1559 if (arg_until_set && !arg_reverse) {
1562 r = sd_journal_get_realtime_usec(j, &usec);
1564 log_error("Failed to determine timestamp: %s", strerror(-r));
1567 if (usec > arg_until)
1571 if (arg_since_set && arg_reverse) {
1574 r = sd_journal_get_realtime_usec(j, &usec);
1576 log_error("Failed to determine timestamp: %s", strerror(-r));
1579 if (usec < arg_since)
1585 const char *color_on = on_tty() ? ANSI_HIGHLIGHT_ON : "",
1586 *color_off = on_tty() ? ANSI_HIGHLIGHT_OFF : "";
1588 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1590 if (previous_boot_id_valid &&
1591 !sd_id128_equal(boot_id, previous_boot_id))
1592 printf("%s-- Reboot --%s\n", color_on, color_off);
1594 previous_boot_id = boot_id;
1595 previous_boot_id_valid = true;
1600 arg_all * OUTPUT_SHOW_ALL |
1601 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1602 on_tty() * OUTPUT_COLOR |
1603 arg_catalog * OUTPUT_CATALOG;
1605 r = output_journal(stdout, j, arg_output, 0, flags);
1607 if (r == -EADDRNOTAVAIL)
1609 else if (r < 0 || ferror(stdout))
1616 if (arg_show_cursor) {
1617 _cleanup_free_ char *cursor = NULL;
1619 r = sd_journal_get_cursor(j, &cursor);
1620 if (r < 0 && r != -EADDRNOTAVAIL)
1621 log_error("Failed to get cursor: %s", strerror(-r));
1623 printf("-- cursor: %s\n", cursor);
1629 r = sd_journal_wait(j, (uint64_t) -1);
1631 log_error("Couldn't wait for journal event: %s", strerror(-r));
1641 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;