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 int arg_lines = -1;
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_unit_type = NULL;
79 static const char *arg_field = NULL;
80 static bool arg_catalog = false;
81 static bool arg_reverse = false;
92 } arg_action = ACTION_SHOW;
94 static int help(void) {
96 printf("%s [OPTIONS...] [MATCHES...]\n\n"
97 "Query the journal.\n\n"
99 " --since=DATE Start showing entries newer or of the specified date\n"
100 " --until=DATE Stop showing entries older or of the specified date\n"
101 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
102 " -b --this-boot Show data only from current boot\n"
103 " -u --unit=UNIT Show data only from the specified unit\n"
104 " --user-unit=UNIT Show data only from the specified user session unit\n"
105 " -p --priority=RANGE Show only messages within the specified priority range\n"
106 " -f --follow Follow journal\n"
107 " -n --lines[=INTEGER] Number of journal entries to show\n"
108 " --no-tail Show all lines, even in follow mode\n"
109 " -r --reverse Show the newest entries first\n"
110 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
111 " verbose, export, json, json-pretty, json-sse, cat)\n"
112 " -x --catalog Add message explanations where available\n"
113 " --full Do not ellipsize fields\n"
114 " -a --all Show all fields, including long and unprintable\n"
115 " -q --quiet Don't show privilege warning\n"
116 " --no-pager Do not pipe output into a pager\n"
117 " -m --merge Show entries from all available journals\n"
118 " -D --directory=PATH Show journal files from directory\n"
120 " --interval=TIME Time interval for changing the FSS sealing key\n"
121 " --verify-key=KEY Specify FSS verification key\n"
124 " -h --help Show this help\n"
125 " --version Show package version\n"
126 " --new-id128 Generate a new 128 Bit ID\n"
127 " --header Show journal header information\n"
128 " --disk-usage Show total disk usage\n"
129 " -F --field=FIELD List all values a certain field takes\n"
130 " --list-catalog Show message IDs of all entries in the message catalog\n"
131 " --update-catalog Update the message catalog database\n"
133 " --setup-keys Generate new FSS key pair\n"
134 " --verify Verify journal file consistency\n"
136 , program_invocation_short_name);
141 static int parse_argv(int argc, char *argv[]) {
162 static const struct option options[] = {
163 { "help", no_argument, NULL, 'h' },
164 { "version" , no_argument, NULL, ARG_VERSION },
165 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
166 { "follow", no_argument, NULL, 'f' },
167 { "output", required_argument, NULL, 'o' },
168 { "all", no_argument, NULL, 'a' },
169 { "full", no_argument, NULL, ARG_FULL },
170 { "lines", optional_argument, NULL, 'n' },
171 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
172 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
173 { "quiet", no_argument, NULL, 'q' },
174 { "merge", no_argument, NULL, 'm' },
175 { "this-boot", no_argument, NULL, 'b' },
176 { "directory", required_argument, NULL, 'D' },
177 { "header", no_argument, NULL, ARG_HEADER },
178 { "priority", required_argument, NULL, 'p' },
179 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
180 { "interval", required_argument, NULL, ARG_INTERVAL },
181 { "verify", no_argument, NULL, ARG_VERIFY },
182 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
183 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
184 { "cursor", required_argument, NULL, 'c' },
185 { "since", required_argument, NULL, ARG_SINCE },
186 { "until", required_argument, NULL, ARG_UNTIL },
187 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
188 { "unit", required_argument, NULL, 'u' },
189 { "field", required_argument, NULL, 'F' },
190 { "catalog", no_argument, NULL, 'x' },
191 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
192 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
193 { "reverse", no_argument, NULL, 'r' },
202 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) {
211 puts(PACKAGE_STRING);
212 puts(SYSTEMD_FEATURES);
224 arg_output = output_mode_from_string(optarg);
225 if (arg_output < 0) {
226 log_error("Unknown output format '%s'.", optarg);
230 if (arg_output == OUTPUT_EXPORT ||
231 arg_output == OUTPUT_JSON ||
232 arg_output == OUTPUT_JSON_PRETTY ||
233 arg_output == OUTPUT_JSON_SSE ||
234 arg_output == OUTPUT_CAT)
249 r = safe_atoi(optarg, &arg_lines);
250 if (r < 0 || arg_lines < 0) {
251 log_error("Failed to parse lines '%s'", optarg);
257 /* Hmm, no argument? Maybe the next
258 * word on the command line is
259 * supposed to be the argument? Let's
260 * see if there is one, and is
261 * parsable as a positive
265 safe_atoi(argv[optind], &n) >= 0 &&
281 arg_action = ACTION_NEW_ID128;
293 arg_this_boot = true;
297 arg_directory = optarg;
305 arg_action = ACTION_PRINT_HEADER;
309 arg_action = ACTION_VERIFY;
313 arg_action = ACTION_DISK_USAGE;
318 arg_action = ACTION_SETUP_KEYS;
323 arg_action = ACTION_VERIFY;
324 arg_verify_key = optarg;
329 r = parse_usec(optarg, &arg_interval);
330 if (r < 0 || arg_interval <= 0) {
331 log_error("Failed to parse sealing key change interval: %s", optarg);
339 log_error("Forward-secure sealing not available.");
346 dots = strstr(optarg, "..");
352 a = strndup(optarg, dots - optarg);
356 from = log_level_from_string(a);
357 to = log_level_from_string(dots + 2);
360 if (from < 0 || to < 0) {
361 log_error("Failed to parse log level range %s", optarg);
368 for (i = from; i <= to; i++)
369 arg_priorities |= 1 << i;
371 for (i = to; i <= from; i++)
372 arg_priorities |= 1 << i;
378 p = log_level_from_string(optarg);
380 log_error("Unknown log level %s", optarg);
386 for (i = 0; i <= p; i++)
387 arg_priorities |= 1 << i;
394 r = parse_timestamp(optarg, &arg_since);
396 log_error("Failed to parse timestamp: %s", optarg);
399 arg_since_set = true;
403 r = parse_timestamp(optarg, &arg_until);
405 log_error("Failed to parse timestamp: %s", optarg);
408 arg_until_set = true;
413 arg_unit_type = "_SYSTEMD_USER_UNIT=";
418 arg_unit_type = "_SYSTEMD_UNIT=";
432 case ARG_LIST_CATALOG:
433 arg_action = ACTION_LIST_CATALOG;
436 case ARG_UPDATE_CATALOG:
437 arg_action = ACTION_UPDATE_CATALOG;
445 log_error("Unknown option code %c", c);
450 if (arg_follow && !arg_no_tail && arg_lines < 0)
453 if (arg_since_set && arg_until_set && arg_since > arg_until) {
454 log_error("--since= must be before --until=.");
458 if (arg_cursor && arg_since_set) {
459 log_error("Please specify either --since= or --cursor=, not both.");
463 if (arg_follow && arg_reverse) {
464 log_error("Please specify either --reverse= or --follow=, not both.");
471 static int generate_new_id128(void) {
476 r = sd_id128_randomize(&id);
478 log_error("Failed to generate ID: %s", strerror(-r));
482 printf("As string:\n"
483 SD_ID128_FORMAT_STR "\n\n"
485 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
487 "#define MESSAGE_XYZ SD_ID128_MAKE(",
488 SD_ID128_FORMAT_VAL(id),
489 SD_ID128_FORMAT_VAL(id));
490 for (i = 0; i < 16; i++)
491 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
492 fputs(")\n\n", stdout);
494 printf("As Python constant:\n"
496 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
497 SD_ID128_FORMAT_VAL(id));
502 static int add_matches(sd_journal *j, char **args) {
508 STRV_FOREACH(i, args) {
511 r = sd_journal_add_disjunction(j);
512 else if (path_is_absolute(*i)) {
517 p = canonicalize_file_name(*i);
520 if (stat(path, &st) < 0) {
522 log_error("Couldn't stat file: %m");
526 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
527 t = strappend("_EXE=", path);
528 else if (S_ISCHR(st.st_mode))
529 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
530 else if (S_ISBLK(st.st_mode))
531 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
534 log_error("File is not a device node, regular file or is not executable: %s", *i);
543 r = sd_journal_add_match(j, t, 0);
546 r = sd_journal_add_match(j, *i, 0);
549 log_error("Failed to add match '%s': %s", *i, strerror(-r));
557 static int add_this_boot(sd_journal *j) {
558 char match[9+32+1] = "_BOOT_ID=";
567 r = sd_id128_get_boot(&boot_id);
569 log_error("Failed to get boot id: %s", strerror(-r));
573 sd_id128_to_string(boot_id, match + 9);
574 r = sd_journal_add_match(j, match, strlen(match));
576 log_error("Failed to add match: %s", strerror(-r));
583 static int add_unit(sd_journal *j) {
584 _cleanup_free_ char *m = NULL, *u = NULL;
589 if (isempty(arg_unit))
592 u = unit_name_mangle(arg_unit);
596 m = strappend(arg_unit_type, u);
601 r = sd_journal_add_match(j, m, strlen(m));
603 log_error("Failed to add match: %s", strerror(-r));
610 static int add_priorities(sd_journal *j) {
611 char match[] = "PRIORITY=0";
616 if (arg_priorities == 0xFF)
619 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
620 if (arg_priorities & (1 << i)) {
621 match[sizeof(match)-2] = '0' + i;
623 r = sd_journal_add_match(j, match, strlen(match));
625 log_error("Failed to add match: %s", strerror(-r));
633 static int setup_keys(void) {
635 size_t mpk_size, seed_size, state_size, i;
636 uint8_t *mpk, *seed, *state;
638 int fd = -1, r, attr = 0;
639 sd_id128_t machine, boot;
640 char *p = NULL, *k = NULL;
644 r = sd_id128_get_machine(&machine);
646 log_error("Failed to get machine ID: %s", strerror(-r));
650 r = sd_id128_get_boot(&boot);
652 log_error("Failed to get boot ID: %s", strerror(-r));
656 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
657 SD_ID128_FORMAT_VAL(machine)) < 0)
660 if (access(p, F_OK) >= 0) {
661 log_error("Sealing key file %s exists already.", p);
666 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
667 SD_ID128_FORMAT_VAL(machine)) < 0) {
672 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
673 mpk = alloca(mpk_size);
675 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
676 seed = alloca(seed_size);
678 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
679 state = alloca(state_size);
681 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
683 log_error("Failed to open /dev/random: %m");
688 log_info("Generating seed...");
689 l = loop_read(fd, seed, seed_size, true);
690 if (l < 0 || (size_t) l != seed_size) {
691 log_error("Failed to read random seed: %s", strerror(EIO));
696 log_info("Generating key pair...");
697 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
699 log_info("Generating sealing key...");
700 FSPRG_GenState0(state, mpk, seed, seed_size);
702 assert(arg_interval > 0);
704 n = now(CLOCK_REALTIME);
707 close_nointr_nofail(fd);
708 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
710 log_error("Failed to open %s: %m", k);
715 /* Enable secure remove, exclusion from dump, synchronous
716 * writing and in-place updating */
717 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
718 log_warning("FS_IOC_GETFLAGS failed: %m");
720 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
722 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
723 log_warning("FS_IOC_SETFLAGS failed: %m");
726 memcpy(h.signature, "KSHHRHLP", 8);
727 h.machine_id = machine;
729 h.header_size = htole64(sizeof(h));
730 h.start_usec = htole64(n * arg_interval);
731 h.interval_usec = htole64(arg_interval);
732 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
733 h.fsprg_state_size = htole64(state_size);
735 l = loop_write(fd, &h, sizeof(h), false);
736 if (l < 0 || (size_t) l != sizeof(h)) {
737 log_error("Failed to write header: %s", strerror(EIO));
742 l = loop_write(fd, state, state_size, false);
743 if (l < 0 || (size_t) l != state_size) {
744 log_error("Failed to write state: %s", strerror(EIO));
749 if (link(k, p) < 0) {
750 log_error("Failed to link file: %m");
758 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
759 "the following local file. This key file is automatically updated when the\n"
760 "sealing key is advanced. It should not be used on multiple hosts.\n"
764 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
765 "at a safe location and should not be saved locally on disk.\n"
766 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
769 for (i = 0; i < seed_size; i++) {
770 if (i > 0 && i % 3 == 0)
772 printf("%02x", ((uint8_t*) seed)[i]);
775 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
778 char tsb[FORMAT_TIMESPAN_MAX], *hn;
781 ANSI_HIGHLIGHT_OFF "\n"
782 "The sealing key is automatically changed every %s.\n",
783 format_timespan(tsb, sizeof(tsb), arg_interval));
785 hn = gethostname_malloc();
788 hostname_cleanup(hn);
789 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
791 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
794 /* If this is not an UTF-8 system don't print any QR codes */
795 if (is_locale_utf8()) {
796 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
797 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
807 close_nointr_nofail(fd);
818 log_error("Forward-secure sealing not available.");
823 static int verify(sd_journal *j) {
830 log_show_color(true);
832 HASHMAP_FOREACH(f, j->files, i) {
834 usec_t first, validated, last;
837 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
838 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
841 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
843 /* If the key was invalid give up right-away. */
846 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
849 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
850 log_info("PASS: %s", f->path);
852 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
854 log_info("=> Validated from %s to %s, final %s entries not sealed.",
855 format_timestamp(a, sizeof(a), first),
856 format_timestamp(b, sizeof(b), validated),
857 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
859 log_info("=> No sealing yet, %s of entries not sealed.",
860 format_timespan(c, sizeof(c), last - first));
862 log_info("=> No sealing yet, no entries in file.");
870 static int access_check(void) {
873 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("systemd-journal") <= 0) {
874 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages.");
878 if (!arg_quiet && geteuid() != 0 && in_group("systemd-journal") <= 0)
879 log_warning("Showing user generated messages only. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off.");
881 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
882 log_error("No access to messages. Only users in the group 'systemd-journal' can see messages.");
890 int main(int argc, char *argv[]) {
892 sd_journal *j = NULL;
893 bool need_seek = false;
894 sd_id128_t previous_boot_id;
895 bool previous_boot_id_valid = false, first_line = true;
898 setlocale(LC_ALL, "");
899 log_parse_environment();
902 r = parse_argv(argc, argv);
906 signal(SIGWINCH, columns_lines_cache_reset);
908 if (arg_action == ACTION_NEW_ID128) {
909 r = generate_new_id128();
913 if (arg_action == ACTION_SETUP_KEYS) {
918 if (arg_action == ACTION_LIST_CATALOG) {
919 r = catalog_list(stdout);
921 log_error("Failed to list catalog: %s", strerror(-r));
925 if (arg_action == ACTION_UPDATE_CATALOG) {
926 r = catalog_update();
935 r = sd_journal_open_directory(&j, arg_directory, 0);
937 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
939 log_error("Failed to open journal: %s", strerror(-r));
943 if (arg_action == ACTION_VERIFY) {
948 if (arg_action == ACTION_PRINT_HEADER) {
949 journal_print_header(j);
954 if (arg_action == ACTION_DISK_USAGE) {
956 char sbytes[FORMAT_BYTES_MAX];
958 r = sd_journal_get_usage(j, &bytes);
962 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
967 r = add_this_boot(j);
975 r = add_matches(j, argv + optind);
979 r = add_priorities(j);
983 /* Opening the fd now means the first sd_journal_wait() will actually wait */
984 r = sd_journal_get_fd(j);
992 r = sd_journal_query_unique(j, arg_field);
994 log_error("Failed to query unique data objects: %s", strerror(-r));
998 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1001 if (arg_lines >= 0 && n_shown >= arg_lines)
1004 eq = memchr(data, '=', size);
1006 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1008 printf("%.*s\n", (int) size, (const char*) data);
1018 r = sd_journal_seek_cursor(j, arg_cursor);
1020 log_error("Failed to seek to cursor: %s", strerror(-r));
1024 r = sd_journal_next(j);
1026 r = sd_journal_previous(j);
1028 } else if (arg_since_set && !arg_reverse) {
1029 r = sd_journal_seek_realtime_usec(j, arg_since);
1031 log_error("Failed to seek to date: %s", strerror(-r));
1034 r = sd_journal_next(j);
1036 } else if (arg_until_set && arg_reverse) {
1037 r = sd_journal_seek_realtime_usec(j, arg_until);
1039 log_error("Failed to seek to date: %s", strerror(-r));
1042 r = sd_journal_previous(j);
1044 } else if (arg_lines >= 0) {
1045 r = sd_journal_seek_tail(j);
1047 log_error("Failed to seek to tail: %s", strerror(-r));
1051 r = sd_journal_previous_skip(j, arg_lines);
1053 } else if (arg_reverse) {
1054 r = sd_journal_seek_tail(j);
1056 log_error("Failed to seek to tail: %s", strerror(-r));
1060 r = sd_journal_previous(j);
1063 r = sd_journal_seek_head(j);
1065 log_error("Failed to seek to head: %s", strerror(-r));
1069 r = sd_journal_next(j);
1073 log_error("Failed to iterate through journal: %s", strerror(-r));
1077 if (!arg_no_pager && !arg_follow)
1082 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1084 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1086 log_error("Failed to get cutoff: %s", strerror(-r));
1092 printf("-- Logs begin at %s. --\n",
1093 format_timestamp(start_buf, sizeof(start_buf), start));
1095 printf("-- Logs begin at %s, end at %s. --\n",
1096 format_timestamp(start_buf, sizeof(start_buf), start),
1097 format_timestamp(end_buf, sizeof(end_buf), end));
1102 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1107 r = sd_journal_next(j);
1109 r = sd_journal_previous(j);
1111 log_error("Failed to iterate through journal: %s", strerror(-r));
1119 if (arg_until_set && !arg_reverse) {
1122 r = sd_journal_get_realtime_usec(j, &usec);
1124 log_error("Failed to determine timestamp: %s", strerror(-r));
1127 if (usec > arg_until)
1131 if (arg_since_set && arg_reverse) {
1134 r = sd_journal_get_realtime_usec(j, &usec);
1136 log_error("Failed to determine timestamp: %s", strerror(-r));
1139 if (usec < arg_since)
1146 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1148 if (previous_boot_id_valid &&
1149 !sd_id128_equal(boot_id, previous_boot_id))
1150 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1152 previous_boot_id = boot_id;
1153 previous_boot_id_valid = true;
1158 arg_all * OUTPUT_SHOW_ALL |
1159 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1160 on_tty() * OUTPUT_COLOR |
1161 arg_catalog * OUTPUT_CATALOG;
1163 r = output_journal(stdout, j, arg_output, 0, flags);
1164 if (r < 0 || ferror(stdout))
1174 r = sd_journal_wait(j, (uint64_t) -1);
1176 log_error("Couldn't wait for journal event: %s", strerror(-r));
1185 sd_journal_close(j);
1189 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;