1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
12 #include <sys/inotify.h>
17 #include "sd-device.h"
18 #include "sd-journal.h"
21 #include "alloc-util.h"
23 #include "bus-error.h"
24 #include "bus-locator.h"
28 #include "chattr-util.h"
29 #include "constants.h"
30 #include "devnum-util.h"
31 #include "dissect-image.h"
34 #include "format-table.h"
35 #include "format-util.h"
38 #include "glob-util.h"
39 #include "hostname-util.h"
40 #include "id128-print.h"
42 #include "journal-def.h"
43 #include "journal-internal.h"
44 #include "journal-util.h"
45 #include "journal-vacuum.h"
46 #include "journal-verify.h"
47 #include "locale-util.h"
49 #include "logs-show.h"
50 #include "main-func.h"
51 #include "memory-util.h"
52 #include "memstream-util.h"
53 #include "missing_sched.h"
55 #include "mount-util.h"
56 #include "mountpoint-util.h"
57 #include "nulstr-util.h"
59 #include "parse-argument.h"
60 #include "parse-util.h"
61 #include "path-util.h"
62 #include "pcre2-util.h"
63 #include "pretty-print.h"
64 #include "qrcode-util.h"
65 #include "random-util.h"
66 #include "rlimit-util.h"
69 #include "signal-util.h"
70 #include "static-destruct.h"
71 #include "stdio-util.h"
72 #include "string-table.h"
74 #include "syslog-util.h"
75 #include "terminal-util.h"
76 #include "tmpfile-util.h"
77 #include "unit-name.h"
78 #include "user-util.h"
81 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
82 #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
85 /* Special values for arg_lines */
86 ARG_LINES_DEFAULT
= -2,
90 static OutputMode arg_output
= OUTPUT_SHORT
;
91 static JsonFormatFlags arg_json_format_flags
= JSON_FORMAT_OFF
;
92 static bool arg_utc
= false;
93 static bool arg_follow
= false;
94 static bool arg_full
= true;
95 static bool arg_all
= false;
96 static PagerFlags arg_pager_flags
= 0;
97 static int arg_lines
= ARG_LINES_DEFAULT
;
98 static bool arg_lines_oldest
= false;
99 static bool arg_no_tail
= false;
100 static bool arg_truncate_newline
= false;
101 static bool arg_quiet
= false;
102 static bool arg_merge
= false;
103 static bool arg_boot
= false;
104 static sd_id128_t arg_boot_id
= {};
105 static int arg_boot_offset
= 0;
106 static bool arg_dmesg
= false;
107 static bool arg_no_hostname
= false;
108 static const char *arg_cursor
= NULL
;
109 static const char *arg_cursor_file
= NULL
;
110 static const char *arg_after_cursor
= NULL
;
111 static bool arg_show_cursor
= false;
112 static const char *arg_directory
= NULL
;
113 static char **arg_file
= NULL
;
114 static bool arg_file_stdin
= false;
115 static int arg_priorities
= 0xFF;
116 static Set
*arg_facilities
= NULL
;
117 static char *arg_verify_key
= NULL
;
119 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
120 static bool arg_force
= false;
122 static usec_t arg_since
= 0, arg_until
= 0;
123 static bool arg_since_set
= false, arg_until_set
= false;
124 static char **arg_syslog_identifier
= NULL
;
125 static char **arg_system_units
= NULL
;
126 static char **arg_user_units
= NULL
;
127 static const char *arg_field
= NULL
;
128 static bool arg_catalog
= false;
129 static bool arg_reverse
= false;
130 static int arg_journal_type
= 0;
131 static int arg_namespace_flags
= 0;
132 static char *arg_root
= NULL
;
133 static char *arg_image
= NULL
;
134 static const char *arg_machine
= NULL
;
135 static const char *arg_namespace
= NULL
;
136 static uint64_t arg_vacuum_size
= 0;
137 static uint64_t arg_vacuum_n_files
= 0;
138 static usec_t arg_vacuum_time
= 0;
139 static Set
*arg_output_fields
= NULL
;
140 static const char *arg_pattern
= NULL
;
141 static pcre2_code
*arg_compiled_pattern
= NULL
;
142 static PatternCompileCase arg_case
= PATTERN_COMPILE_CASE_AUTO
;
143 ImagePolicy
*arg_image_policy
= NULL
;
145 STATIC_DESTRUCTOR_REGISTER(arg_file
, strv_freep
);
146 STATIC_DESTRUCTOR_REGISTER(arg_facilities
, set_freep
);
147 STATIC_DESTRUCTOR_REGISTER(arg_verify_key
, freep
);
148 STATIC_DESTRUCTOR_REGISTER(arg_syslog_identifier
, strv_freep
);
149 STATIC_DESTRUCTOR_REGISTER(arg_system_units
, strv_freep
);
150 STATIC_DESTRUCTOR_REGISTER(arg_user_units
, strv_freep
);
151 STATIC_DESTRUCTOR_REGISTER(arg_root
, freep
);
152 STATIC_DESTRUCTOR_REGISTER(arg_image
, freep
);
153 STATIC_DESTRUCTOR_REGISTER(arg_output_fields
, set_freep
);
154 STATIC_DESTRUCTOR_REGISTER(arg_compiled_pattern
, pattern_freep
);
155 STATIC_DESTRUCTOR_REGISTER(arg_image_policy
, image_policy_freep
);
166 ACTION_UPDATE_CATALOG
,
169 ACTION_RELINQUISH_VAR
,
173 ACTION_ROTATE_AND_VACUUM
,
175 ACTION_LIST_FIELD_NAMES
,
176 } arg_action
= ACTION_SHOW
;
178 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
179 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
187 if (!path_startswith(devpath
, "/dev/"))
188 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
189 "Devpath does not start with /dev/");
191 if (stat(devpath
, &st
) < 0)
192 return log_error_errno(errno
, "Couldn't stat file: %m");
194 r
= sd_device_new_from_stat_rdev(&device
, &st
);
196 return log_error_errno(r
, "Failed to get device from devnum " DEVNUM_FORMAT_STR
": %m", DEVNUM_FORMAT_VAL(st
.st_rdev
));
198 for (d
= device
; d
; ) {
199 _cleanup_free_
char *match
= NULL
;
200 const char *subsys
, *sysname
, *devnode
;
203 r
= sd_device_get_subsystem(d
, &subsys
);
207 r
= sd_device_get_sysname(d
, &sysname
);
211 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
215 r
= sd_journal_add_match(j
, match
, 0);
217 return log_error_errno(r
, "Failed to add match: %m");
219 if (sd_device_get_devname(d
, &devnode
) >= 0) {
220 _cleanup_free_
char *match1
= NULL
;
222 r
= stat(devnode
, &st
);
224 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
226 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c" DEVNUM_FORMAT_STR
, S_ISBLK(st
.st_mode
) ? 'b' : 'c', DEVNUM_FORMAT_VAL(st
.st_rdev
));
230 r
= sd_journal_add_match(j
, match1
, 0);
232 return log_error_errno(r
, "Failed to add match: %m");
236 if (sd_device_get_parent(d
, &parent
) < 0)
242 r
= add_match_this_boot(j
, arg_machine
);
244 return log_error_errno(r
, "Failed to add match for the current boot: %m");
249 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
252 return format_timestamp_style(buf
, l
, t
, TIMESTAMP_UTC
);
254 return format_timestamp(buf
, l
, t
);
257 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
258 sd_id128_t id
= SD_ID128_NULL
;
261 if (streq(x
, "all")) {
262 *boot_id
= SD_ID128_NULL
;
265 } else if (strlen(x
) >= SD_ID128_STRING_MAX
- 1) {
268 t
= strndupa_safe(x
, SD_ID128_STRING_MAX
- 1);
269 r
= sd_id128_from_string(t
, &id
);
271 x
+= SD_ID128_STRING_MAX
- 1;
273 if (!IN_SET(*x
, 0, '-', '+'))
277 r
= safe_atoi(x
, &off
);
282 r
= safe_atoi(x
, &off
);
296 static int parse_lines(const char *arg
, bool graceful
) {
300 assert(arg
|| graceful
);
305 if (streq(arg
, "all")) {
306 arg_lines
= ARG_LINES_ALL
;
310 l
= startswith(arg
, "+");
312 r
= safe_atoi(l
?: arg
, &n
);
313 if (r
< 0 || n
< 0) {
317 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse --lines='%s'.", arg
);
321 arg_lines_oldest
= l
;
327 arg_lines_oldest
= false;
331 static bool arg_lines_needs_seek_end(void) {
332 return arg_lines
>= 0 && !arg_lines_oldest
;
335 static int help_facilities(void) {
337 puts("Available facilities:");
339 for (int i
= 0; i
< LOG_NFACILITIES
; i
++) {
340 _cleanup_free_
char *t
= NULL
;
342 if (log_facility_unshifted_to_string_alloc(i
, &t
))
350 static int help(void) {
351 _cleanup_free_
char *link
= NULL
;
354 pager_open(arg_pager_flags
);
356 r
= terminal_urlify_man("journalctl", "1", &link
);
360 printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
361 "%5$sQuery the journal.%6$s\n\n"
362 "%3$sSource Options:%4$s\n"
363 " --system Show the system journal\n"
364 " --user Show the user journal for the current user\n"
365 " -M --machine=CONTAINER Operate on local container\n"
366 " -m --merge Show entries from all available journals\n"
367 " -D --directory=PATH Show journal files from directory\n"
368 " --file=PATH Show journal file\n"
369 " --root=PATH Operate on an alternate filesystem root\n"
370 " --image=PATH Operate on disk image as filesystem root\n"
371 " --image-policy=POLICY Specify disk image dissection policy\n"
372 " --namespace=NAMESPACE Show journal data from specified journal namespace\n"
373 "\n%3$sFiltering Options:%4$s\n"
374 " -S --since=DATE Show entries not older than the specified date\n"
375 " -U --until=DATE Show entries not newer than the specified date\n"
376 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
377 " --after-cursor=CURSOR Show entries after the specified cursor\n"
378 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
379 " -b --boot[=ID] Show current boot or the specified boot\n"
380 " -u --unit=UNIT Show logs from the specified unit\n"
381 " --user-unit=UNIT Show logs from the specified user unit\n"
382 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
383 " -p --priority=RANGE Show entries with the specified priority\n"
384 " --facility=FACILITY... Show entries with the specified facilities\n"
385 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
386 " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
387 " -k --dmesg Show kernel message log from the current boot\n"
388 "\n%3$sOutput Control Options:%4$s\n"
389 " -o --output=STRING Change journal output mode (short, short-precise,\n"
390 " short-iso, short-iso-precise, short-full,\n"
391 " short-monotonic, short-unix, verbose, export,\n"
392 " json, json-pretty, json-sse, json-seq, cat,\n"
394 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
395 " -n --lines[=[+]INTEGER] Number of journal entries to show\n"
396 " -r --reverse Show the newest entries first\n"
397 " --show-cursor Print the cursor after all the entries\n"
398 " --utc Express time in Coordinated Universal Time (UTC)\n"
399 " -x --catalog Add message explanations where available\n"
400 " --no-hostname Suppress output of hostname field\n"
401 " --no-full Ellipsize fields\n"
402 " -a --all Show all fields, including long and unprintable\n"
403 " -f --follow Follow the journal\n"
404 " --no-tail Show all lines, even in follow mode\n"
405 " --truncate-newline Truncate entries by first newline character\n"
406 " -q --quiet Do not show info messages and privilege warning\n"
407 "\n%3$sPager Control Options:%4$s\n"
408 " --no-pager Do not pipe output into a pager\n"
409 " -e --pager-end Immediately jump to the end in the pager\n"
410 "\n%3$sForward Secure Sealing (FSS) Options:%4$s\n"
411 " --interval=TIME Time interval for changing the FSS sealing key\n"
412 " --verify-key=KEY Specify FSS verification key\n"
413 " --force Override of the FSS key pair with --setup-keys\n"
414 "\n%3$sCommands:%4$s\n"
415 " -h --help Show this help text\n"
416 " --version Show package version\n"
417 " -N --fields List all field names currently used\n"
418 " -F --field=FIELD List all values that a specified field takes\n"
419 " --list-boots Show terse information about recorded boots\n"
420 " --disk-usage Show total disk usage of all journal files\n"
421 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
422 " --vacuum-files=INT Leave only the specified number of journal files\n"
423 " --vacuum-time=TIME Remove journal files older than specified time\n"
424 " --verify Verify journal file consistency\n"
425 " --sync Synchronize unwritten journal messages to disk\n"
426 " --relinquish-var Stop logging to disk, log to temporary file system\n"
427 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
428 " --flush Flush all journal data from /run into /var\n"
429 " --rotate Request immediate rotation of the journal files\n"
430 " --header Show journal header information\n"
431 " --list-catalog Show all message IDs in the catalog\n"
432 " --dump-catalog Show entries in the message catalog\n"
433 " --update-catalog Update the message catalog database\n"
434 " --setup-keys Generate a new FSS key pair\n"
435 "\nSee the %2$s for details.\n",
436 program_invocation_short_name
,
446 static int parse_argv(int argc
, char *argv
[]) {
482 ARG_SMART_RELINQUISH_VAR
,
484 ARG_TRUNCATE_NEWLINE
,
493 static const struct option options
[] = {
494 { "help", no_argument
, NULL
, 'h' },
495 { "version" , no_argument
, NULL
, ARG_VERSION
},
496 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
497 { "pager-end", no_argument
, NULL
, 'e' },
498 { "follow", no_argument
, NULL
, 'f' },
499 { "force", no_argument
, NULL
, ARG_FORCE
},
500 { "output", required_argument
, NULL
, 'o' },
501 { "all", no_argument
, NULL
, 'a' },
502 { "full", no_argument
, NULL
, 'l' },
503 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
504 { "lines", optional_argument
, NULL
, 'n' },
505 { "truncate-newline", no_argument
, NULL
, ARG_TRUNCATE_NEWLINE
},
506 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
507 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
508 { "quiet", no_argument
, NULL
, 'q' },
509 { "merge", no_argument
, NULL
, 'm' },
510 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
511 { "boot", optional_argument
, NULL
, 'b' },
512 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
513 { "dmesg", no_argument
, NULL
, 'k' },
514 { "system", no_argument
, NULL
, ARG_SYSTEM
},
515 { "user", no_argument
, NULL
, ARG_USER
},
516 { "directory", required_argument
, NULL
, 'D' },
517 { "file", required_argument
, NULL
, ARG_FILE
},
518 { "root", required_argument
, NULL
, ARG_ROOT
},
519 { "image", required_argument
, NULL
, ARG_IMAGE
},
520 { "image-policy", required_argument
, NULL
, ARG_IMAGE_POLICY
},
521 { "header", no_argument
, NULL
, ARG_HEADER
},
522 { "identifier", required_argument
, NULL
, 't' },
523 { "priority", required_argument
, NULL
, 'p' },
524 { "facility", required_argument
, NULL
, ARG_FACILITY
},
525 { "grep", required_argument
, NULL
, 'g' },
526 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
527 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
528 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
529 { "verify", no_argument
, NULL
, ARG_VERIFY
},
530 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
531 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
532 { "cursor", required_argument
, NULL
, 'c' },
533 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
534 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
535 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
536 { "since", required_argument
, NULL
, 'S' },
537 { "until", required_argument
, NULL
, 'U' },
538 { "unit", required_argument
, NULL
, 'u' },
539 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
540 { "field", required_argument
, NULL
, 'F' },
541 { "fields", no_argument
, NULL
, 'N' },
542 { "catalog", no_argument
, NULL
, 'x' },
543 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
544 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
545 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
546 { "reverse", no_argument
, NULL
, 'r' },
547 { "machine", required_argument
, NULL
, 'M' },
548 { "utc", no_argument
, NULL
, ARG_UTC
},
549 { "flush", no_argument
, NULL
, ARG_FLUSH
},
550 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
551 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
552 { "sync", no_argument
, NULL
, ARG_SYNC
},
553 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
554 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
555 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
556 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
557 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
558 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
559 { "namespace", required_argument
, NULL
, ARG_NAMESPACE
},
568 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
579 arg_pager_flags
|= PAGER_DISABLE
;
583 arg_pager_flags
|= PAGER_JUMP_TO_END
;
585 if (arg_lines
== ARG_LINES_DEFAULT
)
597 if (streq(optarg
, "help")) {
598 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
602 arg_output
= output_mode_from_string(optarg
);
604 return log_error_errno(arg_output
, "Unknown output format '%s'.", optarg
);
606 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
609 if (OUTPUT_MODE_IS_JSON(arg_output
))
610 arg_json_format_flags
= output_mode_to_json_format_flags(arg_output
) | JSON_FORMAT_COLOR_AUTO
;
612 arg_json_format_flags
= JSON_FORMAT_OFF
;
629 r
= parse_lines(optarg
?: argv
[optind
], !optarg
);
632 if (r
> 0 && !optarg
)
641 case ARG_TRUNCATE_NEWLINE
:
642 arg_truncate_newline
= true;
646 arg_action
= ACTION_NEW_ID128
;
659 arg_boot_id
= SD_ID128_NULL
;
665 arg_boot_id
= SD_ID128_NULL
;
669 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
671 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
675 /* Hmm, no argument? Maybe the next
676 * word on the command line is
677 * supposed to be the argument? Let's
678 * see if there is one and is parsable
679 * as a boot descriptor... */
680 } else if (optind
< argc
) {
681 r
= parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
690 arg_action
= ACTION_LIST_BOOTS
;
694 arg_boot
= arg_dmesg
= true;
698 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
702 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
706 arg_machine
= optarg
;
710 if (streq(optarg
, "*")) {
711 arg_namespace_flags
= SD_JOURNAL_ALL_NAMESPACES
;
712 arg_namespace
= NULL
;
713 } else if (startswith(optarg
, "+")) {
714 arg_namespace_flags
= SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
;
715 arg_namespace
= optarg
+ 1;
716 } else if (isempty(optarg
)) {
717 arg_namespace_flags
= 0;
718 arg_namespace
= NULL
;
720 arg_namespace_flags
= 0;
721 arg_namespace
= optarg
;
727 arg_directory
= optarg
;
731 if (streq(optarg
, "-"))
732 /* An undocumented feature: we can read journal files from STDIN. We don't document
733 * this though, since after all we only support this for mmap-able, seekable files, and
734 * not for example pipes which are probably the primary use case for reading things from
735 * STDIN. To avoid confusion we hence don't document this feature. */
736 arg_file_stdin
= true;
738 r
= glob_extend(&arg_file
, optarg
, GLOB_NOCHECK
);
740 return log_error_errno(r
, "Failed to add paths: %m");
745 r
= parse_path_argument(optarg
, /* suppress_root= */ true, &arg_root
);
751 r
= parse_path_argument(optarg
, /* suppress_root= */ false, &arg_image
);
756 case ARG_IMAGE_POLICY
:
757 r
= parse_image_policy_argument(optarg
, &arg_image_policy
);
766 case ARG_CURSOR_FILE
:
767 arg_cursor_file
= optarg
;
770 case ARG_AFTER_CURSOR
:
771 arg_after_cursor
= optarg
;
774 case ARG_SHOW_CURSOR
:
775 arg_show_cursor
= true;
779 arg_action
= ACTION_PRINT_HEADER
;
783 arg_action
= ACTION_VERIFY
;
787 arg_action
= ACTION_DISK_USAGE
;
790 case ARG_VACUUM_SIZE
:
791 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
793 return log_error_errno(r
, "Failed to parse vacuum size: %s", optarg
);
795 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
798 case ARG_VACUUM_FILES
:
799 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
801 return log_error_errno(r
, "Failed to parse vacuum files: %s", optarg
);
803 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
806 case ARG_VACUUM_TIME
:
807 r
= parse_sec(optarg
, &arg_vacuum_time
);
809 return log_error_errno(r
, "Failed to parse vacuum time: %s", optarg
);
811 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
820 arg_action
= ACTION_SETUP_KEYS
;
824 r
= free_and_strdup(&arg_verify_key
, optarg
);
827 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
828 * in ps or htop output. */
829 memset(optarg
, 'x', strlen(optarg
));
831 arg_action
= ACTION_VERIFY
;
836 r
= parse_sec(optarg
, &arg_interval
);
837 if (r
< 0 || arg_interval
<= 0)
838 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
839 "Failed to parse sealing key change interval: %s", optarg
);
846 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
847 "Compiled without forward-secure sealing support.");
853 dots
= strstr(optarg
, "..");
855 _cleanup_free_
char *a
= NULL
;
859 a
= strndup(optarg
, dots
- optarg
);
863 from
= log_level_from_string(a
);
864 to
= log_level_from_string(dots
+ 2);
866 if (from
< 0 || to
< 0)
867 return log_error_errno(from
< 0 ? from
: to
,
868 "Failed to parse log level range %s", optarg
);
873 for (i
= from
; i
<= to
; i
++)
874 arg_priorities
|= 1 << i
;
876 for (i
= to
; i
<= from
; i
++)
877 arg_priorities
|= 1 << i
;
883 p
= log_level_from_string(optarg
);
885 return log_error_errno(p
, "Unknown log level %s", optarg
);
889 for (i
= 0; i
<= p
; i
++)
890 arg_priorities
|= 1 << i
;
900 _cleanup_free_
char *fac
= NULL
;
903 r
= extract_first_word(&p
, &fac
, ",", 0);
905 return log_error_errno(r
, "Failed to parse facilities: %s", optarg
);
909 if (streq(fac
, "help")) {
914 num
= log_facility_unshifted_from_string(fac
);
916 return log_error_errno(num
, "Bad --facility= argument \"%s\".", fac
);
918 if (set_ensure_put(&arg_facilities
, NULL
, INT_TO_PTR(num
)) < 0)
926 arg_pattern
= optarg
;
929 case ARG_CASE_SENSITIVE
:
931 r
= parse_boolean(optarg
);
933 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
934 arg_case
= r
? PATTERN_COMPILE_CASE_SENSITIVE
: PATTERN_COMPILE_CASE_INSENSITIVE
;
936 arg_case
= PATTERN_COMPILE_CASE_SENSITIVE
;
941 r
= parse_timestamp(optarg
, &arg_since
);
943 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
944 "Failed to parse timestamp: %s", optarg
);
945 arg_since_set
= true;
949 r
= parse_timestamp(optarg
, &arg_until
);
951 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
952 "Failed to parse timestamp: %s", optarg
);
953 arg_until_set
= true;
957 r
= strv_extend(&arg_syslog_identifier
, optarg
);
963 r
= strv_extend(&arg_system_units
, optarg
);
969 r
= strv_extend(&arg_user_units
, optarg
);
975 arg_action
= ACTION_LIST_FIELDS
;
980 arg_action
= ACTION_LIST_FIELD_NAMES
;
983 case ARG_NO_HOSTNAME
:
984 arg_no_hostname
= true;
991 case ARG_LIST_CATALOG
:
992 arg_action
= ACTION_LIST_CATALOG
;
995 case ARG_DUMP_CATALOG
:
996 arg_action
= ACTION_DUMP_CATALOG
;
999 case ARG_UPDATE_CATALOG
:
1000 arg_action
= ACTION_UPDATE_CATALOG
;
1012 arg_action
= ACTION_FLUSH
;
1015 case ARG_SMART_RELINQUISH_VAR
: {
1016 int root_mnt_id
, log_mnt_id
;
1018 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
1019 * if it's on the same mount as the root file system there's no point in
1020 * relinquishing access and we can leave journald write to it until the very last
1023 r
= path_get_mnt_id("/", &root_mnt_id
);
1025 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
1027 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
1029 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
1030 else if (root_mnt_id
== log_mnt_id
) {
1031 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
1034 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
1040 case ARG_RELINQUISH_VAR
:
1041 arg_action
= ACTION_RELINQUISH_VAR
;
1045 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
1049 arg_action
= ACTION_SYNC
;
1052 case ARG_OUTPUT_FIELDS
: {
1053 _cleanup_strv_free_
char **v
= NULL
;
1055 v
= strv_split(optarg
, ",");
1059 r
= set_put_strdupv(&arg_output_fields
, v
);
1069 assert_not_reached();
1073 arg_lines
= ARG_LINES_ALL
;
1075 if (arg_follow
&& !arg_since_set
&& arg_lines
== ARG_LINES_DEFAULT
)
1078 if (arg_follow
&& !arg_merge
&& !arg_boot
) {
1080 arg_boot_id
= SD_ID128_NULL
;
1081 arg_boot_offset
= 0;
1084 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
+ !!arg_image
> 1)
1085 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1086 "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
1088 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
)
1089 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1090 "--since= must be before --until=.");
1092 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1)
1093 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1094 "Please specify only one of --since=, --cursor=, and --after-cursor=.");
1096 if (arg_follow
&& arg_reverse
)
1097 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1098 "Please specify either --reverse or --follow, not both.");
1100 if (arg_lines
>= 0 && arg_lines_oldest
&& (arg_reverse
|| arg_follow
))
1101 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1102 "--lines=+N is unsupported when --reverse or --follow is specified.");
1104 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
)
1105 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1106 "Extraneous arguments starting with '%s'",
1109 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
)
1110 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1111 "Using --boot or --list-boots with --merge is not supported.");
1113 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
1114 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1115 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1116 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1117 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
1121 arg_system_units
= strv_free(arg_system_units
);
1125 r
= pattern_compile_and_log(arg_pattern
, arg_case
, &arg_compiled_pattern
);
1129 /* When --grep is used along with --lines without '+', i.e. when we start from the end of the
1130 * journal, we don't know how many lines we can print. So we search backwards and count until
1131 * enough lines have been printed or we hit the head.
1132 * An exception is that --follow might set arg_lines, so let's not imply --reverse
1133 * if that is specified. */
1134 if (arg_lines_needs_seek_end() && !arg_follow
)
1141 static int add_matches(sd_journal
*j
, char **args
) {
1142 bool have_term
= false;
1146 STRV_FOREACH(i
, args
) {
1149 if (streq(*i
, "+")) {
1152 r
= sd_journal_add_disjunction(j
);
1155 } else if (path_is_absolute(*i
)) {
1156 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1159 r
= chase(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
, NULL
);
1161 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1163 if (lstat(p
, &st
) < 0)
1164 return log_error_errno(errno
, "Couldn't stat file: %m");
1166 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1167 if (executable_is_script(p
, &interpreter
) > 0) {
1168 _cleanup_free_
char *comm
= NULL
;
1170 r
= path_extract_filename(p
, &comm
);
1172 return log_error_errno(r
, "Failed to extract filename of '%s': %m", p
);
1174 t
= strjoin("_COMM=", strshorten(comm
, TASK_COMM_LEN
-1));
1178 /* Append _EXE only if the interpreter is not a link.
1179 Otherwise, it might be outdated often. */
1180 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1181 t2
= strjoin("_EXE=", interpreter
);
1186 t
= strjoin("_EXE=", p
);
1191 r
= sd_journal_add_match(j
, t
, 0);
1194 r
= sd_journal_add_match(j
, t2
, 0);
1196 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1197 r
= add_matches_for_device(j
, p
);
1201 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1202 "File is neither a device node, nor regular file, nor executable: %s",
1207 r
= sd_journal_add_match(j
, *i
, 0);
1212 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1215 if (!strv_isempty(args
) && !have_term
)
1216 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1217 "\"+\" can only be used between terms");
1222 static int list_boots(sd_journal
*j
) {
1223 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1224 _cleanup_free_ BootId
*boots
= NULL
;
1230 r
= journal_get_boots(j
, &boots
, &n_boots
);
1232 return log_error_errno(r
, "Failed to determine boots: %m");
1236 table
= table_new("idx", "boot id", "first entry", "last entry");
1241 table_set_width(table
, 0);
1243 r
= table_set_json_field_name(table
, 0, "index");
1245 return log_error_errno(r
, "Failed to set JSON field name of column 0: %m");
1247 (void) table_set_sort(table
, (size_t) 0);
1248 (void) table_set_reverse(table
, 0, arg_reverse
);
1250 FOREACH_ARRAY(i
, boots
, n_boots
) {
1251 r
= table_add_many(table
,
1252 TABLE_INT
, (int)(i
- boots
) - (int) n_boots
+ 1,
1253 TABLE_SET_ALIGN_PERCENT
, 100,
1255 TABLE_TIMESTAMP
, i
->first_usec
,
1256 TABLE_TIMESTAMP
, i
->last_usec
);
1258 return table_log_add_error(r
);
1261 r
= table_print_with_pager(table
, arg_json_format_flags
, arg_pager_flags
, !arg_quiet
);
1263 return table_log_print_error(r
);
1268 static int add_boot(sd_journal
*j
) {
1276 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1277 * We can do this only when we logs are coming from the current machine,
1278 * so take the slow path if log location is specified. */
1279 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1280 !arg_directory
&& !arg_file
&& !arg_root
)
1281 return add_match_this_boot(j
, arg_machine
);
1283 if (sd_id128_is_null(arg_boot_id
)) {
1284 r
= journal_find_boot_by_offset(j
, arg_boot_offset
, &arg_boot_id
);
1286 return log_error_errno(r
, "Failed to find journal entry from the specified boot offset (%+i): %m",
1289 return log_error_errno(SYNTHETIC_ERRNO(ENODATA
),
1290 "No journal boot entry found from the specified boot offset (%+i).",
1293 r
= journal_find_boot_by_id(j
, arg_boot_id
);
1295 return log_error_errno(r
, "Failed to find journal entry from the specified boot ID (%s): %m",
1296 SD_ID128_TO_STRING(arg_boot_id
));
1298 return log_error_errno(SYNTHETIC_ERRNO(ENODATA
),
1299 "No journal boot entry found from the specified boot ID (%s).",
1300 SD_ID128_TO_STRING(arg_boot_id
));
1303 r
= add_match_boot_id(j
, arg_boot_id
);
1305 return log_error_errno(r
, "Failed to add match: %m");
1307 r
= sd_journal_add_conjunction(j
);
1309 return log_error_errno(r
, "Failed to add conjunction: %m");
1314 static int add_dmesg(sd_journal
*j
) {
1321 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1322 STRLEN("_TRANSPORT=kernel"));
1324 return log_error_errno(r
, "Failed to add match: %m");
1326 r
= sd_journal_add_conjunction(j
);
1328 return log_error_errno(r
, "Failed to add conjunction: %m");
1333 static int get_possible_units(
1339 _cleanup_set_free_free_ Set
*found
= NULL
;
1342 found
= set_new(&string_hash_ops
);
1346 NULSTR_FOREACH(field
, fields
) {
1350 r
= sd_journal_query_unique(j
, field
);
1354 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1357 _cleanup_free_
char *u
= NULL
;
1359 eq
= memchr(data
, '=', size
);
1361 prefix
= eq
- (char*) data
+ 1;
1365 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1369 STRV_FOREACH(pattern
, patterns
)
1370 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1371 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1373 r
= set_consume(found
, u
);
1375 if (r
< 0 && r
!= -EEXIST
)
1383 *units
= TAKE_PTR(found
);
1388 /* This list is supposed to return the superset of unit names
1389 * possibly matched by rules added with add_matches_for_unit... */
1390 #define SYSTEM_UNITS \
1394 "OBJECT_SYSTEMD_UNIT\0" \
1397 /* ... and add_matches_for_user_unit */
1398 #define USER_UNITS \
1399 "_SYSTEMD_USER_UNIT\0" \
1401 "COREDUMP_USER_UNIT\0" \
1402 "OBJECT_SYSTEMD_USER_UNIT\0" \
1403 "_SYSTEMD_USER_SLICE\0"
1405 static int add_units(sd_journal
*j
) {
1406 _cleanup_strv_free_
char **patterns
= NULL
;
1411 STRV_FOREACH(i
, arg_system_units
) {
1412 _cleanup_free_
char *u
= NULL
;
1414 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1418 if (string_is_glob(u
)) {
1419 r
= strv_push(&patterns
, u
);
1424 r
= add_matches_for_unit(j
, u
);
1427 r
= sd_journal_add_disjunction(j
);
1434 if (!strv_isempty(patterns
)) {
1435 _cleanup_set_free_free_ Set
*units
= NULL
;
1438 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1442 SET_FOREACH(u
, units
) {
1443 r
= add_matches_for_unit(j
, u
);
1446 r
= sd_journal_add_disjunction(j
);
1453 patterns
= strv_free(patterns
);
1455 STRV_FOREACH(i
, arg_user_units
) {
1456 _cleanup_free_
char *u
= NULL
;
1458 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1462 if (string_is_glob(u
)) {
1463 r
= strv_push(&patterns
, u
);
1468 r
= add_matches_for_user_unit(j
, u
, getuid());
1471 r
= sd_journal_add_disjunction(j
);
1478 if (!strv_isempty(patterns
)) {
1479 _cleanup_set_free_free_ Set
*units
= NULL
;
1482 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1486 SET_FOREACH(u
, units
) {
1487 r
= add_matches_for_user_unit(j
, u
, getuid());
1490 r
= sd_journal_add_disjunction(j
);
1497 /* Complain if the user request matches but nothing whatsoever was
1498 * found, since otherwise everything would be matched. */
1499 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1502 r
= sd_journal_add_conjunction(j
);
1509 static int add_priorities(sd_journal
*j
) {
1510 char match
[] = "PRIORITY=0";
1514 if (arg_priorities
== 0xFF)
1517 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1518 if (arg_priorities
& (1 << i
)) {
1519 match
[sizeof(match
)-2] = '0' + i
;
1521 r
= sd_journal_add_match(j
, match
, strlen(match
));
1523 return log_error_errno(r
, "Failed to add match: %m");
1526 r
= sd_journal_add_conjunction(j
);
1528 return log_error_errno(r
, "Failed to add conjunction: %m");
1533 static int add_facilities(sd_journal
*j
) {
1537 SET_FOREACH(p
, arg_facilities
) {
1538 char match
[STRLEN("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
1540 xsprintf(match
, "SYSLOG_FACILITY=%d", PTR_TO_INT(p
));
1542 r
= sd_journal_add_match(j
, match
, strlen(match
));
1544 return log_error_errno(r
, "Failed to add match: %m");
1550 static int add_syslog_identifier(sd_journal
*j
) {
1555 STRV_FOREACH(i
, arg_syslog_identifier
) {
1556 _cleanup_free_
char *u
= NULL
;
1558 u
= strjoin("SYSLOG_IDENTIFIER=", *i
);
1561 r
= sd_journal_add_match(j
, u
, 0);
1564 r
= sd_journal_add_disjunction(j
);
1569 r
= sd_journal_add_conjunction(j
);
1577 static int format_journal_url(
1587 _cleanup_(memstream_done
) MemStream m
= {};
1591 assert(seed_size
> 0);
1593 f
= memstream_init(&m
);
1600 for (size_t i
= 0; i
< seed_size
; i
++) {
1601 if (i
> 0 && i
% 3 == 0)
1603 fprintf(f
, "%02x", ((uint8_t*) seed
)[i
]);
1606 fprintf(f
, "/%"PRIx64
"-%"PRIx64
, start
, interval
);
1609 fprintf(f
, "?machine=" SD_ID128_FORMAT_STR
, SD_ID128_FORMAT_VAL(machine
));
1611 fprintf(f
, ";hostname=%s", hn
);
1614 return memstream_finalize(&m
, ret_url
, NULL
);
1618 static int setup_keys(void) {
1620 size_t mpk_size
, seed_size
, state_size
;
1621 _cleanup_(unlink_and_freep
) char *k
= NULL
;
1622 _cleanup_free_
char *p
= NULL
;
1623 uint8_t *mpk
, *seed
, *state
;
1624 _cleanup_close_
int fd
= -EBADF
;
1625 sd_id128_t machine
, boot
;
1630 r
= stat("/var/log/journal", &st
);
1631 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1632 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1634 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1635 log_error("%s is not a directory, must be using persistent logging for FSS.",
1636 "/var/log/journal");
1637 return r
< 0 ? -errno
: -ENOTDIR
;
1640 r
= sd_id128_get_machine(&machine
);
1642 return log_error_errno(r
, "Failed to get machine ID: %m");
1644 r
= sd_id128_get_boot(&boot
);
1646 return log_error_errno(r
, "Failed to get boot ID: %m");
1648 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1649 SD_ID128_FORMAT_VAL(machine
)) < 0)
1654 if (r
< 0 && errno
!= ENOENT
)
1655 return log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1656 } else if (access(p
, F_OK
) >= 0)
1657 return log_error_errno(SYNTHETIC_ERRNO(EEXIST
),
1658 "Sealing key file %s exists already. Use --force to recreate.", p
);
1660 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1661 SD_ID128_FORMAT_VAL(machine
)) < 0)
1664 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1665 mpk
= alloca_safe(mpk_size
);
1667 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1668 seed
= alloca_safe(seed_size
);
1670 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1671 state
= alloca_safe(state_size
);
1673 log_info("Generating seed...");
1674 r
= crypto_random_bytes(seed
, seed_size
);
1676 return log_error_errno(r
, "Failed to acquire random seed: %m");
1678 log_info("Generating key pair...");
1679 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1681 log_info("Generating sealing key...");
1682 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1684 assert(arg_interval
> 0);
1686 n
= now(CLOCK_REALTIME
);
1690 fd
= mkostemp_safe(k
);
1692 return log_error_errno(fd
, "Failed to open %s: %m", k
);
1694 r
= chattr_secret(fd
, CHATTR_WARN_UNSUPPORTED_FLAGS
);
1696 log_full_errno(ERRNO_IS_NOT_SUPPORTED(r
) ? LOG_DEBUG
: LOG_WARNING
,
1697 r
, "Failed to set file attributes on '%s', ignoring: %m", k
);
1699 struct FSSHeader h
= {
1700 .signature
= { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' },
1701 .machine_id
= machine
,
1703 .header_size
= htole64(sizeof(h
)),
1704 .start_usec
= htole64(n
* arg_interval
),
1705 .interval_usec
= htole64(arg_interval
),
1706 .fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
),
1707 .fsprg_state_size
= htole64(state_size
),
1710 r
= loop_write(fd
, &h
, sizeof(h
));
1712 return log_error_errno(r
, "Failed to write header: %m");
1714 r
= loop_write(fd
, state
, state_size
);
1716 return log_error_errno(r
, "Failed to write state: %m");
1718 if (rename(k
, p
) < 0)
1719 return log_error_errno(errno
, "Failed to link file: %m");
1723 _cleanup_free_
char *hn
= NULL
, *key
= NULL
;
1725 r
= format_journal_url(seed
, seed_size
, n
, arg_interval
, hn
, machine
, false, &key
);
1730 hn
= gethostname_malloc();
1732 hostname_cleanup(hn
);
1735 "\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR
".\n"
1737 "The %ssecret sealing key%s has been written to the following local file.\n"
1738 "This key file is automatically updated when the sealing key is advanced.\n"
1739 "It should not be used on multiple hosts.\n"
1743 "The sealing key is automatically changed every %s.\n"
1745 "Please write down the following %ssecret verification key%s. It should be stored\n"
1746 "in a safe location and should not be saved locally on disk.\n"
1748 strempty(hn
), hn
? "/" : "",
1749 SD_ID128_FORMAT_VAL(machine
),
1750 ansi_highlight(), ansi_normal(),
1752 FORMAT_TIMESPAN(arg_interval
, 0),
1753 ansi_highlight(), ansi_normal(),
1754 ansi_highlight_red());
1761 fprintf(stderr
, "%s", ansi_normal());
1763 _cleanup_free_
char *url
= NULL
;
1764 r
= format_journal_url(seed
, seed_size
, n
, arg_interval
, hn
, machine
, true, &url
);
1768 (void) print_qrcode(stderr
,
1769 "To transfer the verification key to your phone scan the QR code below",
1776 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1777 "Forward-secure sealing not available.");
1781 static int verify(sd_journal
*j
, bool verbose
) {
1787 log_show_color(true);
1789 ORDERED_HASHMAP_FOREACH(f
, j
->files
) {
1791 usec_t first
= 0, validated
= 0, last
= 0;
1794 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1795 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1798 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, verbose
);
1800 /* If the key was invalid give up right-away. */
1803 r
= log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1805 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1806 log_full(verbose
? LOG_INFO
: LOG_DEBUG
, "PASS: %s", f
->path
);
1808 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1809 if (validated
> 0) {
1810 log_full(verbose
? LOG_INFO
: LOG_DEBUG
,
1811 "=> Validated from %s to %s, final %s entries not sealed.",
1812 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1813 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1814 FORMAT_TIMESPAN(last
> validated
? last
- validated
: 0, 0));
1815 } else if (last
> 0)
1816 log_full(verbose
? LOG_INFO
: LOG_DEBUG
,
1817 "=> No sealing yet, %s of entries not sealed.",
1818 FORMAT_TIMESPAN(last
- first
, 0));
1820 log_full(verbose
? LOG_INFO
: LOG_DEBUG
,
1821 "=> No sealing yet, no entries in file.");
1829 static int simple_varlink_call(const char *option
, const char *method
) {
1830 _cleanup_(varlink_flush_close_unrefp
) Varlink
*link
= NULL
;
1831 const char *error
, *fn
;
1835 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "%s is not supported in conjunction with --machine=.", option
);
1837 fn
= arg_namespace
?
1838 strjoina("/run/systemd/journal.", arg_namespace
, "/io.systemd.journal") :
1839 "/run/systemd/journal/io.systemd.journal";
1841 r
= varlink_connect_address(&link
, fn
);
1843 return log_error_errno(r
, "Failed to connect to %s: %m", fn
);
1845 (void) varlink_set_description(link
, "journal");
1846 (void) varlink_set_relative_timeout(link
, USEC_INFINITY
);
1848 r
= varlink_call(link
, method
, NULL
, NULL
, &error
, NULL
);
1850 return log_error_errno(r
, "Failed to execute varlink call: %m");
1852 return log_error_errno(SYNTHETIC_ERRNO(ENOANO
),
1853 "Failed to execute varlink call: %s", error
);
1858 static int flush_to_var(void) {
1859 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1860 return 0; /* Already flushed, no need to contact journald */
1861 if (errno
!= ENOENT
)
1862 return log_error_errno(errno
, "Unable to check for existence of /run/systemd/journal/flushed: %m");
1864 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
1867 static int relinquish_var(void) {
1868 return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
1871 static int rotate(void) {
1872 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
1875 static int sync_journal(void) {
1876 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
1879 static int action_list_fields(sd_journal
*j
) {
1886 r
= sd_journal_set_data_threshold(j
, 0);
1888 return log_error_errno(r
, "Failed to unset data size threshold: %m");
1890 r
= sd_journal_query_unique(j
, arg_field
);
1892 return log_error_errno(r
, "Failed to query unique data objects: %m");
1894 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1897 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
1900 eq
= memchr(data
, '=', size
);
1902 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
1904 printf("%.*s\n", (int) size
, (const char*) data
);
1912 static int update_cursor(sd_journal
*j
) {
1913 _cleanup_free_
char *cursor
= NULL
;
1918 if (!arg_show_cursor
&& !arg_cursor_file
)
1921 r
= sd_journal_get_cursor(j
, &cursor
);
1922 if (r
== -EADDRNOTAVAIL
)
1925 return log_error_errno(r
, "Failed to get cursor: %m");
1927 if (arg_show_cursor
)
1928 printf("-- cursor: %s\n", cursor
);
1930 if (arg_cursor_file
) {
1931 r
= write_string_file(arg_cursor_file
, cursor
, WRITE_STRING_FILE_CREATE
| WRITE_STRING_FILE_ATOMIC
);
1933 return log_error_errno(r
, "Failed to write new cursor to %s: %m", arg_cursor_file
);
1939 typedef struct Context
{
1940 sd_journal
*journal
;
1944 bool previous_boot_id_valid
;
1945 sd_id128_t previous_boot_id
;
1946 sd_id128_t previous_boot_id_output
;
1947 dual_timestamp previous_ts_output
;
1950 static int show(Context
*c
) {
1956 j
= ASSERT_PTR(c
->journal
);
1958 while (arg_lines
< 0 || n_shown
< arg_lines
|| arg_follow
) {
1960 size_t highlight
[2] = {};
1963 r
= sd_journal_step_one(j
, !arg_reverse
);
1965 return log_error_errno(r
, "Failed to iterate through journal: %m");
1970 if (arg_until_set
&& !arg_reverse
&& (arg_lines
< 0 || arg_since_set
)) {
1971 /* If --lines= is set, we usually rely on the n_shown to tell us
1972 * when to stop. However, if --since= is set too, we may end up
1973 * having less than --lines= to output. In this case let's also
1974 * check if the entry is in range. */
1978 r
= sd_journal_get_realtime_usec(j
, &usec
);
1980 return log_error_errno(r
, "Failed to determine timestamp: %m");
1981 if (usec
> arg_until
)
1985 if (arg_since_set
&& (arg_reverse
|| !c
->since_seeked
)) {
1988 r
= sd_journal_get_realtime_usec(j
, &usec
);
1990 return log_error_errno(r
, "Failed to determine timestamp: %m");
1992 if (usec
< arg_since
) {
1994 break; /* Reached the earliest entry */
1996 /* arg_lines >= 0 (!since_seeked):
1997 * We jumped arg_lines back and it seems to be too much */
1998 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2000 return log_error_errno(r
, "Failed to seek to date: %m");
2001 c
->since_seeked
= true;
2003 c
->need_seek
= true;
2006 c
->since_seeked
= true; /* We're surely within the range of --since now */
2009 if (!arg_merge
&& !arg_quiet
) {
2012 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2014 if (c
->previous_boot_id_valid
&&
2015 !sd_id128_equal(boot_id
, c
->previous_boot_id
))
2016 printf("%s-- Boot "SD_ID128_FORMAT_STR
" --%s\n",
2017 ansi_highlight(), SD_ID128_FORMAT_VAL(boot_id
), ansi_normal());
2019 c
->previous_boot_id
= boot_id
;
2020 c
->previous_boot_id_valid
= true;
2024 if (arg_compiled_pattern
) {
2025 const void *message
;
2028 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2031 c
->need_seek
= true;
2035 return log_error_errno(r
, "Failed to get MESSAGE field: %m");
2038 assert_se(message
= startswith(message
, "MESSAGE="));
2040 r
= pattern_matches_and_log(arg_compiled_pattern
, message
,
2041 len
- strlen("MESSAGE="), highlight
);
2045 c
->need_seek
= true;
2051 arg_all
* OUTPUT_SHOW_ALL
|
2052 arg_full
* OUTPUT_FULL_WIDTH
|
2053 colors_enabled() * OUTPUT_COLOR
|
2054 arg_catalog
* OUTPUT_CATALOG
|
2055 arg_utc
* OUTPUT_UTC
|
2056 arg_truncate_newline
* OUTPUT_TRUNCATE_NEWLINE
|
2057 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2059 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2060 arg_output_fields
, highlight
, &c
->ellipsized
,
2061 &c
->previous_ts_output
, &c
->previous_boot_id_output
);
2062 c
->need_seek
= true;
2063 if (r
== -EADDRNOTAVAIL
)
2070 /* If journalctl take a long time to process messages, and during that time journal file
2071 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2072 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2073 * in the "following" case. By periodically calling sd_journal_process() during the processing
2074 * loop we shrink the window of time a client instance has open file descriptors for rotated
2075 * (deleted) journal files. */
2076 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2077 r
= sd_journal_process(j
);
2079 return log_error_errno(r
, "Failed to process inotify events: %m");
2086 static int show_and_fflush(Context
*c
, sd_event_source
*s
) {
2094 return sd_event_exit(sd_event_source_get_event(s
), r
);
2100 static int on_journal_event(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
2101 Context
*c
= ASSERT_PTR(userdata
);
2106 r
= sd_journal_process(c
->journal
);
2108 log_error_errno(r
, "Failed to process journal events: %m");
2109 return sd_event_exit(sd_event_source_get_event(s
), r
);
2112 return show_and_fflush(c
, s
);
2115 static int on_first_event(sd_event_source
*s
, void *userdata
) {
2116 return show_and_fflush(userdata
, s
);
2119 static int on_signal(sd_event_source
*s
, const struct signalfd_siginfo
*si
, void *userdata
) {
2122 assert(IN_SET(si
->ssi_signo
, SIGTERM
, SIGINT
));
2124 return sd_event_exit(sd_event_source_get_event(s
), si
->ssi_signo
);
2127 static int setup_event(Context
*c
, int fd
, sd_event
**ret
) {
2128 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
2136 r
= sd_event_default(&e
);
2138 return log_error_errno(r
, "Failed to allocate sd_event object: %m");
2140 (void) sd_event_add_signal(e
, NULL
, SIGTERM
| SD_EVENT_SIGNAL_PROCMASK
, on_signal
, NULL
);
2141 (void) sd_event_add_signal(e
, NULL
, SIGINT
| SD_EVENT_SIGNAL_PROCMASK
, on_signal
, NULL
);
2143 r
= sd_event_add_io(e
, NULL
, fd
, EPOLLIN
, &on_journal_event
, c
);
2145 return log_error_errno(r
, "Failed to add io event source for journal: %m");
2147 /* Also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that, i.e. when it is closed. */
2148 r
= sd_event_add_io(e
, NULL
, STDOUT_FILENO
, EPOLLHUP
|EPOLLERR
, NULL
, INT_TO_PTR(-ECANCELED
));
2150 /* Installing an epoll watch on a regular file doesn't work and fails with EPERM. Which is
2151 * totally OK, handle it gracefully. epoll_ctl() documents EPERM as the error returned when
2152 * the specified fd doesn't support epoll, hence it's safe to check for that. */
2153 log_debug_errno(r
, "Unable to install EPOLLHUP watch on stderr, not watching for hangups.");
2155 return log_error_errno(r
, "Failed to add io event source for stdout: %m");
2157 if (arg_lines
!= 0 || arg_since_set
) {
2158 r
= sd_event_add_defer(e
, NULL
, on_first_event
, c
);
2160 return log_error_errno(r
, "Failed to add defer event source: %m");
2167 static int run(int argc
, char *argv
[]) {
2168 bool need_seek
= false, since_seeked
= false, use_cursor
= false, after_cursor
= false;
2169 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
2170 _cleanup_(umount_and_freep
) char *mounted_dir
= NULL
;
2171 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2172 int n_shown
, r
, poll_fd
= -EBADF
;
2174 setlocale(LC_ALL
, "");
2177 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2178 * split up into many files. */
2179 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
2181 r
= parse_argv(argc
, argv
);
2188 r
= mount_image_privately_interactively(
2191 DISSECT_IMAGE_GENERIC_ROOT
|
2192 DISSECT_IMAGE_REQUIRE_ROOT
|
2193 DISSECT_IMAGE_VALIDATE_OS
|
2194 DISSECT_IMAGE_RELAX_VAR_CHECK
|
2195 (arg_action
== ACTION_UPDATE_CATALOG
? DISSECT_IMAGE_FSCK
|DISSECT_IMAGE_GROWFS
: DISSECT_IMAGE_READ_ONLY
),
2197 /* ret_dir_fd= */ NULL
,
2202 arg_root
= strdup(mounted_dir
);
2207 signal(SIGWINCH
, columns_lines_cache_reset
);
2210 switch (arg_action
) {
2212 case ACTION_NEW_ID128
:
2213 return id128_print_new(ID128_PRINT_PRETTY
);
2215 case ACTION_SETUP_KEYS
:
2216 return setup_keys();
2218 case ACTION_LIST_CATALOG
:
2219 case ACTION_DUMP_CATALOG
:
2220 case ACTION_UPDATE_CATALOG
: {
2221 _cleanup_free_
char *database
= NULL
;
2223 database
= path_join(arg_root
, secure_getenv("SYSTEMD_CATALOG") ?: CATALOG_DATABASE
);
2227 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2230 e
= secure_getenv("SYSTEMD_CATALOG_SOURCES");
2235 e
? (const char* const*) STRV_MAKE(e
) : catalog_file_dirs
);
2237 return log_error_errno(r
, "Failed to list catalog: %m");
2239 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2241 pager_open(arg_pager_flags
);
2244 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2246 r
= catalog_list(stdout
, database
, oneline
);
2248 return log_error_errno(r
, "Failed to list catalog: %m");
2255 return flush_to_var();
2257 case ACTION_RELINQUISH_VAR
:
2258 return relinquish_var();
2261 return sync_journal();
2267 case ACTION_PRINT_HEADER
:
2269 case ACTION_DISK_USAGE
:
2270 case ACTION_LIST_BOOTS
:
2272 case ACTION_ROTATE_AND_VACUUM
:
2273 case ACTION_LIST_FIELDS
:
2274 case ACTION_LIST_FIELD_NAMES
:
2275 /* These ones require access to the journal files, continue below. */
2279 assert_not_reached();
2283 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2285 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2286 else if (arg_file_stdin
)
2287 r
= sd_journal_open_files_fd(&j
, (int[]) { STDIN_FILENO
}, 1, 0);
2289 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2290 else if (arg_machine
)
2291 r
= journal_open_machine(&j
, arg_machine
);
2293 r
= sd_journal_open_namespace(
2296 (arg_merge
? 0 : SD_JOURNAL_LOCAL_ONLY
) |
2297 arg_namespace_flags
| arg_journal_type
);
2299 return log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2301 r
= journal_access_check_and_warn(j
, arg_quiet
,
2302 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2306 switch (arg_action
) {
2308 case ACTION_NEW_ID128
:
2309 case ACTION_SETUP_KEYS
:
2310 case ACTION_LIST_CATALOG
:
2311 case ACTION_DUMP_CATALOG
:
2312 case ACTION_UPDATE_CATALOG
:
2316 assert_not_reached();
2318 case ACTION_PRINT_HEADER
:
2319 journal_print_header(j
);
2323 return verify(j
, !arg_quiet
);
2325 case ACTION_DISK_USAGE
: {
2328 r
= sd_journal_get_usage(j
, &bytes
);
2332 printf("Archived and active journals take up %s in the file system.\n",
2333 FORMAT_BYTES(bytes
));
2338 case ACTION_LIST_BOOTS
:
2339 return list_boots(j
);
2341 case ACTION_ROTATE_AND_VACUUM
:
2349 case ACTION_VACUUM
: {
2353 HASHMAP_FOREACH(d
, j
->directories_by_path
) {
2354 r
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2356 log_error_errno(r
, "Failed to vacuum %s: %m", d
->path
);
2365 case ACTION_LIST_FIELD_NAMES
: {
2368 SD_JOURNAL_FOREACH_FIELD(j
, field
)
2369 printf("%s\n", field
);
2375 case ACTION_LIST_FIELDS
:
2379 assert_not_reached();
2382 if (arg_boot_offset
!= 0 &&
2383 sd_journal_has_runtime_files(j
) > 0 &&
2384 sd_journal_has_persistent_files(j
) == 0) {
2385 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2387 if (arg_action
== ACTION_SHOW
&& arg_compiled_pattern
)
2392 /* add_boot() must be called first!
2393 * It may need to seek the journal to find parent boot IDs. */
2404 return log_error_errno(r
, "Failed to add filter for units: %m");
2406 r
= add_syslog_identifier(j
);
2408 return log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2410 r
= add_priorities(j
);
2414 r
= add_facilities(j
);
2418 r
= add_matches(j
, argv
+ optind
);
2422 if (DEBUG_LOGGING
) {
2423 _cleanup_free_
char *filter
= NULL
;
2425 filter
= journal_make_match_string(j
);
2429 log_debug("Journal filter: %s", filter
);
2432 if (arg_action
== ACTION_LIST_FIELDS
)
2433 return action_list_fields(j
);
2435 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2437 poll_fd
= sd_journal_get_fd(j
);
2438 if (poll_fd
== -EMFILE
) {
2439 log_warning_errno(poll_fd
, "Insufficient watch descriptors available. Reverting to -n.");
2441 } else if (poll_fd
== -EMEDIUMTYPE
)
2442 return log_error_errno(poll_fd
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2443 else if (poll_fd
< 0)
2444 return log_error_errno(poll_fd
, "Failed to get journal fd: %m");
2447 if (arg_cursor
|| arg_after_cursor
|| arg_cursor_file
) {
2448 _cleanup_free_
char *cursor_from_file
= NULL
;
2449 const char *cursor
= arg_cursor
?: arg_after_cursor
;
2451 if (arg_cursor_file
) {
2452 r
= read_one_line_file(arg_cursor_file
, &cursor_from_file
);
2453 if (r
< 0 && r
!= -ENOENT
)
2454 return log_error_errno(r
, "Failed to read cursor file %s: %m", arg_cursor_file
);
2457 cursor
= cursor_from_file
;
2458 after_cursor
= true;
2461 after_cursor
= arg_after_cursor
;
2464 r
= sd_journal_seek_cursor(j
, cursor
);
2466 return log_error_errno(r
, "Failed to seek to cursor: %m");
2474 r
= sd_journal_next_skip(j
, 1 + after_cursor
);
2476 r
= sd_journal_previous_skip(j
, 1 + after_cursor
);
2478 if (after_cursor
&& r
< 2) {
2479 /* We couldn't find the next entry after the cursor. */
2486 } else if (arg_until_set
&& (arg_reverse
|| arg_lines_needs_seek_end())) {
2487 /* If both --until and any of --reverse and --lines=N is specified, things get
2488 * a little tricky. We seek to the place of --until first. If only --reverse or
2489 * --reverse and --lines is specified, we search backwards and let the output
2490 * counter handle --lines for us. If only --lines is used, we just jump backwards
2491 * arg_lines and search afterwards from there. */
2493 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2495 return log_error_errno(r
, "Failed to seek to date: %m");
2498 r
= sd_journal_previous(j
);
2499 else /* arg_lines_needs_seek_end */
2500 r
= sd_journal_previous_skip(j
, arg_lines
);
2502 } else if (arg_reverse
) {
2503 r
= sd_journal_seek_tail(j
);
2505 return log_error_errno(r
, "Failed to seek to tail: %m");
2507 r
= sd_journal_previous(j
);
2509 } else if (arg_lines_needs_seek_end()) {
2510 r
= sd_journal_seek_tail(j
);
2512 return log_error_errno(r
, "Failed to seek to tail: %m");
2514 r
= sd_journal_previous_skip(j
, arg_lines
);
2516 } else if (arg_since_set
) {
2517 /* This is placed after arg_reverse and arg_lines. If --since is used without
2518 * both, we seek to the place of --since and search afterwards from there.
2519 * If used with --reverse or --lines, we seek to the tail first and check if
2520 * the entry is within the range of --since later. */
2522 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2524 return log_error_errno(r
, "Failed to seek to date: %m");
2525 since_seeked
= true;
2527 r
= sd_journal_next(j
);
2530 r
= sd_journal_seek_head(j
);
2532 return log_error_errno(r
, "Failed to seek to head: %m");
2534 r
= sd_journal_next(j
);
2537 return log_error_errno(r
, "Failed to iterate through journal: %m");
2542 pager_open(arg_pager_flags
);
2544 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
) && DEBUG_LOGGING
) {
2546 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2548 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2550 return log_error_errno(r
, "Failed to get cutoff: %m");
2553 printf("-- Journal begins at %s. --\n",
2554 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2556 printf("-- Journal begins at %s, ends at %s. --\n",
2557 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2558 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2564 .need_seek
= need_seek
,
2565 .since_seeked
= since_seeked
,
2569 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
2572 assert(poll_fd
>= 0);
2574 r
= setup_event(&c
, poll_fd
, &e
);
2578 r
= sd_event_loop(e
);
2583 /* unref signal event sources. */
2584 e
= sd_event_unref(e
);
2586 r
= update_cursor(j
);
2590 /* re-send the original signal. */
2591 assert(SIGNAL_VALID(sig
));
2593 log_error("Failed to raise the original signal SIG%s, ignoring: %m", signal_to_string(sig
));
2603 if (n_shown
== 0 && !arg_quiet
)
2604 printf("-- No entries --\n");
2606 r
= update_cursor(j
);
2610 if (arg_compiled_pattern
&& n_shown
== 0)
2611 /* --grep was used, no error was thrown, but the pattern didn't
2612 * match anything. Let's mimic grep's behavior here and return
2613 * a non-zero exit code, so journalctl --grep can be used
2614 * in scripts and such */
2620 DEFINE_MAIN_FUNCTION(run
);