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_this_boot = false;
74 static bool arg_dmesg = false;
75 static const char *arg_cursor = NULL;
76 static const char *arg_directory = NULL;
77 static int arg_priorities = 0xFF;
78 static const char *arg_verify_key = NULL;
80 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
82 static usec_t arg_since, arg_until;
83 static bool arg_since_set = false, arg_until_set = false;
84 static char **arg_system_units = NULL;
85 static char **arg_user_units = NULL;
86 static const char *arg_field = NULL;
87 static bool arg_catalog = false;
88 static bool arg_reverse = false;
89 static const char *arg_root = NULL;
100 ACTION_UPDATE_CATALOG
101 } arg_action = ACTION_SHOW;
103 static int help(void) {
105 printf("%s [OPTIONS...] [MATCHES...]\n\n"
106 "Query the journal.\n\n"
108 " --since=DATE Start showing entries newer or of the specified date\n"
109 " --until=DATE Stop showing entries older or of the specified date\n"
110 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
111 " -b --this-boot Show data only from current boot\n"
112 " -k --dmesg Show kmsg log from current boot\n"
113 " -u --unit=UNIT Show data only from the specified unit\n"
114 " --user-unit=UNIT Show data only from the specified user session unit\n"
115 " -p --priority=RANGE Show only messages within the specified priority range\n"
116 " -e --pager-end Immediately jump to end of the journal in the pager\n"
117 " -f --follow Follow journal\n"
118 " -n --lines[=INTEGER] Number of journal entries to show\n"
119 " --no-tail Show all lines, even in follow mode\n"
120 " -r --reverse Show the newest entries first\n"
121 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
122 " verbose, export, json, json-pretty, json-sse, cat)\n"
123 " -x --catalog Add message explanations where available\n"
124 " --full Do not ellipsize fields\n"
125 " -a --all Show all fields, including long and unprintable\n"
126 " -q --quiet Don't show privilege warning\n"
127 " --no-pager Do not pipe output into a pager\n"
128 " -m --merge Show entries from all available journals\n"
129 " -D --directory=PATH Show journal files from directory\n"
130 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
132 " --interval=TIME Time interval for changing the FSS sealing key\n"
133 " --verify-key=KEY Specify FSS verification key\n"
136 " -h --help Show this help\n"
137 " --version Show package version\n"
138 " --new-id128 Generate a new 128 Bit ID\n"
139 " --header Show journal header information\n"
140 " --disk-usage Show total disk usage\n"
141 " -F --field=FIELD List all values a certain field takes\n"
142 " --list-catalog Show message IDs of all entries in the message catalog\n"
143 " --dump-catalog Show entries in the message catalog\n"
144 " --update-catalog Update the message catalog database\n"
146 " --setup-keys Generate new FSS key pair\n"
147 " --verify Verify journal file consistency\n"
149 , program_invocation_short_name);
154 static int parse_argv(int argc, char *argv[]) {
177 static const struct option options[] = {
178 { "help", no_argument, NULL, 'h' },
179 { "version" , no_argument, NULL, ARG_VERSION },
180 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
181 { "pager-end", no_argument, NULL, 'e' },
182 { "follow", no_argument, NULL, 'f' },
183 { "output", required_argument, NULL, 'o' },
184 { "all", no_argument, NULL, 'a' },
185 { "full", no_argument, NULL, ARG_FULL },
186 { "lines", optional_argument, NULL, 'n' },
187 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
188 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
189 { "quiet", no_argument, NULL, 'q' },
190 { "merge", no_argument, NULL, 'm' },
191 { "this-boot", no_argument, NULL, 'b' },
192 { "dmesg", no_argument, NULL, 'k' },
193 { "directory", required_argument, NULL, 'D' },
194 { "root", required_argument, NULL, ARG_ROOT },
195 { "header", no_argument, NULL, ARG_HEADER },
196 { "priority", required_argument, NULL, 'p' },
197 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
198 { "interval", required_argument, NULL, ARG_INTERVAL },
199 { "verify", no_argument, NULL, ARG_VERIFY },
200 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
201 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
202 { "cursor", required_argument, NULL, 'c' },
203 { "since", required_argument, NULL, ARG_SINCE },
204 { "until", required_argument, NULL, ARG_UNTIL },
205 { "unit", required_argument, NULL, 'u' },
206 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
207 { "field", required_argument, NULL, 'F' },
208 { "catalog", no_argument, NULL, 'x' },
209 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
210 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
211 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
212 { "reverse", no_argument, NULL, 'r' },
221 while ((c = getopt_long(argc, argv, "hefo:an::qmbkD:p:c:u:F:xr", options, NULL)) >= 0) {
230 puts(PACKAGE_STRING);
231 puts(SYSTEMD_FEATURES);
239 arg_pager_end = true;
251 arg_output = output_mode_from_string(optarg);
252 if (arg_output < 0) {
253 log_error("Unknown output format '%s'.", optarg);
257 if (arg_output == OUTPUT_EXPORT ||
258 arg_output == OUTPUT_JSON ||
259 arg_output == OUTPUT_JSON_PRETTY ||
260 arg_output == OUTPUT_JSON_SSE ||
261 arg_output == OUTPUT_CAT)
276 r = safe_atoi(optarg, &arg_lines);
277 if (r < 0 || arg_lines < 0) {
278 log_error("Failed to parse lines '%s'", optarg);
284 /* Hmm, no argument? Maybe the next
285 * word on the command line is
286 * supposed to be the argument? Let's
287 * see if there is one, and is
288 * parsable as a positive
292 safe_atoi(argv[optind], &n) >= 0 &&
308 arg_action = ACTION_NEW_ID128;
320 arg_this_boot = true;
324 arg_this_boot = arg_dmesg = true;
328 arg_directory = optarg;
340 arg_action = ACTION_PRINT_HEADER;
344 arg_action = ACTION_VERIFY;
348 arg_action = ACTION_DISK_USAGE;
353 arg_action = ACTION_SETUP_KEYS;
358 arg_action = ACTION_VERIFY;
359 arg_verify_key = optarg;
364 r = parse_sec(optarg, &arg_interval);
365 if (r < 0 || arg_interval <= 0) {
366 log_error("Failed to parse sealing key change interval: %s", optarg);
374 log_error("Forward-secure sealing not available.");
381 dots = strstr(optarg, "..");
387 a = strndup(optarg, dots - optarg);
391 from = log_level_from_string(a);
392 to = log_level_from_string(dots + 2);
395 if (from < 0 || to < 0) {
396 log_error("Failed to parse log level range %s", optarg);
403 for (i = from; i <= to; i++)
404 arg_priorities |= 1 << i;
406 for (i = to; i <= from; i++)
407 arg_priorities |= 1 << i;
413 p = log_level_from_string(optarg);
415 log_error("Unknown log level %s", optarg);
421 for (i = 0; i <= p; i++)
422 arg_priorities |= 1 << i;
429 r = parse_timestamp(optarg, &arg_since);
431 log_error("Failed to parse timestamp: %s", optarg);
434 arg_since_set = true;
438 r = parse_timestamp(optarg, &arg_until);
440 log_error("Failed to parse timestamp: %s", optarg);
443 arg_until_set = true;
447 r = strv_extend(&arg_system_units, optarg);
453 r = strv_extend(&arg_user_units, optarg);
469 case ARG_LIST_CATALOG:
470 arg_action = ACTION_LIST_CATALOG;
473 case ARG_DUMP_CATALOG:
474 arg_action = ACTION_DUMP_CATALOG;
477 case ARG_UPDATE_CATALOG:
478 arg_action = ACTION_UPDATE_CATALOG;
486 log_error("Unknown option code %c", c);
491 if (arg_follow && !arg_no_tail && arg_lines < 0)
494 if (arg_since_set && arg_until_set && arg_since > arg_until) {
495 log_error("--since= must be before --until=.");
499 if (arg_cursor && arg_since_set) {
500 log_error("Please specify either --since= or --cursor=, not both.");
504 if (arg_follow && arg_reverse) {
505 log_error("Please specify either --reverse= or --follow=, not both.");
512 static int generate_new_id128(void) {
517 r = sd_id128_randomize(&id);
519 log_error("Failed to generate ID: %s", strerror(-r));
523 printf("As string:\n"
524 SD_ID128_FORMAT_STR "\n\n"
526 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
528 "#define MESSAGE_XYZ SD_ID128_MAKE(",
529 SD_ID128_FORMAT_VAL(id),
530 SD_ID128_FORMAT_VAL(id));
531 for (i = 0; i < 16; i++)
532 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
533 fputs(")\n\n", stdout);
535 printf("As Python constant:\n"
537 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
538 SD_ID128_FORMAT_VAL(id));
543 static int add_matches(sd_journal *j, char **args) {
548 STRV_FOREACH(i, args) {
552 r = sd_journal_add_disjunction(j);
553 else if (path_is_absolute(*i)) {
554 _cleanup_free_ char *p, *t = NULL;
558 p = canonicalize_file_name(*i);
561 if (stat(path, &st) < 0) {
562 log_error("Couldn't stat file: %m");
566 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
567 t = strappend("_EXE=", path);
568 else if (S_ISCHR(st.st_mode))
569 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
570 else if (S_ISBLK(st.st_mode))
571 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
573 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
580 r = sd_journal_add_match(j, t, 0);
582 r = sd_journal_add_match(j, *i, 0);
585 log_error("Failed to add match '%s': %s", *i, strerror(-r));
593 static int add_this_boot(sd_journal *j) {
594 char match[9+32+1] = "_BOOT_ID=";
603 r = sd_id128_get_boot(&boot_id);
605 log_error("Failed to get boot id: %s", strerror(-r));
609 sd_id128_to_string(boot_id, match + 9);
610 r = sd_journal_add_match(j, match, strlen(match));
612 log_error("Failed to add match: %s", strerror(-r));
616 r = sd_journal_add_conjunction(j);
623 static int add_dmesg(sd_journal *j) {
630 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
632 log_error("Failed to add match: %s", strerror(-r));
636 r = sd_journal_add_conjunction(j);
643 static int add_units(sd_journal *j) {
644 _cleanup_free_ char *u = NULL;
650 STRV_FOREACH(i, arg_system_units) {
651 u = unit_name_mangle(*i);
654 r = add_matches_for_unit(j, u);
657 r = sd_journal_add_disjunction(j);
662 STRV_FOREACH(i, arg_user_units) {
663 u = unit_name_mangle(*i);
667 r = add_matches_for_user_unit(j, u, getuid());
671 r = sd_journal_add_disjunction(j);
677 r = sd_journal_add_conjunction(j);
684 static int add_priorities(sd_journal *j) {
685 char match[] = "PRIORITY=0";
689 if (arg_priorities == 0xFF)
692 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
693 if (arg_priorities & (1 << i)) {
694 match[sizeof(match)-2] = '0' + i;
696 r = sd_journal_add_match(j, match, strlen(match));
698 log_error("Failed to add match: %s", strerror(-r));
703 r = sd_journal_add_conjunction(j);
710 static int setup_keys(void) {
712 size_t mpk_size, seed_size, state_size, i;
713 uint8_t *mpk, *seed, *state;
715 int fd = -1, r, attr = 0;
716 sd_id128_t machine, boot;
717 char *p = NULL, *k = NULL;
721 r = sd_id128_get_machine(&machine);
723 log_error("Failed to get machine ID: %s", strerror(-r));
727 r = sd_id128_get_boot(&boot);
729 log_error("Failed to get boot ID: %s", strerror(-r));
733 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
734 SD_ID128_FORMAT_VAL(machine)) < 0)
737 if (access(p, F_OK) >= 0) {
738 log_error("Sealing key file %s exists already.", p);
743 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
744 SD_ID128_FORMAT_VAL(machine)) < 0) {
749 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
750 mpk = alloca(mpk_size);
752 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
753 seed = alloca(seed_size);
755 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
756 state = alloca(state_size);
758 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
760 log_error("Failed to open /dev/random: %m");
765 log_info("Generating seed...");
766 l = loop_read(fd, seed, seed_size, true);
767 if (l < 0 || (size_t) l != seed_size) {
768 log_error("Failed to read random seed: %s", strerror(EIO));
773 log_info("Generating key pair...");
774 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
776 log_info("Generating sealing key...");
777 FSPRG_GenState0(state, mpk, seed, seed_size);
779 assert(arg_interval > 0);
781 n = now(CLOCK_REALTIME);
784 close_nointr_nofail(fd);
785 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
787 log_error("Failed to open %s: %m", k);
792 /* Enable secure remove, exclusion from dump, synchronous
793 * writing and in-place updating */
794 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
795 log_warning("FS_IOC_GETFLAGS failed: %m");
797 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
799 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
800 log_warning("FS_IOC_SETFLAGS failed: %m");
803 memcpy(h.signature, "KSHHRHLP", 8);
804 h.machine_id = machine;
806 h.header_size = htole64(sizeof(h));
807 h.start_usec = htole64(n * arg_interval);
808 h.interval_usec = htole64(arg_interval);
809 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
810 h.fsprg_state_size = htole64(state_size);
812 l = loop_write(fd, &h, sizeof(h), false);
813 if (l < 0 || (size_t) l != sizeof(h)) {
814 log_error("Failed to write header: %s", strerror(EIO));
819 l = loop_write(fd, state, state_size, false);
820 if (l < 0 || (size_t) l != state_size) {
821 log_error("Failed to write state: %s", strerror(EIO));
826 if (link(k, p) < 0) {
827 log_error("Failed to link file: %m");
835 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
836 "the following local file. This key file is automatically updated when the\n"
837 "sealing key is advanced. It should not be used on multiple hosts.\n"
841 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
842 "at a safe location and should not be saved locally on disk.\n"
843 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
846 for (i = 0; i < seed_size; i++) {
847 if (i > 0 && i % 3 == 0)
849 printf("%02x", ((uint8_t*) seed)[i]);
852 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
855 char tsb[FORMAT_TIMESPAN_MAX], *hn;
858 ANSI_HIGHLIGHT_OFF "\n"
859 "The sealing key is automatically changed every %s.\n",
860 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
862 hn = gethostname_malloc();
865 hostname_cleanup(hn, false);
866 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
868 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
871 /* If this is not an UTF-8 system don't print any QR codes */
872 if (is_locale_utf8()) {
873 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
874 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
884 close_nointr_nofail(fd);
895 log_error("Forward-secure sealing not available.");
900 static int verify(sd_journal *j) {
907 log_show_color(true);
909 HASHMAP_FOREACH(f, j->files, i) {
911 usec_t first, validated, last;
914 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
915 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
918 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
920 /* If the key was invalid give up right-away. */
923 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
926 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
927 log_info("PASS: %s", f->path);
929 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
931 log_info("=> Validated from %s to %s, final %s entries not sealed.",
932 format_timestamp(a, sizeof(a), first),
933 format_timestamp(b, sizeof(b), validated),
934 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
936 log_info("=> No sealing yet, %s of entries not sealed.",
937 format_timespan(c, sizeof(c), last - first, 0));
939 log_info("=> No sealing yet, no entries in file.");
948 static int access_check_var_log_journal(sd_journal *j) {
949 _cleanup_strv_free_ char **g = NULL;
955 have_access = in_group("systemd-journal") > 0;
958 /* Let's enumerate all groups from the default ACL of
959 * the directory, which generally should allow access
960 * to most journal files too */
961 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
969 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
970 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
971 " turn off this notice.");
973 _cleanup_free_ char *s = NULL;
975 r = strv_extend(&g, "systemd-journal");
982 s = strv_join(g, "', '");
986 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
987 " Users in the groups '%s' can see all messages.\n"
988 " Pass -q to turn off this notice.", s);
996 static int access_check(sd_journal *j) {
1003 if (set_isempty(j->errors)) {
1004 if (hashmap_isempty(j->files))
1005 log_notice("No journal files were found.");
1009 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
1011 /* If /var/log/journal doesn't even exist,
1012 * unprivileged users have no access at all */
1013 if (access("/var/log/journal", F_OK) < 0 &&
1015 in_group("systemd-journal") <= 0) {
1016 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1017 "enabled. Users in the 'systemd-journal' group may always access messages.");
1021 /* If /var/log/journal exists, try to pring a nice
1022 notice if the user lacks access to it */
1023 if (!arg_quiet && geteuid() != 0) {
1024 r = access_check_var_log_journal(j);
1029 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1030 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1031 "group may access messages.");
1036 if (hashmap_isempty(j->files)) {
1037 log_error("No journal files were opened due to insufficient permissions.");
1042 SET_FOREACH(code, j->errors, it) {
1045 err = -PTR_TO_INT(code);
1049 log_warning("Error was encountered while opening journal files: %s",
1056 int main(int argc, char *argv[]) {
1058 _cleanup_journal_close_ sd_journal*j = NULL;
1059 bool need_seek = false;
1060 sd_id128_t previous_boot_id;
1061 bool previous_boot_id_valid = false, first_line = true;
1064 setlocale(LC_ALL, "");
1065 log_parse_environment();
1068 r = parse_argv(argc, argv);
1072 signal(SIGWINCH, columns_lines_cache_reset);
1074 if (arg_action == ACTION_NEW_ID128) {
1075 r = generate_new_id128();
1079 if (arg_action == ACTION_SETUP_KEYS) {
1084 if (arg_action == ACTION_UPDATE_CATALOG ||
1085 arg_action == ACTION_LIST_CATALOG ||
1086 arg_action == ACTION_DUMP_CATALOG) {
1088 const char* database = CATALOG_DATABASE;
1089 _cleanup_free_ char *copy = NULL;
1091 copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1096 path_kill_slashes(copy);
1100 if (arg_action == ACTION_UPDATE_CATALOG) {
1101 r = catalog_update(database, arg_root, catalog_file_dirs);
1103 log_error("Failed to list catalog: %s", strerror(-r));
1105 bool oneline = arg_action == ACTION_LIST_CATALOG;
1108 r = catalog_list_items(stdout, database,
1109 oneline, argv + optind);
1111 r = catalog_list(stdout, database, oneline);
1113 log_error("Failed to list catalog: %s", strerror(-r));
1120 r = sd_journal_open_directory(&j, arg_directory, 0);
1122 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
1124 log_error("Failed to open journal: %s", strerror(-r));
1125 return EXIT_FAILURE;
1128 r = access_check(j);
1130 return EXIT_FAILURE;
1132 if (arg_action == ACTION_VERIFY) {
1137 if (arg_action == ACTION_PRINT_HEADER) {
1138 journal_print_header(j);
1139 return EXIT_SUCCESS;
1142 if (arg_action == ACTION_DISK_USAGE) {
1144 char sbytes[FORMAT_BYTES_MAX];
1146 r = sd_journal_get_usage(j, &bytes);
1148 return EXIT_FAILURE;
1150 printf("Journals take up %s on disk.\n",
1151 format_bytes(sbytes, sizeof(sbytes), bytes));
1152 return EXIT_SUCCESS;
1155 r = add_this_boot(j);
1157 return EXIT_FAILURE;
1161 return EXIT_FAILURE;
1164 strv_free(arg_system_units);
1165 strv_free(arg_user_units);
1168 return EXIT_FAILURE;
1170 r = add_priorities(j);
1172 return EXIT_FAILURE;
1174 r = add_matches(j, argv + optind);
1176 return EXIT_FAILURE;
1178 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1179 r = sd_journal_get_fd(j);
1181 return EXIT_FAILURE;
1187 r = sd_journal_set_data_threshold(j, 0);
1189 log_error("Failed to unset data size threshold");
1190 return EXIT_FAILURE;
1193 r = sd_journal_query_unique(j, arg_field);
1195 log_error("Failed to query unique data objects: %s", strerror(-r));
1196 return EXIT_FAILURE;
1199 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1202 if (arg_lines >= 0 && n_shown >= arg_lines)
1205 eq = memchr(data, '=', size);
1207 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1209 printf("%.*s\n", (int) size, (const char*) data);
1214 return EXIT_SUCCESS;
1218 r = sd_journal_seek_cursor(j, arg_cursor);
1220 log_error("Failed to seek to cursor: %s", strerror(-r));
1221 return EXIT_FAILURE;
1224 r = sd_journal_next(j);
1226 r = sd_journal_previous(j);
1228 } else if (arg_since_set && !arg_reverse) {
1229 r = sd_journal_seek_realtime_usec(j, arg_since);
1231 log_error("Failed to seek to date: %s", strerror(-r));
1232 return EXIT_FAILURE;
1234 r = sd_journal_next(j);
1236 } else if (arg_until_set && arg_reverse) {
1237 r = sd_journal_seek_realtime_usec(j, arg_until);
1239 log_error("Failed to seek to date: %s", strerror(-r));
1240 return EXIT_FAILURE;
1242 r = sd_journal_previous(j);
1244 } else if (arg_lines >= 0) {
1245 r = sd_journal_seek_tail(j);
1247 log_error("Failed to seek to tail: %s", strerror(-r));
1248 return EXIT_FAILURE;
1251 r = sd_journal_previous_skip(j, arg_lines);
1253 } else if (arg_reverse) {
1254 r = sd_journal_seek_tail(j);
1256 log_error("Failed to seek to tail: %s", strerror(-r));
1257 return EXIT_FAILURE;
1260 r = sd_journal_previous(j);
1263 r = sd_journal_seek_head(j);
1265 log_error("Failed to seek to head: %s", strerror(-r));
1266 return EXIT_FAILURE;
1269 r = sd_journal_next(j);
1273 log_error("Failed to iterate through journal: %s", strerror(-r));
1274 return EXIT_FAILURE;
1277 if (!arg_no_pager && !arg_follow)
1278 pager_open(arg_pager_end);
1282 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1284 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1286 log_error("Failed to get cutoff: %s", strerror(-r));
1292 printf("-- Logs begin at %s. --\n",
1293 format_timestamp(start_buf, sizeof(start_buf), start));
1295 printf("-- Logs begin at %s, end at %s. --\n",
1296 format_timestamp(start_buf, sizeof(start_buf), start),
1297 format_timestamp(end_buf, sizeof(end_buf), end));
1302 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1307 r = sd_journal_next(j);
1309 r = sd_journal_previous(j);
1311 log_error("Failed to iterate through journal: %s", strerror(-r));
1319 if (arg_until_set && !arg_reverse) {
1322 r = sd_journal_get_realtime_usec(j, &usec);
1324 log_error("Failed to determine timestamp: %s", strerror(-r));
1327 if (usec > arg_until)
1331 if (arg_since_set && arg_reverse) {
1334 r = sd_journal_get_realtime_usec(j, &usec);
1336 log_error("Failed to determine timestamp: %s", strerror(-r));
1339 if (usec < arg_since)
1346 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1348 if (previous_boot_id_valid &&
1349 !sd_id128_equal(boot_id, previous_boot_id))
1350 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1352 previous_boot_id = boot_id;
1353 previous_boot_id_valid = true;
1358 arg_all * OUTPUT_SHOW_ALL |
1359 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1360 on_tty() * OUTPUT_COLOR |
1361 arg_catalog * OUTPUT_CATALOG;
1363 r = output_journal(stdout, j, arg_output, 0, flags);
1364 if (r < 0 || ferror(stdout))
1374 r = sd_journal_wait(j, (uint64_t) -1);
1376 log_error("Couldn't wait for journal event: %s", strerror(-r));
1386 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;