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/inotify.h>
39 #include "sd-journal.h"
42 #include "bus-error.h"
47 #include "hostname-util.h"
48 #include "journal-def.h"
49 #include "journal-internal.h"
50 #include "journal-qrcode.h"
51 #include "journal-vacuum.h"
52 #include "journal-verify.h"
54 #include "logs-show.h"
57 #include "path-util.h"
61 #include "terminal-util.h"
62 #include "unit-name.h"
64 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
67 /* Special values for arg_lines */
68 ARG_LINES_DEFAULT
= -2,
72 static OutputMode arg_output
= OUTPUT_SHORT
;
73 static bool arg_utc
= false;
74 static bool arg_pager_end
= false;
75 static bool arg_follow
= false;
76 static bool arg_full
= true;
77 static bool arg_all
= false;
78 static bool arg_no_pager
= false;
79 static int arg_lines
= ARG_LINES_DEFAULT
;
80 static bool arg_no_tail
= false;
81 static bool arg_quiet
= false;
82 static bool arg_merge
= false;
83 static bool arg_boot
= false;
84 static sd_id128_t arg_boot_id
= {};
85 static int arg_boot_offset
= 0;
86 static bool arg_dmesg
= false;
87 static const char *arg_cursor
= NULL
;
88 static const char *arg_after_cursor
= NULL
;
89 static bool arg_show_cursor
= false;
90 static const char *arg_directory
= NULL
;
91 static char **arg_file
= NULL
;
92 static int arg_priorities
= 0xFF;
93 static const char *arg_verify_key
= NULL
;
95 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
96 static bool arg_force
= false;
98 static usec_t arg_since
, arg_until
;
99 static bool arg_since_set
= false, arg_until_set
= false;
100 static char **arg_syslog_identifier
= NULL
;
101 static char **arg_system_units
= NULL
;
102 static char **arg_user_units
= NULL
;
103 static const char *arg_field
= NULL
;
104 static bool arg_catalog
= false;
105 static bool arg_reverse
= false;
106 static int arg_journal_type
= 0;
107 static const char *arg_root
= NULL
;
108 static const char *arg_machine
= NULL
;
109 static uint64_t arg_vacuum_size
= (uint64_t) -1;
110 static usec_t arg_vacuum_time
= USEC_INFINITY
;
121 ACTION_UPDATE_CATALOG
,
125 } arg_action
= ACTION_SHOW
;
127 typedef struct BootId
{
131 LIST_FIELDS(struct BootId
, boot_list
);
134 static void pager_open_if_enabled(void) {
139 pager_open(arg_pager_end
);
142 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
145 return format_timestamp_utc(buf
, l
, t
);
147 return format_timestamp(buf
, l
, t
);
150 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
151 sd_id128_t id
= SD_ID128_NULL
;
154 if (strlen(x
) >= 32) {
158 r
= sd_id128_from_string(t
, &id
);
162 if (*x
!= '-' && *x
!= '+' && *x
!= 0)
166 r
= safe_atoi(x
, &off
);
171 r
= safe_atoi(x
, &off
);
185 static void help(void) {
187 pager_open_if_enabled();
189 printf("%s [OPTIONS...] [MATCHES...]\n\n"
190 "Query the journal.\n\n"
192 " --system Show the system journal\n"
193 " --user Show the user journal for the current user\n"
194 " -M --machine=CONTAINER Operate on local container\n"
195 " --since=DATE Show entries not older than the specified date\n"
196 " --until=DATE Show entries not newer than the specified date\n"
197 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
198 " --after-cursor=CURSOR Show entries after the specified cursor\n"
199 " --show-cursor Print the cursor after all the entries\n"
200 " -b --boot[=ID] Show current boot or the specified boot\n"
201 " --list-boots Show terse information about recorded boots\n"
202 " -k --dmesg Show kernel message log from the current boot\n"
203 " -u --unit=UNIT Show logs from the specified unit\n"
204 " --user-unit=UNIT Show logs from the specified user unit\n"
205 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
206 " -p --priority=RANGE Show entries with the specified priority\n"
207 " -e --pager-end Immediately jump to the end in the pager\n"
208 " -f --follow Follow the journal\n"
209 " -n --lines[=INTEGER] Number of journal entries to show\n"
210 " --no-tail Show all lines, even in follow mode\n"
211 " -r --reverse Show the newest entries first\n"
212 " -o --output=STRING Change journal output mode (short, short-iso,\n"
213 " short-precise, short-monotonic, verbose,\n"
214 " export, json, json-pretty, json-sse, cat)\n"
215 " --utc Express time in Coordinated Universal Time (UTC)\n"
216 " -x --catalog Add message explanations where available\n"
217 " --no-full Ellipsize fields\n"
218 " -a --all Show all fields, including long and unprintable\n"
219 " -q --quiet Do not show privilege warning\n"
220 " --no-pager Do not pipe output into a pager\n"
221 " -m --merge Show entries from all available journals\n"
222 " -D --directory=PATH Show journal files from directory\n"
223 " --file=PATH Show journal file\n"
224 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
226 " --interval=TIME Time interval for changing the FSS sealing key\n"
227 " --verify-key=KEY Specify FSS verification key\n"
228 " --force Override of the FSS key pair with --setup-keys\n"
231 " -h --help Show this help text\n"
232 " --version Show package version\n"
233 " -F --field=FIELD List all values that a specified field takes\n"
234 " --new-id128 Generate a new 128-bit ID\n"
235 " --disk-usage Show total disk usage of all journal files\n"
236 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
237 " --vacuum-time=TIME Remove journal files older than specified date\n"
238 " --flush Flush all journal data from /run into /var\n"
239 " --header Show journal header information\n"
240 " --list-catalog Show all message IDs in the catalog\n"
241 " --dump-catalog Show entries in the message catalog\n"
242 " --update-catalog Update the message catalog database\n"
244 " --setup-keys Generate a new FSS key pair\n"
245 " --verify Verify journal file consistency\n"
247 , program_invocation_short_name
);
250 static int parse_argv(int argc
, char *argv
[]) {
284 static const struct option options
[] = {
285 { "help", no_argument
, NULL
, 'h' },
286 { "version" , no_argument
, NULL
, ARG_VERSION
},
287 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
288 { "pager-end", no_argument
, NULL
, 'e' },
289 { "follow", no_argument
, NULL
, 'f' },
290 { "force", no_argument
, NULL
, ARG_FORCE
},
291 { "output", required_argument
, NULL
, 'o' },
292 { "all", no_argument
, NULL
, 'a' },
293 { "full", no_argument
, NULL
, 'l' },
294 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
295 { "lines", optional_argument
, NULL
, 'n' },
296 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
297 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
298 { "quiet", no_argument
, NULL
, 'q' },
299 { "merge", no_argument
, NULL
, 'm' },
300 { "boot", optional_argument
, NULL
, 'b' },
301 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
302 { "this-boot", optional_argument
, NULL
, 'b' }, /* deprecated */
303 { "dmesg", no_argument
, NULL
, 'k' },
304 { "system", no_argument
, NULL
, ARG_SYSTEM
},
305 { "user", no_argument
, NULL
, ARG_USER
},
306 { "directory", required_argument
, NULL
, 'D' },
307 { "file", required_argument
, NULL
, ARG_FILE
},
308 { "root", required_argument
, NULL
, ARG_ROOT
},
309 { "header", no_argument
, NULL
, ARG_HEADER
},
310 { "identifier", required_argument
, NULL
, 't' },
311 { "priority", required_argument
, NULL
, 'p' },
312 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
313 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
314 { "verify", no_argument
, NULL
, ARG_VERIFY
},
315 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
316 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
317 { "cursor", required_argument
, NULL
, 'c' },
318 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
319 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
320 { "since", required_argument
, NULL
, ARG_SINCE
},
321 { "until", required_argument
, NULL
, ARG_UNTIL
},
322 { "unit", required_argument
, NULL
, 'u' },
323 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
324 { "field", required_argument
, NULL
, 'F' },
325 { "catalog", no_argument
, NULL
, 'x' },
326 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
327 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
328 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
329 { "reverse", no_argument
, NULL
, 'r' },
330 { "machine", required_argument
, NULL
, 'M' },
331 { "utc", no_argument
, NULL
, ARG_UTC
},
332 { "flush", no_argument
, NULL
, ARG_FLUSH
},
333 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
334 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
343 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options
, NULL
)) >= 0)
359 arg_pager_end
= true;
361 if (arg_lines
== ARG_LINES_DEFAULT
)
371 arg_output
= output_mode_from_string(optarg
);
372 if (arg_output
< 0) {
373 log_error("Unknown output format '%s'.", optarg
);
377 if (arg_output
== OUTPUT_EXPORT
||
378 arg_output
== OUTPUT_JSON
||
379 arg_output
== OUTPUT_JSON_PRETTY
||
380 arg_output
== OUTPUT_JSON_SSE
||
381 arg_output
== OUTPUT_CAT
)
400 if (streq(optarg
, "all"))
401 arg_lines
= ARG_LINES_ALL
;
403 r
= safe_atoi(optarg
, &arg_lines
);
404 if (r
< 0 || arg_lines
< 0) {
405 log_error("Failed to parse lines '%s'", optarg
);
412 /* Hmm, no argument? Maybe the next
413 * word on the command line is
414 * supposed to be the argument? Let's
415 * see if there is one, and is
419 if (streq(argv
[optind
], "all")) {
420 arg_lines
= ARG_LINES_ALL
;
422 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
436 arg_action
= ACTION_NEW_ID128
;
451 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
453 log_error("Failed to parse boot descriptor '%s'", optarg
);
458 /* Hmm, no argument? Maybe the next
459 * word on the command line is
460 * supposed to be the argument? Let's
461 * see if there is one and is parsable
462 * as a boot descriptor... */
465 parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
) >= 0)
472 arg_action
= ACTION_LIST_BOOTS
;
476 arg_boot
= arg_dmesg
= true;
480 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
484 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
488 arg_machine
= optarg
;
492 arg_directory
= optarg
;
496 r
= glob_extend(&arg_file
, optarg
);
498 return log_error_errno(r
, "Failed to add paths: %m");
509 case ARG_AFTER_CURSOR
:
510 arg_after_cursor
= optarg
;
513 case ARG_SHOW_CURSOR
:
514 arg_show_cursor
= true;
518 arg_action
= ACTION_PRINT_HEADER
;
522 arg_action
= ACTION_VERIFY
;
526 arg_action
= ACTION_DISK_USAGE
;
529 case ARG_VACUUM_SIZE
:
530 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
532 log_error("Failed to parse vacuum size: %s", optarg
);
536 arg_action
= ACTION_VACUUM
;
539 case ARG_VACUUM_TIME
:
540 r
= parse_sec(optarg
, &arg_vacuum_time
);
542 log_error("Failed to parse vacuum time: %s", optarg
);
546 arg_action
= ACTION_VACUUM
;
555 arg_action
= ACTION_SETUP_KEYS
;
560 arg_action
= ACTION_VERIFY
;
561 arg_verify_key
= optarg
;
566 r
= parse_sec(optarg
, &arg_interval
);
567 if (r
< 0 || arg_interval
<= 0) {
568 log_error("Failed to parse sealing key change interval: %s", optarg
);
577 log_error("Forward-secure sealing not available.");
584 dots
= strstr(optarg
, "..");
590 a
= strndup(optarg
, dots
- optarg
);
594 from
= log_level_from_string(a
);
595 to
= log_level_from_string(dots
+ 2);
598 if (from
< 0 || to
< 0) {
599 log_error("Failed to parse log level range %s", optarg
);
606 for (i
= from
; i
<= to
; i
++)
607 arg_priorities
|= 1 << i
;
609 for (i
= to
; i
<= from
; i
++)
610 arg_priorities
|= 1 << i
;
616 p
= log_level_from_string(optarg
);
618 log_error("Unknown log level %s", optarg
);
624 for (i
= 0; i
<= p
; i
++)
625 arg_priorities
|= 1 << i
;
632 r
= parse_timestamp(optarg
, &arg_since
);
634 log_error("Failed to parse timestamp: %s", optarg
);
637 arg_since_set
= true;
641 r
= parse_timestamp(optarg
, &arg_until
);
643 log_error("Failed to parse timestamp: %s", optarg
);
646 arg_until_set
= true;
650 r
= strv_extend(&arg_syslog_identifier
, optarg
);
656 r
= strv_extend(&arg_system_units
, optarg
);
662 r
= strv_extend(&arg_user_units
, optarg
);
675 case ARG_LIST_CATALOG
:
676 arg_action
= ACTION_LIST_CATALOG
;
679 case ARG_DUMP_CATALOG
:
680 arg_action
= ACTION_DUMP_CATALOG
;
683 case ARG_UPDATE_CATALOG
:
684 arg_action
= ACTION_UPDATE_CATALOG
;
696 arg_action
= ACTION_FLUSH
;
703 assert_not_reached("Unhandled option");
706 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
709 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
> 1) {
710 log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one.");
714 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
715 log_error("--since= must be before --until=.");
719 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
720 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
724 if (arg_follow
&& arg_reverse
) {
725 log_error("Please specify either --reverse= or --follow=, not both.");
729 if (arg_action
!= ACTION_SHOW
&& optind
< argc
) {
730 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
734 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && (arg_file
|| arg_directory
|| arg_merge
)) {
735 log_error("Using --boot or --list-boots with --file, --directory or --merge is not supported.");
742 static int generate_new_id128(void) {
747 r
= sd_id128_randomize(&id
);
749 return log_error_errno(r
, "Failed to generate ID: %m");
751 printf("As string:\n"
752 SD_ID128_FORMAT_STR
"\n\n"
754 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
756 "#define MESSAGE_XYZ SD_ID128_MAKE(",
757 SD_ID128_FORMAT_VAL(id
),
758 SD_ID128_FORMAT_VAL(id
));
759 for (i
= 0; i
< 16; i
++)
760 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
761 fputs(")\n\n", stdout
);
763 printf("As Python constant:\n"
765 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
766 SD_ID128_FORMAT_VAL(id
));
771 static int add_matches(sd_journal
*j
, char **args
) {
773 bool have_term
= false;
777 STRV_FOREACH(i
, args
) {
780 if (streq(*i
, "+")) {
783 r
= sd_journal_add_disjunction(j
);
786 } else if (path_is_absolute(*i
)) {
787 _cleanup_free_
char *p
, *t
= NULL
, *t2
= NULL
;
789 _cleanup_free_
char *interpreter
= NULL
;
792 p
= canonicalize_file_name(*i
);
795 if (lstat(path
, &st
) < 0)
796 return log_error_errno(errno
, "Couldn't stat file: %m");
798 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
799 if (executable_is_script(path
, &interpreter
) > 0) {
800 _cleanup_free_
char *comm
;
802 comm
= strndup(basename(path
), 15);
806 t
= strappend("_COMM=", comm
);
808 /* Append _EXE only if the interpreter is not a link.
809 Otherwise, it might be outdated often. */
810 if (lstat(interpreter
, &st
) == 0 &&
811 !S_ISLNK(st
.st_mode
)) {
812 t2
= strappend("_EXE=", interpreter
);
817 t
= strappend("_EXE=", path
);
818 } else if (S_ISCHR(st
.st_mode
))
819 (void) asprintf(&t
, "_KERNEL_DEVICE=c%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
820 else if (S_ISBLK(st
.st_mode
))
821 (void) asprintf(&t
, "_KERNEL_DEVICE=b%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
823 log_error("File is neither a device node, nor regular file, nor executable: %s", *i
);
830 r
= sd_journal_add_match(j
, t
, 0);
832 r
= sd_journal_add_match(j
, t2
, 0);
836 r
= sd_journal_add_match(j
, *i
, 0);
841 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
844 if (!strv_isempty(args
) && !have_term
) {
845 log_error("\"+\" can only be used between terms");
852 static void boot_id_free_all(BootId
*l
) {
856 LIST_REMOVE(boot_list
, l
, i
);
861 static int discover_next_boot(
865 bool read_realtime
) {
868 char match
[9+32+1] = "_BOOT_ID=";
869 _cleanup_free_ BootId
*next_boot
= NULL
;
874 /* We expect the journal to be on the last position of a boot
875 * (in relation to the direction we are going), so that the next
876 * invocation of sd_journal_next/previous will be from a different
877 * boot. We then collect any information we desire and then jump
878 * to the last location of the new boot by using a _BOOT_ID match
879 * coming from the other journal direction. */
881 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
882 * we can actually advance to a *different* boot. */
883 sd_journal_flush_matches(j
);
886 r
= sd_journal_previous(j
);
888 r
= sd_journal_next(j
);
892 return 0; /* End of journal, yay. */
894 next_boot
= new0(BootId
, 1);
898 r
= sd_journal_get_monotonic_usec(j
, NULL
, &next_boot
->id
);
903 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
908 /* Now seek to the last occurrence of this boot ID. */
909 sd_id128_to_string(next_boot
->id
, match
+ 9);
910 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
915 r
= sd_journal_seek_head(j
);
917 r
= sd_journal_seek_tail(j
);
922 r
= sd_journal_next(j
);
924 r
= sd_journal_previous(j
);
928 return -ENODATA
; /* This shouldn't happen. We just came from this very boot ID. */
931 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
942 static int get_boots(
945 BootId
*query_ref_boot
,
946 int ref_boot_offset
) {
950 BootId
*head
= NULL
, *tail
= NULL
;
951 const bool advance_older
= query_ref_boot
&& ref_boot_offset
<= 0;
955 /* Adjust for the asymmetry that offset 0 is
956 * the last (and current) boot, while 1 is considered the
957 * (chronological) first boot in the journal. */
958 skip_once
= query_ref_boot
&& sd_id128_is_null(query_ref_boot
->id
) && ref_boot_offset
< 0;
960 /* Advance to the earliest/latest occurrence of our reference
961 * boot ID (taking our lookup direction into account), so that
962 * discover_next_boot() can do its job.
963 * If no reference is given, the journal head/tail will do,
964 * they're "virtual" boots after all. */
965 if (query_ref_boot
&& !sd_id128_is_null(query_ref_boot
->id
)) {
966 char match
[9+32+1] = "_BOOT_ID=";
968 sd_journal_flush_matches(j
);
970 sd_id128_to_string(query_ref_boot
->id
, match
+ 9);
971 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
976 r
= sd_journal_seek_head(j
);
978 r
= sd_journal_seek_tail(j
);
983 r
= sd_journal_next(j
);
985 r
= sd_journal_previous(j
);
990 else if (ref_boot_offset
== 0) {
996 r
= sd_journal_seek_tail(j
);
998 r
= sd_journal_seek_head(j
);
1002 /* No sd_journal_next/previous here. */
1006 _cleanup_free_ BootId
*current
= NULL
;
1008 r
= discover_next_boot(j
, ¤t
, advance_older
, !query_ref_boot
);
1010 boot_id_free_all(head
);
1017 if (query_ref_boot
) {
1019 ref_boot_offset
+= advance_older
? 1 : -1;
1022 if (ref_boot_offset
== 0) {
1024 query_ref_boot
->id
= current
->id
;
1028 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1039 sd_journal_flush_matches(j
);
1044 static int list_boots(sd_journal
*j
) {
1046 BootId
*id
, *all_ids
;
1050 count
= get_boots(j
, &all_ids
, NULL
, 0);
1052 return log_error_errno(count
, "Failed to determine boots: %m");
1056 pager_open_if_enabled();
1058 /* numbers are one less, but we need an extra char for the sign */
1059 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1062 LIST_FOREACH(boot_list
, id
, all_ids
) {
1063 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1065 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1067 SD_ID128_FORMAT_VAL(id
->id
),
1068 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1069 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1073 boot_id_free_all(all_ids
);
1078 static int add_boot(sd_journal
*j
) {
1079 char match
[9+32+1] = "_BOOT_ID=";
1081 BootId ref_boot_id
= {};
1088 if (arg_boot_offset
== 0 && sd_id128_equal(arg_boot_id
, SD_ID128_NULL
))
1089 return add_match_this_boot(j
, arg_machine
);
1091 ref_boot_id
.id
= arg_boot_id
;
1092 r
= get_boots(j
, NULL
, &ref_boot_id
, arg_boot_offset
);
1095 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror(-r
);
1097 if (sd_id128_is_null(arg_boot_id
))
1098 log_error("Failed to look up boot %+i: %s", arg_boot_offset
, reason
);
1100 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR
"%+i: %s",
1101 SD_ID128_FORMAT_VAL(arg_boot_id
), arg_boot_offset
, reason
);
1103 return r
== 0 ? -ENODATA
: r
;
1106 sd_id128_to_string(ref_boot_id
.id
, match
+ 9);
1108 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1110 return log_error_errno(r
, "Failed to add match: %m");
1112 r
= sd_journal_add_conjunction(j
);
1114 return log_error_errno(r
, "Failed to add conjunction: %m");
1119 static int add_dmesg(sd_journal
*j
) {
1126 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
1128 return log_error_errno(r
, "Failed to add match: %m");
1130 r
= sd_journal_add_conjunction(j
);
1132 return log_error_errno(r
, "Failed to add conjunction: %m");
1137 static int get_possible_units(
1143 _cleanup_set_free_free_ Set
*found
;
1147 found
= set_new(&string_hash_ops
);
1151 NULSTR_FOREACH(field
, fields
) {
1155 r
= sd_journal_query_unique(j
, field
);
1159 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1160 char **pattern
, *eq
;
1162 _cleanup_free_
char *u
= NULL
;
1164 eq
= memchr(data
, '=', size
);
1166 prefix
= eq
- (char*) data
+ 1;
1170 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1174 STRV_FOREACH(pattern
, patterns
)
1175 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1176 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1178 r
= set_consume(found
, u
);
1180 if (r
< 0 && r
!= -EEXIST
)
1193 /* This list is supposed to return the superset of unit names
1194 * possibly matched by rules added with add_matches_for_unit... */
1195 #define SYSTEM_UNITS \
1199 "OBJECT_SYSTEMD_UNIT\0" \
1202 /* ... and add_matches_for_user_unit */
1203 #define USER_UNITS \
1204 "_SYSTEMD_USER_UNIT\0" \
1206 "COREDUMP_USER_UNIT\0" \
1207 "OBJECT_SYSTEMD_USER_UNIT\0"
1209 static int add_units(sd_journal
*j
) {
1210 _cleanup_strv_free_
char **patterns
= NULL
;
1216 STRV_FOREACH(i
, arg_system_units
) {
1217 _cleanup_free_
char *u
= NULL
;
1219 r
= unit_name_mangle(*i
, UNIT_NAME_GLOB
, &u
);
1223 if (string_is_glob(u
)) {
1224 r
= strv_push(&patterns
, u
);
1229 r
= add_matches_for_unit(j
, u
);
1232 r
= sd_journal_add_disjunction(j
);
1239 if (!strv_isempty(patterns
)) {
1240 _cleanup_set_free_free_ Set
*units
= NULL
;
1244 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1248 SET_FOREACH(u
, units
, it
) {
1249 r
= add_matches_for_unit(j
, u
);
1252 r
= sd_journal_add_disjunction(j
);
1259 patterns
= strv_free(patterns
);
1261 STRV_FOREACH(i
, arg_user_units
) {
1262 _cleanup_free_
char *u
= NULL
;
1264 r
= unit_name_mangle(*i
, UNIT_NAME_GLOB
, &u
);
1268 if (string_is_glob(u
)) {
1269 r
= strv_push(&patterns
, u
);
1274 r
= add_matches_for_user_unit(j
, u
, getuid());
1277 r
= sd_journal_add_disjunction(j
);
1284 if (!strv_isempty(patterns
)) {
1285 _cleanup_set_free_free_ Set
*units
= NULL
;
1289 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1293 SET_FOREACH(u
, units
, it
) {
1294 r
= add_matches_for_user_unit(j
, u
, getuid());
1297 r
= sd_journal_add_disjunction(j
);
1304 /* Complain if the user request matches but nothing whatsoever was
1305 * found, since otherwise everything would be matched. */
1306 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1309 r
= sd_journal_add_conjunction(j
);
1316 static int add_priorities(sd_journal
*j
) {
1317 char match
[] = "PRIORITY=0";
1321 if (arg_priorities
== 0xFF)
1324 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1325 if (arg_priorities
& (1 << i
)) {
1326 match
[sizeof(match
)-2] = '0' + i
;
1328 r
= sd_journal_add_match(j
, match
, strlen(match
));
1330 return log_error_errno(r
, "Failed to add match: %m");
1333 r
= sd_journal_add_conjunction(j
);
1335 return log_error_errno(r
, "Failed to add conjunction: %m");
1341 static int add_syslog_identifier(sd_journal
*j
) {
1347 STRV_FOREACH(i
, arg_syslog_identifier
) {
1350 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1351 r
= sd_journal_add_match(j
, u
, 0);
1354 r
= sd_journal_add_disjunction(j
);
1359 r
= sd_journal_add_conjunction(j
);
1366 static int setup_keys(void) {
1368 size_t mpk_size
, seed_size
, state_size
, i
;
1369 uint8_t *mpk
, *seed
, *state
;
1371 sd_id128_t machine
, boot
;
1372 char *p
= NULL
, *k
= NULL
;
1377 r
= stat("/var/log/journal", &st
);
1378 if (r
< 0 && errno
!= ENOENT
&& errno
!= ENOTDIR
)
1379 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1381 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1382 log_error("%s is not a directory, must be using persistent logging for FSS.",
1383 "/var/log/journal");
1384 return r
< 0 ? -errno
: -ENOTDIR
;
1387 r
= sd_id128_get_machine(&machine
);
1389 return log_error_errno(r
, "Failed to get machine ID: %m");
1391 r
= sd_id128_get_boot(&boot
);
1393 return log_error_errno(r
, "Failed to get boot ID: %m");
1395 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1396 SD_ID128_FORMAT_VAL(machine
)) < 0)
1401 if (r
< 0 && errno
!= ENOENT
) {
1402 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1405 } else if (access(p
, F_OK
) >= 0) {
1406 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1411 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1412 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1417 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1418 mpk
= alloca(mpk_size
);
1420 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1421 seed
= alloca(seed_size
);
1423 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1424 state
= alloca(state_size
);
1426 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1428 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1432 log_info("Generating seed...");
1433 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1435 log_error_errno(r
, "Failed to read random seed: %m");
1439 log_info("Generating key pair...");
1440 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1442 log_info("Generating sealing key...");
1443 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1445 assert(arg_interval
> 0);
1447 n
= now(CLOCK_REALTIME
);
1451 fd
= mkostemp_safe(k
, O_WRONLY
|O_CLOEXEC
);
1453 r
= log_error_errno(errno
, "Failed to open %s: %m", k
);
1457 /* Enable secure remove, exclusion from dump, synchronous
1458 * writing and in-place updating */
1459 r
= chattr_fd(fd
, FS_SECRM_FL
|FS_NODUMP_FL
|FS_SYNC_FL
|FS_NOCOW_FL
, FS_SECRM_FL
|FS_NODUMP_FL
|FS_SYNC_FL
|FS_NOCOW_FL
);
1461 log_warning_errno(errno
, "Failed to set file attributes: %m");
1464 memcpy(h
.signature
, "KSHHRHLP", 8);
1465 h
.machine_id
= machine
;
1467 h
.header_size
= htole64(sizeof(h
));
1468 h
.start_usec
= htole64(n
* arg_interval
);
1469 h
.interval_usec
= htole64(arg_interval
);
1470 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1471 h
.fsprg_state_size
= htole64(state_size
);
1473 r
= loop_write(fd
, &h
, sizeof(h
), false);
1475 log_error_errno(r
, "Failed to write header: %m");
1479 r
= loop_write(fd
, state
, state_size
, false);
1481 log_error_errno(r
, "Failed to write state: %m");
1485 if (link(k
, p
) < 0) {
1486 r
= log_error_errno(errno
, "Failed to link file: %m");
1493 "The new key pair has been generated. The " ANSI_HIGHLIGHT
"secret sealing key" ANSI_NORMAL
" has been written to\n"
1494 "the following local file. This key file is automatically updated when the\n"
1495 "sealing key is advanced. It should not be used on multiple hosts.\n"
1499 "Please write down the following " ANSI_HIGHLIGHT
"secret verification key" ANSI_NORMAL
". It should be stored\n"
1500 "at a safe location and should not be saved locally on disk.\n"
1501 "\n\t" ANSI_HIGHLIGHT_RED
, p
);
1504 for (i
= 0; i
< seed_size
; i
++) {
1505 if (i
> 0 && i
% 3 == 0)
1507 printf("%02x", ((uint8_t*) seed
)[i
]);
1510 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1513 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1517 "The sealing key is automatically changed every %s.\n",
1518 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1520 hn
= gethostname_malloc();
1523 hostname_cleanup(hn
);
1524 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1526 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1528 #ifdef HAVE_QRENCODE
1529 /* If this is not an UTF-8 system don't print any QR codes */
1530 if (is_locale_utf8()) {
1531 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1532 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1552 log_error("Forward-secure sealing not available.");
1557 static int verify(sd_journal
*j
) {
1564 log_show_color(true);
1566 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1568 usec_t first
= 0, validated
= 0, last
= 0;
1571 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1572 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1575 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1577 /* If the key was invalid give up right-away. */
1580 log_warning("FAIL: %s (%s)", f
->path
, strerror(-k
));
1583 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1584 log_info("PASS: %s", f
->path
);
1586 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1587 if (validated
> 0) {
1588 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1589 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1590 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1591 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1592 } else if (last
> 0)
1593 log_info("=> No sealing yet, %s of entries not sealed.",
1594 format_timespan(c
, sizeof(c
), last
- first
, 0));
1596 log_info("=> No sealing yet, no entries in file.");
1604 static int access_check_var_log_journal(sd_journal
*j
) {
1606 _cleanup_strv_free_
char **g
= NULL
;
1616 /* If we are root, we should have access, don't warn. */
1620 /* If we are in the 'systemd-journal' group, we should have
1622 r
= in_group("systemd-journal");
1624 return log_error_errno(r
, "Failed to check if we are in the 'systemd-journal' group: %m");
1629 if (laccess("/run/log/journal", F_OK
) >= 0)
1630 dir
= "/run/log/journal";
1632 dir
= "/var/log/journal";
1634 /* If we are in any of the groups listed in the journal ACLs,
1635 * then all is good, too. Let's enumerate all groups from the
1636 * default ACL of the directory, which generally should allow
1637 * access to most journal files too. */
1638 r
= acl_search_groups(dir
, &g
);
1640 return log_error_errno(r
, "Failed to search journal ACL: %m");
1644 /* Print a pretty list, if there were ACLs set. */
1645 if (!strv_isempty(g
)) {
1646 _cleanup_free_
char *s
= NULL
;
1648 /* Thre are groups in the ACL, let's list them */
1649 r
= strv_extend(&g
, "systemd-journal");
1656 s
= strv_join(g
, "', '");
1660 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1661 " Users in groups '%s' can see all messages.\n"
1662 " Pass -q to turn off this notice.", s
);
1667 /* If no ACLs were found, print a short version of the message. */
1668 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1669 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1670 " turn off this notice.");
1675 static int access_check(sd_journal
*j
) {
1682 if (set_isempty(j
->errors
)) {
1683 if (ordered_hashmap_isempty(j
->files
))
1684 log_notice("No journal files were found.");
1689 if (set_contains(j
->errors
, INT_TO_PTR(-EACCES
))) {
1690 (void) access_check_var_log_journal(j
);
1692 if (ordered_hashmap_isempty(j
->files
))
1693 r
= log_error_errno(EACCES
, "No journal files were opened due to insufficient permissions.");
1696 SET_FOREACH(code
, j
->errors
, it
) {
1699 err
= -PTR_TO_INT(code
);
1705 log_warning_errno(err
, "Error was encountered while opening journal files: %m");
1713 static int flush_to_var(void) {
1714 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1715 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1716 _cleanup_close_
int watch_fd
= -1;
1720 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1723 /* OK, let's actually do the full logic, send SIGUSR1 to the
1724 * daemon and set up inotify to wait for the flushed file to appear */
1725 r
= bus_connect_system_systemd(&bus
);
1727 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1729 r
= sd_bus_call_method(
1731 "org.freedesktop.systemd1",
1732 "/org/freedesktop/systemd1",
1733 "org.freedesktop.systemd1.Manager",
1737 "ssi", "systemd-journald.service", "main", SIGUSR1
);
1739 log_error("Failed to kill journal service: %s", bus_error_message(&error
, r
));
1743 mkdir_p("/run/systemd/journal", 0755);
1745 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1747 return log_error_errno(errno
, "Failed to create inotify watch: %m");
1749 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_CREATE
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
1751 return log_error_errno(errno
, "Failed to watch journal directory: %m");
1754 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1757 if (errno
!= ENOENT
)
1758 return log_error_errno(errno
, "Failed to check for existence of /run/systemd/journal/flushed: %m");
1760 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
1762 return log_error_errno(r
, "Failed to wait for event: %m");
1764 r
= flush_fd(watch_fd
);
1766 return log_error_errno(r
, "Failed to flush inotify events: %m");
1772 int main(int argc
, char *argv
[]) {
1774 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1775 bool need_seek
= false;
1776 sd_id128_t previous_boot_id
;
1777 bool previous_boot_id_valid
= false, first_line
= true;
1779 bool ellipsized
= false;
1781 setlocale(LC_ALL
, "");
1782 log_parse_environment();
1785 r
= parse_argv(argc
, argv
);
1789 signal(SIGWINCH
, columns_lines_cache_reset
);
1792 /* Increase max number of open files to 16K if we can, we
1793 * might needs this when browsing journal files, which might
1794 * be split up into many files. */
1795 setrlimit_closest(RLIMIT_NOFILE
, &RLIMIT_MAKE_CONST(16384));
1797 if (arg_action
== ACTION_NEW_ID128
) {
1798 r
= generate_new_id128();
1802 if (arg_action
== ACTION_FLUSH
) {
1807 if (arg_action
== ACTION_SETUP_KEYS
) {
1812 if (arg_action
== ACTION_UPDATE_CATALOG
||
1813 arg_action
== ACTION_LIST_CATALOG
||
1814 arg_action
== ACTION_DUMP_CATALOG
) {
1816 _cleanup_free_
char *database
;
1818 database
= path_join(arg_root
, CATALOG_DATABASE
, NULL
);
1824 if (arg_action
== ACTION_UPDATE_CATALOG
) {
1825 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
1827 log_error_errno(r
, "Failed to list catalog: %m");
1829 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
1832 r
= catalog_list_items(stdout
, database
,
1833 oneline
, argv
+ optind
);
1835 r
= catalog_list(stdout
, database
, oneline
);
1837 log_error_errno(r
, "Failed to list catalog: %m");
1844 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
1846 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
1847 else if (arg_machine
)
1848 r
= sd_journal_open_container(&j
, arg_machine
, 0);
1850 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
1852 log_error_errno(r
, "Failed to open %s: %m",
1853 arg_directory
? arg_directory
: arg_file
? "files" : "journal");
1857 r
= access_check(j
);
1861 if (arg_action
== ACTION_VERIFY
) {
1866 if (arg_action
== ACTION_PRINT_HEADER
) {
1867 journal_print_header(j
);
1872 if (arg_action
== ACTION_DISK_USAGE
) {
1874 char sbytes
[FORMAT_BYTES_MAX
];
1876 r
= sd_journal_get_usage(j
, &bytes
);
1880 printf("Archived and active journals take up %s on disk.\n",
1881 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
1885 if (arg_action
== ACTION_VACUUM
) {
1889 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
1895 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_time
, NULL
, true);
1897 log_error_errno(q
, "Failed to vacuum: %m");
1905 if (arg_action
== ACTION_LIST_BOOTS
) {
1910 /* add_boot() must be called first!
1911 * It may need to seek the journal to find parent boot IDs. */
1922 log_error_errno(r
, "Failed to add filter for units: %m");
1926 r
= add_syslog_identifier(j
);
1928 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
1932 r
= add_priorities(j
);
1936 r
= add_matches(j
, argv
+ optind
);
1940 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1941 _cleanup_free_
char *filter
;
1943 filter
= journal_make_match_string(j
);
1947 log_debug("Journal filter: %s", filter
);
1954 r
= sd_journal_set_data_threshold(j
, 0);
1956 log_error_errno(r
, "Failed to unset data size threshold: %m");
1960 r
= sd_journal_query_unique(j
, arg_field
);
1962 log_error_errno(r
, "Failed to query unique data objects: %m");
1966 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1969 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
1972 eq
= memchr(data
, '=', size
);
1974 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
1976 printf("%.*s\n", (int) size
, (const char*) data
);
1985 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1987 r
= sd_journal_get_fd(j
);
1989 log_error_errno(r
, "Failed to get journal fd: %m");
1994 if (arg_cursor
|| arg_after_cursor
) {
1995 r
= sd_journal_seek_cursor(j
, arg_cursor
?: arg_after_cursor
);
1997 log_error_errno(r
, "Failed to seek to cursor: %m");
2002 r
= sd_journal_next_skip(j
, 1 + !!arg_after_cursor
);
2004 r
= sd_journal_previous_skip(j
, 1 + !!arg_after_cursor
);
2006 if (arg_after_cursor
&& r
< 2) {
2007 /* We couldn't find the next entry after the cursor. */
2014 } else if (arg_since_set
&& !arg_reverse
) {
2015 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2017 log_error_errno(r
, "Failed to seek to date: %m");
2020 r
= sd_journal_next(j
);
2022 } else if (arg_until_set
&& arg_reverse
) {
2023 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2025 log_error_errno(r
, "Failed to seek to date: %m");
2028 r
= sd_journal_previous(j
);
2030 } else if (arg_lines
>= 0) {
2031 r
= sd_journal_seek_tail(j
);
2033 log_error_errno(r
, "Failed to seek to tail: %m");
2037 r
= sd_journal_previous_skip(j
, arg_lines
);
2039 } else if (arg_reverse
) {
2040 r
= sd_journal_seek_tail(j
);
2042 log_error_errno(r
, "Failed to seek to tail: %m");
2046 r
= sd_journal_previous(j
);
2049 r
= sd_journal_seek_head(j
);
2051 log_error_errno(r
, "Failed to seek to head: %m");
2055 r
= sd_journal_next(j
);
2059 log_error_errno(r
, "Failed to iterate through journal: %m");
2066 printf("-- No entries --\n");
2072 pager_open_if_enabled();
2076 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2078 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2080 log_error_errno(r
, "Failed to get cutoff: %m");
2086 printf("-- Logs begin at %s. --\n",
2087 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2089 printf("-- Logs begin at %s, end at %s. --\n",
2090 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2091 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2096 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2101 r
= sd_journal_next(j
);
2103 r
= sd_journal_previous(j
);
2105 log_error_errno(r
, "Failed to iterate through journal: %m");
2112 if (arg_until_set
&& !arg_reverse
) {
2115 r
= sd_journal_get_realtime_usec(j
, &usec
);
2117 log_error_errno(r
, "Failed to determine timestamp: %m");
2120 if (usec
> arg_until
)
2124 if (arg_since_set
&& arg_reverse
) {
2127 r
= sd_journal_get_realtime_usec(j
, &usec
);
2129 log_error_errno(r
, "Failed to determine timestamp: %m");
2132 if (usec
< arg_since
)
2136 if (!arg_merge
&& !arg_quiet
) {
2139 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2141 if (previous_boot_id_valid
&&
2142 !sd_id128_equal(boot_id
, previous_boot_id
))
2143 printf("%s-- Reboot --%s\n",
2144 ansi_highlight(), ansi_normal());
2146 previous_boot_id
= boot_id
;
2147 previous_boot_id_valid
= true;
2152 arg_all
* OUTPUT_SHOW_ALL
|
2153 arg_full
* OUTPUT_FULL_WIDTH
|
2154 on_tty() * OUTPUT_COLOR
|
2155 arg_catalog
* OUTPUT_CATALOG
|
2156 arg_utc
* OUTPUT_UTC
;
2158 r
= output_journal(stdout
, j
, arg_output
, 0, flags
, &ellipsized
);
2160 if (r
== -EADDRNOTAVAIL
)
2162 else if (r
< 0 || ferror(stdout
))
2169 if (arg_show_cursor
) {
2170 _cleanup_free_
char *cursor
= NULL
;
2172 r
= sd_journal_get_cursor(j
, &cursor
);
2173 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2174 log_error_errno(r
, "Failed to get cursor: %m");
2176 printf("-- cursor: %s\n", cursor
);
2182 r
= sd_journal_wait(j
, (uint64_t) -1);
2184 log_error_errno(r
, "Couldn't wait for journal event: %m");
2194 strv_free(arg_file
);
2196 strv_free(arg_syslog_identifier
);
2197 strv_free(arg_system_units
);
2198 strv_free(arg_user_units
);
2200 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;