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>
41 #include "logs-show.h"
43 #include "path-util.h"
46 #include "logs-show.h"
48 #include "journal-internal.h"
49 #include "journal-def.h"
50 #include "journal-verify.h"
51 #include "journal-authenticate.h"
52 #include "journal-qrcode.h"
54 #include "unit-name.h"
57 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
59 static OutputMode arg_output = OUTPUT_SHORT;
60 static bool arg_pager_end = false;
61 static bool arg_follow = false;
62 static bool arg_full = false;
63 static bool arg_all = false;
64 static bool arg_no_pager = false;
65 static int arg_lines = -1;
66 static bool arg_no_tail = false;
67 static bool arg_quiet = false;
68 static bool arg_merge = false;
69 static bool arg_this_boot = false;
70 static const char *arg_cursor = NULL;
71 static const char *arg_directory = NULL;
72 static int arg_priorities = 0xFF;
73 static const char *arg_verify_key = NULL;
75 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
77 static usec_t arg_since, arg_until;
78 static bool arg_since_set = false, arg_until_set = false;
79 static const char *arg_unit = NULL;
80 static bool arg_unit_system;
81 static const char *arg_field = NULL;
82 static bool arg_catalog = false;
83 static bool arg_reverse = false;
94 } arg_action = ACTION_SHOW;
96 static int help(void) {
98 printf("%s [OPTIONS...] [MATCHES...]\n\n"
99 "Query the journal.\n\n"
101 " --since=DATE Start showing entries newer or of the specified date\n"
102 " --until=DATE Stop showing entries older or of the specified date\n"
103 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
104 " -b --this-boot Show data only from current boot\n"
105 " -u --unit=UNIT Show data only from the specified unit\n"
106 " --user-unit=UNIT Show data only from the specified user session unit\n"
107 " -p --priority=RANGE Show only messages within the specified priority range\n"
108 " -e --pager-end Immediately jump to end of the journal in the pager\n"
109 " -f --follow Follow journal\n"
110 " -n --lines[=INTEGER] Number of journal entries to show\n"
111 " --no-tail Show all lines, even in follow mode\n"
112 " -r --reverse Show the newest entries first\n"
113 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
114 " verbose, export, json, json-pretty, json-sse, cat)\n"
115 " -x --catalog Add message explanations where available\n"
116 " --full Do not ellipsize fields\n"
117 " -a --all Show all fields, including long and unprintable\n"
118 " -q --quiet Don't show privilege warning\n"
119 " --no-pager Do not pipe output into a pager\n"
120 " -m --merge Show entries from all available journals\n"
121 " -D --directory=PATH Show journal files from directory\n"
123 " --interval=TIME Time interval for changing the FSS sealing key\n"
124 " --verify-key=KEY Specify FSS verification key\n"
127 " -h --help Show this help\n"
128 " --version Show package version\n"
129 " --new-id128 Generate a new 128 Bit ID\n"
130 " --header Show journal header information\n"
131 " --disk-usage Show total disk usage\n"
132 " -F --field=FIELD List all values a certain field takes\n"
133 " --list-catalog Show message IDs of all entries in the message catalog\n"
134 " --update-catalog Update the message catalog database\n"
136 " --setup-keys Generate new FSS key pair\n"
137 " --verify Verify journal file consistency\n"
139 , program_invocation_short_name);
144 static int parse_argv(int argc, char *argv[]) {
165 static const struct option options[] = {
166 { "help", no_argument, NULL, 'h' },
167 { "version" , no_argument, NULL, ARG_VERSION },
168 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
169 { "pager-end", no_argument, NULL, 'e' },
170 { "follow", no_argument, NULL, 'f' },
171 { "output", required_argument, NULL, 'o' },
172 { "all", no_argument, NULL, 'a' },
173 { "full", no_argument, NULL, ARG_FULL },
174 { "lines", optional_argument, NULL, 'n' },
175 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
176 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
177 { "quiet", no_argument, NULL, 'q' },
178 { "merge", no_argument, NULL, 'm' },
179 { "this-boot", no_argument, NULL, 'b' },
180 { "directory", required_argument, NULL, 'D' },
181 { "header", no_argument, NULL, ARG_HEADER },
182 { "priority", required_argument, NULL, 'p' },
183 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
184 { "interval", required_argument, NULL, ARG_INTERVAL },
185 { "verify", no_argument, NULL, ARG_VERIFY },
186 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
187 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
188 { "cursor", required_argument, NULL, 'c' },
189 { "since", required_argument, NULL, ARG_SINCE },
190 { "until", required_argument, NULL, ARG_UNTIL },
191 { "unit", required_argument, NULL, 'u' },
192 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
193 { "field", required_argument, NULL, 'F' },
194 { "catalog", no_argument, NULL, 'x' },
195 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
196 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
197 { "reverse", no_argument, NULL, 'r' },
206 while ((c = getopt_long(argc, argv, "hefo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) {
215 puts(PACKAGE_STRING);
216 puts(SYSTEMD_FEATURES);
224 arg_pager_end = true;
236 arg_output = output_mode_from_string(optarg);
237 if (arg_output < 0) {
238 log_error("Unknown output format '%s'.", optarg);
242 if (arg_output == OUTPUT_EXPORT ||
243 arg_output == OUTPUT_JSON ||
244 arg_output == OUTPUT_JSON_PRETTY ||
245 arg_output == OUTPUT_JSON_SSE ||
246 arg_output == OUTPUT_CAT)
261 r = safe_atoi(optarg, &arg_lines);
262 if (r < 0 || arg_lines < 0) {
263 log_error("Failed to parse lines '%s'", optarg);
269 /* Hmm, no argument? Maybe the next
270 * word on the command line is
271 * supposed to be the argument? Let's
272 * see if there is one, and is
273 * parsable as a positive
277 safe_atoi(argv[optind], &n) >= 0 &&
293 arg_action = ACTION_NEW_ID128;
305 arg_this_boot = true;
309 arg_directory = optarg;
317 arg_action = ACTION_PRINT_HEADER;
321 arg_action = ACTION_VERIFY;
325 arg_action = ACTION_DISK_USAGE;
330 arg_action = ACTION_SETUP_KEYS;
335 arg_action = ACTION_VERIFY;
336 arg_verify_key = optarg;
341 r = parse_usec(optarg, &arg_interval);
342 if (r < 0 || arg_interval <= 0) {
343 log_error("Failed to parse sealing key change interval: %s", optarg);
351 log_error("Forward-secure sealing not available.");
358 dots = strstr(optarg, "..");
364 a = strndup(optarg, dots - optarg);
368 from = log_level_from_string(a);
369 to = log_level_from_string(dots + 2);
372 if (from < 0 || to < 0) {
373 log_error("Failed to parse log level range %s", optarg);
380 for (i = from; i <= to; i++)
381 arg_priorities |= 1 << i;
383 for (i = to; i <= from; i++)
384 arg_priorities |= 1 << i;
390 p = log_level_from_string(optarg);
392 log_error("Unknown log level %s", optarg);
398 for (i = 0; i <= p; i++)
399 arg_priorities |= 1 << i;
406 r = parse_timestamp(optarg, &arg_since);
408 log_error("Failed to parse timestamp: %s", optarg);
411 arg_since_set = true;
415 r = parse_timestamp(optarg, &arg_until);
417 log_error("Failed to parse timestamp: %s", optarg);
420 arg_until_set = true;
425 arg_unit_system = true;
430 arg_unit_system = false;
444 case ARG_LIST_CATALOG:
445 arg_action = ACTION_LIST_CATALOG;
448 case ARG_UPDATE_CATALOG:
449 arg_action = ACTION_UPDATE_CATALOG;
457 log_error("Unknown option code %c", c);
462 if (arg_follow && !arg_no_tail && arg_lines < 0)
465 if (arg_since_set && arg_until_set && arg_since > arg_until) {
466 log_error("--since= must be before --until=.");
470 if (arg_cursor && arg_since_set) {
471 log_error("Please specify either --since= or --cursor=, not both.");
475 if (arg_follow && arg_reverse) {
476 log_error("Please specify either --reverse= or --follow=, not both.");
483 static int generate_new_id128(void) {
488 r = sd_id128_randomize(&id);
490 log_error("Failed to generate ID: %s", strerror(-r));
494 printf("As string:\n"
495 SD_ID128_FORMAT_STR "\n\n"
497 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
499 "#define MESSAGE_XYZ SD_ID128_MAKE(",
500 SD_ID128_FORMAT_VAL(id),
501 SD_ID128_FORMAT_VAL(id));
502 for (i = 0; i < 16; i++)
503 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
504 fputs(")\n\n", stdout);
506 printf("As Python constant:\n"
508 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
509 SD_ID128_FORMAT_VAL(id));
514 static int add_matches(sd_journal *j, char **args) {
520 STRV_FOREACH(i, args) {
523 r = sd_journal_add_disjunction(j);
524 else if (path_is_absolute(*i)) {
529 p = canonicalize_file_name(*i);
532 if (stat(path, &st) < 0) {
534 log_error("Couldn't stat file: %m");
538 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
539 t = strappend("_EXE=", path);
540 else if (S_ISCHR(st.st_mode))
541 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
542 else if (S_ISBLK(st.st_mode))
543 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
546 log_error("File is not a device node, regular file or is not executable: %s", *i);
555 r = sd_journal_add_match(j, t, 0);
558 r = sd_journal_add_match(j, *i, 0);
561 log_error("Failed to add match '%s': %s", *i, strerror(-r));
569 static int add_this_boot(sd_journal *j) {
570 char match[9+32+1] = "_BOOT_ID=";
579 r = sd_id128_get_boot(&boot_id);
581 log_error("Failed to get boot id: %s", strerror(-r));
585 sd_id128_to_string(boot_id, match + 9);
586 r = sd_journal_add_match(j, match, strlen(match));
588 log_error("Failed to add match: %s", strerror(-r));
595 static int add_unit(sd_journal *j) {
596 _cleanup_free_ char *m = NULL, *u = NULL;
601 if (isempty(arg_unit))
604 u = unit_name_mangle(arg_unit);
609 r = add_matches_for_unit(j, u);
611 r = add_matches_for_user_unit(j, u, getuid());
618 static int add_priorities(sd_journal *j) {
619 char match[] = "PRIORITY=0";
624 if (arg_priorities == 0xFF)
627 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
628 if (arg_priorities & (1 << i)) {
629 match[sizeof(match)-2] = '0' + i;
631 r = sd_journal_add_match(j, match, strlen(match));
633 log_error("Failed to add match: %s", strerror(-r));
641 static int setup_keys(void) {
643 size_t mpk_size, seed_size, state_size, i;
644 uint8_t *mpk, *seed, *state;
646 int fd = -1, r, attr = 0;
647 sd_id128_t machine, boot;
648 char *p = NULL, *k = NULL;
652 r = sd_id128_get_machine(&machine);
654 log_error("Failed to get machine ID: %s", strerror(-r));
658 r = sd_id128_get_boot(&boot);
660 log_error("Failed to get boot ID: %s", strerror(-r));
664 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
665 SD_ID128_FORMAT_VAL(machine)) < 0)
668 if (access(p, F_OK) >= 0) {
669 log_error("Sealing key file %s exists already.", p);
674 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
675 SD_ID128_FORMAT_VAL(machine)) < 0) {
680 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
681 mpk = alloca(mpk_size);
683 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
684 seed = alloca(seed_size);
686 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
687 state = alloca(state_size);
689 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
691 log_error("Failed to open /dev/random: %m");
696 log_info("Generating seed...");
697 l = loop_read(fd, seed, seed_size, true);
698 if (l < 0 || (size_t) l != seed_size) {
699 log_error("Failed to read random seed: %s", strerror(EIO));
704 log_info("Generating key pair...");
705 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
707 log_info("Generating sealing key...");
708 FSPRG_GenState0(state, mpk, seed, seed_size);
710 assert(arg_interval > 0);
712 n = now(CLOCK_REALTIME);
715 close_nointr_nofail(fd);
716 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
718 log_error("Failed to open %s: %m", k);
723 /* Enable secure remove, exclusion from dump, synchronous
724 * writing and in-place updating */
725 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
726 log_warning("FS_IOC_GETFLAGS failed: %m");
728 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
730 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
731 log_warning("FS_IOC_SETFLAGS failed: %m");
734 memcpy(h.signature, "KSHHRHLP", 8);
735 h.machine_id = machine;
737 h.header_size = htole64(sizeof(h));
738 h.start_usec = htole64(n * arg_interval);
739 h.interval_usec = htole64(arg_interval);
740 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
741 h.fsprg_state_size = htole64(state_size);
743 l = loop_write(fd, &h, sizeof(h), false);
744 if (l < 0 || (size_t) l != sizeof(h)) {
745 log_error("Failed to write header: %s", strerror(EIO));
750 l = loop_write(fd, state, state_size, false);
751 if (l < 0 || (size_t) l != state_size) {
752 log_error("Failed to write state: %s", strerror(EIO));
757 if (link(k, p) < 0) {
758 log_error("Failed to link file: %m");
766 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
767 "the following local file. This key file is automatically updated when the\n"
768 "sealing key is advanced. It should not be used on multiple hosts.\n"
772 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
773 "at a safe location and should not be saved locally on disk.\n"
774 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
777 for (i = 0; i < seed_size; i++) {
778 if (i > 0 && i % 3 == 0)
780 printf("%02x", ((uint8_t*) seed)[i]);
783 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
786 char tsb[FORMAT_TIMESPAN_MAX], *hn;
789 ANSI_HIGHLIGHT_OFF "\n"
790 "The sealing key is automatically changed every %s.\n",
791 format_timespan(tsb, sizeof(tsb), arg_interval));
793 hn = gethostname_malloc();
796 hostname_cleanup(hn);
797 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
799 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
802 /* If this is not an UTF-8 system don't print any QR codes */
803 if (is_locale_utf8()) {
804 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
805 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
815 close_nointr_nofail(fd);
826 log_error("Forward-secure sealing not available.");
831 static int verify(sd_journal *j) {
838 log_show_color(true);
840 HASHMAP_FOREACH(f, j->files, i) {
842 usec_t first, validated, last;
845 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
846 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
849 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
851 /* If the key was invalid give up right-away. */
854 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
857 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
858 log_info("PASS: %s", f->path);
860 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
862 log_info("=> Validated from %s to %s, final %s entries not sealed.",
863 format_timestamp(a, sizeof(a), first),
864 format_timestamp(b, sizeof(b), validated),
865 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
867 log_info("=> No sealing yet, %s of entries not sealed.",
868 format_timespan(c, sizeof(c), last - first));
870 log_info("=> No sealing yet, no entries in file.");
878 static int access_check(void) {
881 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("systemd-journal") <= 0) {
882 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages.");
886 if (!arg_quiet && geteuid() != 0 && in_group("systemd-journal") <= 0)
887 log_warning("Showing user generated messages only. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off.");
889 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
890 log_error("No access to messages. Only users in the group 'systemd-journal' can see messages.");
898 int main(int argc, char *argv[]) {
900 sd_journal *j = NULL;
901 bool need_seek = false;
902 sd_id128_t previous_boot_id;
903 bool previous_boot_id_valid = false, first_line = true;
906 setlocale(LC_ALL, "");
907 log_parse_environment();
910 r = parse_argv(argc, argv);
914 signal(SIGWINCH, columns_lines_cache_reset);
916 if (arg_action == ACTION_NEW_ID128) {
917 r = generate_new_id128();
921 if (arg_action == ACTION_SETUP_KEYS) {
926 if (arg_action == ACTION_LIST_CATALOG) {
927 r = catalog_list(stdout);
929 log_error("Failed to list catalog: %s", strerror(-r));
933 if (arg_action == ACTION_UPDATE_CATALOG) {
934 r = catalog_update();
943 r = sd_journal_open_directory(&j, arg_directory, 0);
945 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
947 log_error("Failed to open journal: %s", strerror(-r));
951 if (arg_action == ACTION_VERIFY) {
956 if (arg_action == ACTION_PRINT_HEADER) {
957 journal_print_header(j);
962 if (arg_action == ACTION_DISK_USAGE) {
964 char sbytes[FORMAT_BYTES_MAX];
966 r = sd_journal_get_usage(j, &bytes);
970 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
975 r = add_this_boot(j);
983 r = add_matches(j, argv + optind);
987 r = add_priorities(j);
991 /* Opening the fd now means the first sd_journal_wait() will actually wait */
992 r = sd_journal_get_fd(j);
1000 r = sd_journal_query_unique(j, arg_field);
1002 log_error("Failed to query unique data objects: %s", strerror(-r));
1006 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1009 if (arg_lines >= 0 && n_shown >= arg_lines)
1012 eq = memchr(data, '=', size);
1014 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1016 printf("%.*s\n", (int) size, (const char*) data);
1026 r = sd_journal_seek_cursor(j, arg_cursor);
1028 log_error("Failed to seek to cursor: %s", strerror(-r));
1032 r = sd_journal_next(j);
1034 r = sd_journal_previous(j);
1036 } else if (arg_since_set && !arg_reverse) {
1037 r = sd_journal_seek_realtime_usec(j, arg_since);
1039 log_error("Failed to seek to date: %s", strerror(-r));
1042 r = sd_journal_next(j);
1044 } else if (arg_until_set && arg_reverse) {
1045 r = sd_journal_seek_realtime_usec(j, arg_until);
1047 log_error("Failed to seek to date: %s", strerror(-r));
1050 r = sd_journal_previous(j);
1052 } else if (arg_lines >= 0) {
1053 r = sd_journal_seek_tail(j);
1055 log_error("Failed to seek to tail: %s", strerror(-r));
1059 r = sd_journal_previous_skip(j, arg_lines);
1061 } else if (arg_reverse) {
1062 r = sd_journal_seek_tail(j);
1064 log_error("Failed to seek to tail: %s", strerror(-r));
1068 r = sd_journal_previous(j);
1071 r = sd_journal_seek_head(j);
1073 log_error("Failed to seek to head: %s", strerror(-r));
1077 r = sd_journal_next(j);
1081 log_error("Failed to iterate through journal: %s", strerror(-r));
1085 if (!arg_no_pager && !arg_follow)
1086 pager_open(arg_pager_end);
1090 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1092 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1094 log_error("Failed to get cutoff: %s", strerror(-r));
1100 printf("-- Logs begin at %s. --\n",
1101 format_timestamp(start_buf, sizeof(start_buf), start));
1103 printf("-- Logs begin at %s, end at %s. --\n",
1104 format_timestamp(start_buf, sizeof(start_buf), start),
1105 format_timestamp(end_buf, sizeof(end_buf), end));
1110 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1115 r = sd_journal_next(j);
1117 r = sd_journal_previous(j);
1119 log_error("Failed to iterate through journal: %s", strerror(-r));
1127 if (arg_until_set && !arg_reverse) {
1130 r = sd_journal_get_realtime_usec(j, &usec);
1132 log_error("Failed to determine timestamp: %s", strerror(-r));
1135 if (usec > arg_until)
1139 if (arg_since_set && arg_reverse) {
1142 r = sd_journal_get_realtime_usec(j, &usec);
1144 log_error("Failed to determine timestamp: %s", strerror(-r));
1147 if (usec < arg_since)
1154 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1156 if (previous_boot_id_valid &&
1157 !sd_id128_equal(boot_id, previous_boot_id))
1158 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1160 previous_boot_id = boot_id;
1161 previous_boot_id_valid = true;
1166 arg_all * OUTPUT_SHOW_ALL |
1167 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1168 on_tty() * OUTPUT_COLOR |
1169 arg_catalog * OUTPUT_CATALOG;
1171 r = output_journal(stdout, j, arg_output, 0, flags);
1172 if (r < 0 || ferror(stdout))
1182 r = sd_journal_wait(j, (uint64_t) -1);
1184 log_error("Couldn't wait for journal event: %s", strerror(-r));
1193 sd_journal_close(j);
1197 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;