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_field
= NULL
;
79 static bool arg_catalog
= false;
90 } arg_action
= ACTION_SHOW
;
92 static int help(void) {
94 printf("%s [OPTIONS...] [MATCHES...]\n\n"
95 "Query the journal.\n\n"
97 " --since=DATE Start showing entries newer or of the specified date\n"
98 " --until=DATE Stop showing entries older or of the specified date\n"
99 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
100 " -b --this-boot Show data only from current boot\n"
101 " -u --unit=UNIT Show data only from the specified unit\n"
102 " -p --priority=RANGE Show only messages within the specified priority range\n"
103 " -f --follow Follow journal\n"
104 " -n --lines[=INTEGER] Number of journal entries to show\n"
105 " --no-tail Show all lines, even in follow mode\n"
106 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
107 " verbose, export, json, json-pretty, json-sse, cat)\n"
108 " -x --catalog Add message explanations where available\n"
109 " --full Do not ellipsize fields\n"
110 " -a --all Show all fields, including long and unprintable\n"
111 " -q --quiet Don't show privilege warning\n"
112 " --no-pager Do not pipe output into a pager\n"
113 " -m --merge Show entries from all available journals\n"
114 " -D --directory=PATH Show journal files from directory\n"
116 " --interval=TIME Time interval for changing the FSS sealing key\n"
117 " --verify-key=KEY Specify FSS verification key\n"
120 " -h --help Show this help\n"
121 " --version Show package version\n"
122 " --new-id128 Generate a new 128 Bit ID\n"
123 " --header Show journal header information\n"
124 " --disk-usage Show total disk usage\n"
125 " -F --field=FIELD List all values a certain field takes\n"
126 " --list-catalog Show message IDs of all entries in the message catalog\n"
127 " --update-catalog Update the message catalog database\n"
129 " --setup-keys Generate new FSS key pair\n"
130 " --verify Verify journal file consistency\n"
132 , program_invocation_short_name
);
137 static int parse_argv(int argc
, char *argv
[]) {
157 static const struct option options
[] = {
158 { "help", no_argument
, NULL
, 'h' },
159 { "version" , no_argument
, NULL
, ARG_VERSION
},
160 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
161 { "follow", no_argument
, NULL
, 'f' },
162 { "output", required_argument
, NULL
, 'o' },
163 { "all", no_argument
, NULL
, 'a' },
164 { "full", no_argument
, NULL
, ARG_FULL
},
165 { "lines", optional_argument
, NULL
, 'n' },
166 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
167 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
168 { "quiet", no_argument
, NULL
, 'q' },
169 { "merge", no_argument
, NULL
, 'm' },
170 { "this-boot", no_argument
, NULL
, 'b' },
171 { "directory", required_argument
, NULL
, 'D' },
172 { "header", no_argument
, NULL
, ARG_HEADER
},
173 { "priority", required_argument
, NULL
, 'p' },
174 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
175 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
176 { "verify", no_argument
, NULL
, ARG_VERIFY
},
177 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
178 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
179 { "cursor", required_argument
, NULL
, 'c' },
180 { "since", required_argument
, NULL
, ARG_SINCE
},
181 { "until", required_argument
, NULL
, ARG_UNTIL
},
182 { "unit", required_argument
, NULL
, 'u' },
183 { "field", required_argument
, NULL
, 'F' },
184 { "catalog", no_argument
, NULL
, 'x' },
185 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
186 { "update-catalog",no_argument
, NULL
, ARG_UPDATE_CATALOG
},
195 while ((c
= getopt_long(argc
, argv
, "hfo:an::qmbD:p:c:u:F:x", options
, NULL
)) >= 0) {
204 puts(PACKAGE_STRING
);
205 puts(SYSTEMD_FEATURES
);
217 arg_output
= output_mode_from_string(optarg
);
218 if (arg_output
< 0) {
219 log_error("Unknown output format '%s'.", optarg
);
223 if (arg_output
== OUTPUT_EXPORT
||
224 arg_output
== OUTPUT_JSON
||
225 arg_output
== OUTPUT_JSON_PRETTY
||
226 arg_output
== OUTPUT_JSON_SSE
||
227 arg_output
== OUTPUT_CAT
)
242 r
= safe_atoi(optarg
, &arg_lines
);
243 if (r
< 0 || arg_lines
< 0) {
244 log_error("Failed to parse lines '%s'", optarg
);
250 /* Hmm, no argument? Maybe the next
251 * word on the command line is
252 * supposed to be the argument? Let's
253 * see if there is one, and is
254 * parsable as a positive
258 safe_atoi(argv
[optind
], &n
) >= 0 &&
274 arg_action
= ACTION_NEW_ID128
;
286 arg_this_boot
= true;
290 arg_directory
= optarg
;
298 arg_action
= ACTION_PRINT_HEADER
;
302 arg_action
= ACTION_VERIFY
;
306 arg_action
= ACTION_DISK_USAGE
;
311 arg_action
= ACTION_SETUP_KEYS
;
316 arg_action
= ACTION_VERIFY
;
317 arg_verify_key
= optarg
;
322 r
= parse_usec(optarg
, &arg_interval
);
323 if (r
< 0 || arg_interval
<= 0) {
324 log_error("Failed to parse sealing key change interval: %s", optarg
);
332 log_error("Forward-secure sealing not available.");
339 dots
= strstr(optarg
, "..");
345 a
= strndup(optarg
, dots
- optarg
);
349 from
= log_level_from_string(a
);
350 to
= log_level_from_string(dots
+ 2);
353 if (from
< 0 || to
< 0) {
354 log_error("Failed to parse log level range %s", optarg
);
361 for (i
= from
; i
<= to
; i
++)
362 arg_priorities
|= 1 << i
;
364 for (i
= to
; i
<= from
; i
++)
365 arg_priorities
|= 1 << i
;
371 p
= log_level_from_string(optarg
);
373 log_error("Unknown log level %s", optarg
);
379 for (i
= 0; i
<= p
; i
++)
380 arg_priorities
|= 1 << i
;
387 r
= parse_timestamp(optarg
, &arg_since
);
389 log_error("Failed to parse timestamp: %s", optarg
);
392 arg_since_set
= true;
396 r
= parse_timestamp(optarg
, &arg_until
);
398 log_error("Failed to parse timestamp: %s", optarg
);
401 arg_until_set
= true;
419 case ARG_LIST_CATALOG
:
420 arg_action
= ACTION_LIST_CATALOG
;
423 case ARG_UPDATE_CATALOG
:
424 arg_action
= ACTION_UPDATE_CATALOG
;
428 log_error("Unknown option code %c", c
);
433 if (arg_follow
&& !arg_no_tail
&& arg_lines
< 0)
436 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
437 log_error("--since= must be before --until=.");
441 if (arg_cursor
&& arg_since_set
) {
442 log_error("Please specify either --since= or --cursor=, not both.");
449 static int generate_new_id128(void) {
454 r
= sd_id128_randomize(&id
);
456 log_error("Failed to generate ID: %s", strerror(-r
));
460 printf("As string:\n"
461 SD_ID128_FORMAT_STR
"\n\n"
463 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
465 "#define MESSAGE_XYZ SD_ID128_MAKE(",
466 SD_ID128_FORMAT_VAL(id
),
467 SD_ID128_FORMAT_VAL(id
));
469 for (i
= 0; i
< 16; i
++)
470 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
472 fputs(")\n", stdout
);
477 static int add_matches(sd_journal
*j
, char **args
) {
483 STRV_FOREACH(i
, args
) {
486 r
= sd_journal_add_disjunction(j
);
487 else if (path_is_absolute(*i
)) {
492 p
= canonicalize_file_name(*i
);
495 if (stat(path
, &st
) < 0) {
497 log_error("Couldn't stat file: %m");
501 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
))
502 t
= strappend("_EXE=", path
);
503 else if (S_ISCHR(st
.st_mode
))
504 asprintf(&t
, "_KERNEL_DEVICE=c%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
505 else if (S_ISBLK(st
.st_mode
))
506 asprintf(&t
, "_KERNEL_DEVICE=b%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
509 log_error("File is not a device node, regular file or is not executable: %s", *i
);
518 r
= sd_journal_add_match(j
, t
, 0);
521 r
= sd_journal_add_match(j
, *i
, 0);
524 log_error("Failed to add match '%s': %s", *i
, strerror(-r
));
532 static int add_this_boot(sd_journal
*j
) {
533 char match
[9+32+1] = "_BOOT_ID=";
542 r
= sd_id128_get_boot(&boot_id
);
544 log_error("Failed to get boot id: %s", strerror(-r
));
548 sd_id128_to_string(boot_id
, match
+ 9);
549 r
= sd_journal_add_match(j
, match
, strlen(match
));
551 log_error("Failed to add match: %s", strerror(-r
));
558 static int add_unit(sd_journal
*j
) {
559 _cleanup_free_
char *m
= NULL
, *u
= NULL
;
564 if (isempty(arg_unit
))
567 u
= unit_name_mangle(arg_unit
);
571 m
= strappend("_SYSTEMD_UNIT=", u
);
575 r
= sd_journal_add_match(j
, m
, strlen(m
));
577 log_error("Failed to add match: %s", strerror(-r
));
584 static int add_priorities(sd_journal
*j
) {
585 char match
[] = "PRIORITY=0";
590 if (arg_priorities
== 0xFF)
593 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
594 if (arg_priorities
& (1 << i
)) {
595 match
[sizeof(match
)-2] = '0' + i
;
597 r
= sd_journal_add_match(j
, match
, strlen(match
));
599 log_error("Failed to add match: %s", strerror(-r
));
607 static int setup_keys(void) {
609 size_t mpk_size
, seed_size
, state_size
, i
;
610 uint8_t *mpk
, *seed
, *state
;
612 int fd
= -1, r
, attr
= 0;
613 sd_id128_t machine
, boot
;
614 char *p
= NULL
, *k
= NULL
;
618 r
= sd_id128_get_machine(&machine
);
620 log_error("Failed to get machine ID: %s", strerror(-r
));
624 r
= sd_id128_get_boot(&boot
);
626 log_error("Failed to get boot ID: %s", strerror(-r
));
630 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
631 SD_ID128_FORMAT_VAL(machine
)) < 0)
634 if (access(p
, F_OK
) >= 0) {
635 log_error("Sealing key file %s exists already.", p
);
640 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
641 SD_ID128_FORMAT_VAL(machine
)) < 0) {
646 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
647 mpk
= alloca(mpk_size
);
649 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
650 seed
= alloca(seed_size
);
652 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
653 state
= alloca(state_size
);
655 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
657 log_error("Failed to open /dev/random: %m");
662 log_info("Generating seed...");
663 l
= loop_read(fd
, seed
, seed_size
, true);
664 if (l
< 0 || (size_t) l
!= seed_size
) {
665 log_error("Failed to read random seed: %s", strerror(EIO
));
670 log_info("Generating key pair...");
671 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
673 log_info("Generating sealing key...");
674 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
676 assert(arg_interval
> 0);
678 n
= now(CLOCK_REALTIME
);
681 close_nointr_nofail(fd
);
682 fd
= mkostemp(k
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
684 log_error("Failed to open %s: %m", k
);
689 /* Enable secure remove, exclusion from dump, synchronous
690 * writing and in-place updating */
691 if (ioctl(fd
, FS_IOC_GETFLAGS
, &attr
) < 0)
692 log_warning("FS_IOC_GETFLAGS failed: %m");
694 attr
|= FS_SECRM_FL
|FS_NODUMP_FL
|FS_SYNC_FL
|FS_NOCOW_FL
;
696 if (ioctl(fd
, FS_IOC_SETFLAGS
, &attr
) < 0)
697 log_warning("FS_IOC_SETFLAGS failed: %m");
700 memcpy(h
.signature
, "KSHHRHLP", 8);
701 h
.machine_id
= machine
;
703 h
.header_size
= htole64(sizeof(h
));
704 h
.start_usec
= htole64(n
* arg_interval
);
705 h
.interval_usec
= htole64(arg_interval
);
706 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
707 h
.fsprg_state_size
= htole64(state_size
);
709 l
= loop_write(fd
, &h
, sizeof(h
), false);
710 if (l
< 0 || (size_t) l
!= sizeof(h
)) {
711 log_error("Failed to write header: %s", strerror(EIO
));
716 l
= loop_write(fd
, state
, state_size
, false);
717 if (l
< 0 || (size_t) l
!= state_size
) {
718 log_error("Failed to write state: %s", strerror(EIO
));
723 if (link(k
, p
) < 0) {
724 log_error("Failed to link file: %m");
732 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON
"secret sealing key" ANSI_HIGHLIGHT_OFF
" has been written to\n"
733 "the following local file. This key file is automatically updated when the\n"
734 "sealing key is advanced. It should not be used on multiple hosts.\n"
738 "Please write down the following " ANSI_HIGHLIGHT_ON
"secret verification key" ANSI_HIGHLIGHT_OFF
". It should be stored\n"
739 "at a safe location and should not be saved locally on disk.\n"
740 "\n\t" ANSI_HIGHLIGHT_RED_ON
, p
);
743 for (i
= 0; i
< seed_size
; i
++) {
744 if (i
> 0 && i
% 3 == 0)
746 printf("%02x", ((uint8_t*) seed
)[i
]);
749 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
752 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
755 ANSI_HIGHLIGHT_OFF
"\n"
756 "The sealing key is automatically changed every %s.\n",
757 format_timespan(tsb
, sizeof(tsb
), arg_interval
));
759 hn
= gethostname_malloc();
762 hostname_cleanup(hn
);
763 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
765 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
768 /* If this is not an UTF-8 system don't print any QR codes */
769 if (is_locale_utf8()) {
770 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
771 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
781 close_nointr_nofail(fd
);
792 log_error("Forward-secure sealing not available.");
797 static int verify(sd_journal
*j
) {
804 log_show_color(true);
806 HASHMAP_FOREACH(f
, j
->files
, i
) {
808 usec_t first
, validated
, last
;
811 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
812 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
815 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
817 /* If the key was invalid give up right-away. */
820 log_warning("FAIL: %s (%s)", f
->path
, strerror(-k
));
823 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
824 log_info("PASS: %s", f
->path
);
826 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
828 log_info("=> Validated from %s to %s, final %s entries not sealed.",
829 format_timestamp(a
, sizeof(a
), first
),
830 format_timestamp(b
, sizeof(b
), validated
),
831 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0));
833 log_info("=> No sealing yet, %s of entries not sealed.",
834 format_timespan(c
, sizeof(c
), last
- first
));
836 log_info("=> No sealing yet, no entries in file.");
844 static int access_check(void) {
847 if (access("/var/log/journal", F_OK
) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
848 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
852 if (!arg_quiet
&& geteuid() != 0 && in_group("adm") <= 0)
853 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
855 if (geteuid() != 0 && in_group("adm") <= 0) {
856 log_error("No access to messages. Only users in the group 'adm' can see messages.");
864 int main(int argc
, char *argv
[]) {
866 sd_journal
*j
= NULL
;
867 bool need_seek
= false;
868 sd_id128_t previous_boot_id
;
869 bool previous_boot_id_valid
= false, first_line
= true;
872 setlocale(LC_ALL
, "");
873 log_parse_environment();
876 r
= parse_argv(argc
, argv
);
880 signal(SIGWINCH
, columns_lines_cache_reset
);
882 if (arg_action
== ACTION_NEW_ID128
) {
883 r
= generate_new_id128();
887 if (arg_action
== ACTION_SETUP_KEYS
) {
892 if (arg_action
== ACTION_LIST_CATALOG
) {
893 r
= catalog_list(stdout
);
895 log_error("Failed to list catalog: %s", strerror(-r
));
899 if (arg_action
== ACTION_UPDATE_CATALOG
) {
900 r
= catalog_update();
909 r
= sd_journal_open_directory(&j
, arg_directory
, 0);
911 r
= sd_journal_open(&j
, arg_merge
? 0 : SD_JOURNAL_LOCAL_ONLY
);
913 log_error("Failed to open journal: %s", strerror(-r
));
917 if (arg_action
== ACTION_VERIFY
) {
922 if (arg_action
== ACTION_PRINT_HEADER
) {
923 journal_print_header(j
);
928 if (arg_action
== ACTION_DISK_USAGE
) {
930 char sbytes
[FORMAT_BYTES_MAX
];
932 r
= sd_journal_get_usage(j
, &bytes
);
936 printf("Journals take up %s on disk.\n", format_bytes(sbytes
, sizeof(sbytes
), bytes
));
941 r
= add_this_boot(j
);
949 r
= add_matches(j
, argv
+ optind
);
953 r
= add_priorities(j
);
957 /* Opening the fd now means the first sd_journal_wait() will actually wait */
958 r
= sd_journal_get_fd(j
);
966 r
= sd_journal_query_unique(j
, arg_field
);
968 log_error("Failed to query unique data objects: %s", strerror(-r
));
972 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
975 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
978 eq
= memchr(data
, '=', size
);
980 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
982 printf("%.*s\n", (int) size
, (const char*) data
);
992 r
= sd_journal_seek_cursor(j
, arg_cursor
);
994 log_error("Failed to seek to cursor: %s", strerror(-r
));
998 r
= sd_journal_next(j
);
1000 } else if (arg_since_set
) {
1001 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
1003 log_error("Failed to seek to date: %s", strerror(-r
));
1006 r
= sd_journal_next(j
);
1008 } else if (arg_lines
>= 0) {
1009 r
= sd_journal_seek_tail(j
);
1011 log_error("Failed to seek to tail: %s", strerror(-r
));
1015 r
= sd_journal_previous_skip(j
, arg_lines
);
1018 r
= sd_journal_seek_head(j
);
1020 log_error("Failed to seek to head: %s", strerror(-r
));
1024 r
= sd_journal_next(j
);
1028 log_error("Failed to iterate through journal: %s", strerror(-r
));
1032 if (!arg_no_pager
&& !arg_follow
)
1037 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
1039 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
1041 log_error("Failed to get cutoff: %s", strerror(-r
));
1047 printf("-- Logs begin at %s. --\n",
1048 format_timestamp(start_buf
, sizeof(start_buf
), start
));
1050 printf("-- Logs begin at %s, end at %s. --\n",
1051 format_timestamp(start_buf
, sizeof(start_buf
), start
),
1052 format_timestamp(end_buf
, sizeof(end_buf
), end
));
1057 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
1061 r
= sd_journal_next(j
);
1063 log_error("Failed to iterate through journal: %s", strerror(-r
));
1071 if (arg_until_set
) {
1074 r
= sd_journal_get_realtime_usec(j
, &usec
);
1076 log_error("Failed to determine timestamp: %s", strerror(-r
));
1079 if (usec
> arg_until
)
1086 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1088 if (previous_boot_id_valid
&&
1089 !sd_id128_equal(boot_id
, previous_boot_id
))
1090 printf(ANSI_HIGHLIGHT_ON
"-- Reboot --" ANSI_HIGHLIGHT_OFF
"\n");
1092 previous_boot_id
= boot_id
;
1093 previous_boot_id_valid
= true;
1098 arg_all
* OUTPUT_SHOW_ALL
|
1099 (arg_full
|| !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
1100 on_tty() * OUTPUT_COLOR
|
1101 arg_catalog
* OUTPUT_CATALOG
;
1103 r
= output_journal(stdout
, j
, arg_output
, 0, flags
);
1104 if (r
< 0 || ferror(stdout
))
1114 r
= sd_journal_wait(j
, (uint64_t) -1);
1116 log_error("Couldn't wait for journal event: %s", strerror(-r
));
1125 sd_journal_close(j
);
1129 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;