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_pager_end = false;
60 static bool arg_follow = false;
61 static bool arg_full = false;
62 static bool arg_all = false;
63 static bool arg_no_pager = false;
64 static int arg_lines = -1;
65 static bool arg_no_tail = false;
66 static bool arg_quiet = false;
67 static bool arg_merge = false;
68 static bool arg_this_boot = false;
69 static const char *arg_cursor = NULL;
70 static const char *arg_directory = NULL;
71 static int arg_priorities = 0xFF;
72 static const char *arg_verify_key = NULL;
74 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
76 static usec_t arg_since, arg_until;
77 static bool arg_since_set = false, arg_until_set = false;
78 static const char *arg_unit = NULL;
79 static const char *arg_unit_type = NULL;
80 static const char *arg_field = NULL;
81 static bool arg_catalog = false;
82 static bool arg_reverse = false;
93 } arg_action = ACTION_SHOW;
95 static int help(void) {
97 printf("%s [OPTIONS...] [MATCHES...]\n\n"
98 "Query the journal.\n\n"
100 " --since=DATE Start showing entries newer or of the specified date\n"
101 " --until=DATE Stop showing entries older or of the specified date\n"
102 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
103 " -b --this-boot Show data only from current boot\n"
104 " -u --unit=UNIT Show data only from the specified unit\n"
105 " --user-unit=UNIT Show data only from the specified user session unit\n"
106 " -p --priority=RANGE Show only messages within the specified priority range\n"
107 " -e --pager-end Immediately jump to end of the journal in the pager\n"
108 " -f --follow Follow journal\n"
109 " -n --lines[=INTEGER] Number of journal entries to show\n"
110 " --no-tail Show all lines, even in follow mode\n"
111 " -r --reverse Show the newest entries first\n"
112 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
113 " verbose, export, json, json-pretty, json-sse, cat)\n"
114 " -x --catalog Add message explanations where available\n"
115 " --full Do not ellipsize fields\n"
116 " -a --all Show all fields, including long and unprintable\n"
117 " -q --quiet Don't show privilege warning\n"
118 " --no-pager Do not pipe output into a pager\n"
119 " -m --merge Show entries from all available journals\n"
120 " -D --directory=PATH Show journal files from directory\n"
122 " --interval=TIME Time interval for changing the FSS sealing key\n"
123 " --verify-key=KEY Specify FSS verification key\n"
126 " -h --help Show this help\n"
127 " --version Show package version\n"
128 " --new-id128 Generate a new 128 Bit ID\n"
129 " --header Show journal header information\n"
130 " --disk-usage Show total disk usage\n"
131 " -F --field=FIELD List all values a certain field takes\n"
132 " --list-catalog Show message IDs of all entries in the message catalog\n"
133 " --update-catalog Update the message catalog database\n"
135 " --setup-keys Generate new FSS key pair\n"
136 " --verify Verify journal file consistency\n"
138 , program_invocation_short_name);
143 static int parse_argv(int argc, char *argv[]) {
164 static const struct option options[] = {
165 { "help", no_argument, NULL, 'h' },
166 { "version" , no_argument, NULL, ARG_VERSION },
167 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
168 { "pager-end", no_argument, NULL, 'e' },
169 { "follow", no_argument, NULL, 'f' },
170 { "output", required_argument, NULL, 'o' },
171 { "all", no_argument, NULL, 'a' },
172 { "full", no_argument, NULL, ARG_FULL },
173 { "lines", optional_argument, NULL, 'n' },
174 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
175 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
176 { "quiet", no_argument, NULL, 'q' },
177 { "merge", no_argument, NULL, 'm' },
178 { "this-boot", no_argument, NULL, 'b' },
179 { "directory", required_argument, NULL, 'D' },
180 { "header", no_argument, NULL, ARG_HEADER },
181 { "priority", required_argument, NULL, 'p' },
182 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
183 { "interval", required_argument, NULL, ARG_INTERVAL },
184 { "verify", no_argument, NULL, ARG_VERIFY },
185 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
186 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
187 { "cursor", required_argument, NULL, 'c' },
188 { "since", required_argument, NULL, ARG_SINCE },
189 { "until", required_argument, NULL, ARG_UNTIL },
190 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
191 { "unit", required_argument, NULL, 'u' },
192 { "field", required_argument, NULL, 'F' },
193 { "catalog", no_argument, NULL, 'x' },
194 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
195 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
196 { "reverse", no_argument, NULL, 'r' },
205 while ((c = getopt_long(argc, argv, "hefo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) {
214 puts(PACKAGE_STRING);
215 puts(SYSTEMD_FEATURES);
223 arg_pager_end = true;
231 arg_output = output_mode_from_string(optarg);
232 if (arg_output < 0) {
233 log_error("Unknown output format '%s'.", optarg);
237 if (arg_output == OUTPUT_EXPORT ||
238 arg_output == OUTPUT_JSON ||
239 arg_output == OUTPUT_JSON_PRETTY ||
240 arg_output == OUTPUT_JSON_SSE ||
241 arg_output == OUTPUT_CAT)
256 r = safe_atoi(optarg, &arg_lines);
257 if (r < 0 || arg_lines < 0) {
258 log_error("Failed to parse lines '%s'", optarg);
264 /* Hmm, no argument? Maybe the next
265 * word on the command line is
266 * supposed to be the argument? Let's
267 * see if there is one, and is
268 * parsable as a positive
272 safe_atoi(argv[optind], &n) >= 0 &&
288 arg_action = ACTION_NEW_ID128;
300 arg_this_boot = true;
304 arg_directory = optarg;
312 arg_action = ACTION_PRINT_HEADER;
316 arg_action = ACTION_VERIFY;
320 arg_action = ACTION_DISK_USAGE;
325 arg_action = ACTION_SETUP_KEYS;
330 arg_action = ACTION_VERIFY;
331 arg_verify_key = optarg;
336 r = parse_usec(optarg, &arg_interval);
337 if (r < 0 || arg_interval <= 0) {
338 log_error("Failed to parse sealing key change interval: %s", optarg);
346 log_error("Forward-secure sealing not available.");
353 dots = strstr(optarg, "..");
359 a = strndup(optarg, dots - optarg);
363 from = log_level_from_string(a);
364 to = log_level_from_string(dots + 2);
367 if (from < 0 || to < 0) {
368 log_error("Failed to parse log level range %s", optarg);
375 for (i = from; i <= to; i++)
376 arg_priorities |= 1 << i;
378 for (i = to; i <= from; i++)
379 arg_priorities |= 1 << i;
385 p = log_level_from_string(optarg);
387 log_error("Unknown log level %s", optarg);
393 for (i = 0; i <= p; i++)
394 arg_priorities |= 1 << i;
401 r = parse_timestamp(optarg, &arg_since);
403 log_error("Failed to parse timestamp: %s", optarg);
406 arg_since_set = true;
410 r = parse_timestamp(optarg, &arg_until);
412 log_error("Failed to parse timestamp: %s", optarg);
415 arg_until_set = true;
420 arg_unit_type = "_SYSTEMD_USER_UNIT=";
425 arg_unit_type = "_SYSTEMD_UNIT=";
439 case ARG_LIST_CATALOG:
440 arg_action = ACTION_LIST_CATALOG;
443 case ARG_UPDATE_CATALOG:
444 arg_action = ACTION_UPDATE_CATALOG;
452 log_error("Unknown option code %c", c);
457 if (arg_follow && !arg_no_tail && arg_lines < 0)
460 if (arg_since_set && arg_until_set && arg_since > arg_until) {
461 log_error("--since= must be before --until=.");
465 if (arg_cursor && arg_since_set) {
466 log_error("Please specify either --since= or --cursor=, not both.");
470 if (arg_follow && arg_reverse) {
471 log_error("Please specify either --reverse= or --follow=, not both.");
478 static int generate_new_id128(void) {
483 r = sd_id128_randomize(&id);
485 log_error("Failed to generate ID: %s", strerror(-r));
489 printf("As string:\n"
490 SD_ID128_FORMAT_STR "\n\n"
492 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
494 "#define MESSAGE_XYZ SD_ID128_MAKE(",
495 SD_ID128_FORMAT_VAL(id),
496 SD_ID128_FORMAT_VAL(id));
497 for (i = 0; i < 16; i++)
498 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
499 fputs(")\n\n", stdout);
501 printf("As Python constant:\n"
503 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
504 SD_ID128_FORMAT_VAL(id));
509 static int add_matches(sd_journal *j, char **args) {
515 STRV_FOREACH(i, args) {
518 r = sd_journal_add_disjunction(j);
519 else if (path_is_absolute(*i)) {
524 p = canonicalize_file_name(*i);
527 if (stat(path, &st) < 0) {
529 log_error("Couldn't stat file: %m");
533 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
534 t = strappend("_EXE=", path);
535 else if (S_ISCHR(st.st_mode))
536 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
537 else if (S_ISBLK(st.st_mode))
538 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
541 log_error("File is not a device node, regular file or is not executable: %s", *i);
550 r = sd_journal_add_match(j, t, 0);
553 r = sd_journal_add_match(j, *i, 0);
556 log_error("Failed to add match '%s': %s", *i, strerror(-r));
564 static int add_this_boot(sd_journal *j) {
565 char match[9+32+1] = "_BOOT_ID=";
574 r = sd_id128_get_boot(&boot_id);
576 log_error("Failed to get boot id: %s", strerror(-r));
580 sd_id128_to_string(boot_id, match + 9);
581 r = sd_journal_add_match(j, match, strlen(match));
583 log_error("Failed to add match: %s", strerror(-r));
590 static int add_unit(sd_journal *j) {
591 _cleanup_free_ char *m = NULL, *u = NULL;
596 if (isempty(arg_unit))
599 u = unit_name_mangle(arg_unit);
603 m = strappend(arg_unit_type, u);
608 r = sd_journal_add_match(j, m, strlen(m));
610 log_error("Failed to add match: %s", strerror(-r));
617 static int add_priorities(sd_journal *j) {
618 char match[] = "PRIORITY=0";
623 if (arg_priorities == 0xFF)
626 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
627 if (arg_priorities & (1 << i)) {
628 match[sizeof(match)-2] = '0' + i;
630 r = sd_journal_add_match(j, match, strlen(match));
632 log_error("Failed to add match: %s", strerror(-r));
640 static int setup_keys(void) {
642 size_t mpk_size, seed_size, state_size, i;
643 uint8_t *mpk, *seed, *state;
645 int fd = -1, r, attr = 0;
646 sd_id128_t machine, boot;
647 char *p = NULL, *k = NULL;
651 r = sd_id128_get_machine(&machine);
653 log_error("Failed to get machine ID: %s", strerror(-r));
657 r = sd_id128_get_boot(&boot);
659 log_error("Failed to get boot ID: %s", strerror(-r));
663 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
664 SD_ID128_FORMAT_VAL(machine)) < 0)
667 if (access(p, F_OK) >= 0) {
668 log_error("Sealing key file %s exists already.", p);
673 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
674 SD_ID128_FORMAT_VAL(machine)) < 0) {
679 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
680 mpk = alloca(mpk_size);
682 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
683 seed = alloca(seed_size);
685 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
686 state = alloca(state_size);
688 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
690 log_error("Failed to open /dev/random: %m");
695 log_info("Generating seed...");
696 l = loop_read(fd, seed, seed_size, true);
697 if (l < 0 || (size_t) l != seed_size) {
698 log_error("Failed to read random seed: %s", strerror(EIO));
703 log_info("Generating key pair...");
704 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
706 log_info("Generating sealing key...");
707 FSPRG_GenState0(state, mpk, seed, seed_size);
709 assert(arg_interval > 0);
711 n = now(CLOCK_REALTIME);
714 close_nointr_nofail(fd);
715 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
717 log_error("Failed to open %s: %m", k);
722 /* Enable secure remove, exclusion from dump, synchronous
723 * writing and in-place updating */
724 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
725 log_warning("FS_IOC_GETFLAGS failed: %m");
727 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
729 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
730 log_warning("FS_IOC_SETFLAGS failed: %m");
733 memcpy(h.signature, "KSHHRHLP", 8);
734 h.machine_id = machine;
736 h.header_size = htole64(sizeof(h));
737 h.start_usec = htole64(n * arg_interval);
738 h.interval_usec = htole64(arg_interval);
739 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
740 h.fsprg_state_size = htole64(state_size);
742 l = loop_write(fd, &h, sizeof(h), false);
743 if (l < 0 || (size_t) l != sizeof(h)) {
744 log_error("Failed to write header: %s", strerror(EIO));
749 l = loop_write(fd, state, state_size, false);
750 if (l < 0 || (size_t) l != state_size) {
751 log_error("Failed to write state: %s", strerror(EIO));
756 if (link(k, p) < 0) {
757 log_error("Failed to link file: %m");
765 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
766 "the following local file. This key file is automatically updated when the\n"
767 "sealing key is advanced. It should not be used on multiple hosts.\n"
771 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
772 "at a safe location and should not be saved locally on disk.\n"
773 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
776 for (i = 0; i < seed_size; i++) {
777 if (i > 0 && i % 3 == 0)
779 printf("%02x", ((uint8_t*) seed)[i]);
782 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
785 char tsb[FORMAT_TIMESPAN_MAX], *hn;
788 ANSI_HIGHLIGHT_OFF "\n"
789 "The sealing key is automatically changed every %s.\n",
790 format_timespan(tsb, sizeof(tsb), arg_interval));
792 hn = gethostname_malloc();
795 hostname_cleanup(hn);
796 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
798 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
801 /* If this is not an UTF-8 system don't print any QR codes */
802 if (is_locale_utf8()) {
803 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
804 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
814 close_nointr_nofail(fd);
825 log_error("Forward-secure sealing not available.");
830 static int verify(sd_journal *j) {
837 log_show_color(true);
839 HASHMAP_FOREACH(f, j->files, i) {
841 usec_t first, validated, last;
844 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
845 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
848 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
850 /* If the key was invalid give up right-away. */
853 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
856 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
857 log_info("PASS: %s", f->path);
859 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
861 log_info("=> Validated from %s to %s, final %s entries not sealed.",
862 format_timestamp(a, sizeof(a), first),
863 format_timestamp(b, sizeof(b), validated),
864 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
866 log_info("=> No sealing yet, %s of entries not sealed.",
867 format_timespan(c, sizeof(c), last - first));
869 log_info("=> No sealing yet, no entries in file.");
877 static int access_check(void) {
880 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("systemd-journal") <= 0) {
881 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages.");
885 if (!arg_quiet && geteuid() != 0 && in_group("systemd-journal") <= 0)
886 log_warning("Showing user generated messages only. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off.");
888 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
889 log_error("No access to messages. Only users in the group 'systemd-journal' can see messages.");
897 int main(int argc, char *argv[]) {
899 sd_journal *j = NULL;
900 bool need_seek = false;
901 sd_id128_t previous_boot_id;
902 bool previous_boot_id_valid = false, first_line = true;
905 setlocale(LC_ALL, "");
906 log_parse_environment();
909 r = parse_argv(argc, argv);
913 signal(SIGWINCH, columns_lines_cache_reset);
915 if (arg_action == ACTION_NEW_ID128) {
916 r = generate_new_id128();
920 if (arg_action == ACTION_SETUP_KEYS) {
925 if (arg_action == ACTION_LIST_CATALOG) {
926 r = catalog_list(stdout);
928 log_error("Failed to list catalog: %s", strerror(-r));
932 if (arg_action == ACTION_UPDATE_CATALOG) {
933 r = catalog_update();
942 r = sd_journal_open_directory(&j, arg_directory, 0);
944 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
946 log_error("Failed to open journal: %s", strerror(-r));
950 if (arg_action == ACTION_VERIFY) {
955 if (arg_action == ACTION_PRINT_HEADER) {
956 journal_print_header(j);
961 if (arg_action == ACTION_DISK_USAGE) {
963 char sbytes[FORMAT_BYTES_MAX];
965 r = sd_journal_get_usage(j, &bytes);
969 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
974 r = add_this_boot(j);
982 r = add_matches(j, argv + optind);
986 r = add_priorities(j);
990 /* Opening the fd now means the first sd_journal_wait() will actually wait */
991 r = sd_journal_get_fd(j);
999 r = sd_journal_query_unique(j, arg_field);
1001 log_error("Failed to query unique data objects: %s", strerror(-r));
1005 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1008 if (arg_lines >= 0 && n_shown >= arg_lines)
1011 eq = memchr(data, '=', size);
1013 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1015 printf("%.*s\n", (int) size, (const char*) data);
1025 r = sd_journal_seek_cursor(j, arg_cursor);
1027 log_error("Failed to seek to cursor: %s", strerror(-r));
1031 r = sd_journal_next(j);
1033 r = sd_journal_previous(j);
1035 } else if (arg_since_set && !arg_reverse) {
1036 r = sd_journal_seek_realtime_usec(j, arg_since);
1038 log_error("Failed to seek to date: %s", strerror(-r));
1041 r = sd_journal_next(j);
1043 } else if (arg_until_set && arg_reverse) {
1044 r = sd_journal_seek_realtime_usec(j, arg_until);
1046 log_error("Failed to seek to date: %s", strerror(-r));
1049 r = sd_journal_previous(j);
1051 } else if (arg_lines >= 0) {
1052 r = sd_journal_seek_tail(j);
1054 log_error("Failed to seek to tail: %s", strerror(-r));
1058 r = sd_journal_previous_skip(j, arg_lines);
1060 } else if (arg_reverse) {
1061 r = sd_journal_seek_tail(j);
1063 log_error("Failed to seek to tail: %s", strerror(-r));
1067 r = sd_journal_previous(j);
1070 r = sd_journal_seek_head(j);
1072 log_error("Failed to seek to head: %s", strerror(-r));
1076 r = sd_journal_next(j);
1080 log_error("Failed to iterate through journal: %s", strerror(-r));
1084 if (!arg_no_pager && !arg_follow)
1085 pager_open(arg_pager_end);
1089 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1091 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1093 log_error("Failed to get cutoff: %s", strerror(-r));
1099 printf("-- Logs begin at %s. --\n",
1100 format_timestamp(start_buf, sizeof(start_buf), start));
1102 printf("-- Logs begin at %s, end at %s. --\n",
1103 format_timestamp(start_buf, sizeof(start_buf), start),
1104 format_timestamp(end_buf, sizeof(end_buf), end));
1109 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1114 r = sd_journal_next(j);
1116 r = sd_journal_previous(j);
1118 log_error("Failed to iterate through journal: %s", strerror(-r));
1126 if (arg_until_set && !arg_reverse) {
1129 r = sd_journal_get_realtime_usec(j, &usec);
1131 log_error("Failed to determine timestamp: %s", strerror(-r));
1134 if (usec > arg_until)
1138 if (arg_since_set && arg_reverse) {
1141 r = sd_journal_get_realtime_usec(j, &usec);
1143 log_error("Failed to determine timestamp: %s", strerror(-r));
1146 if (usec < arg_since)
1153 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1155 if (previous_boot_id_valid &&
1156 !sd_id128_equal(boot_id, previous_boot_id))
1157 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1159 previous_boot_id = boot_id;
1160 previous_boot_id_valid = true;
1165 arg_all * OUTPUT_SHOW_ALL |
1166 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1167 on_tty() * OUTPUT_COLOR |
1168 arg_catalog * OUTPUT_CATALOG;
1170 r = output_journal(stdout, j, arg_output, 0, flags);
1171 if (r < 0 || ferror(stdout))
1181 r = sd_journal_wait(j, (uint64_t) -1);
1183 log_error("Couldn't wait for journal event: %s", strerror(-r));
1192 sd_journal_close(j);
1196 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;