1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include <sys/inotify.h>
20 # define PCRE2_CODE_UNIT_WIDTH 8
25 #include "sd-device.h"
26 #include "sd-journal.h"
29 #include "alloc-util.h"
30 #include "bus-error.h"
33 #include "chattr-util.h"
35 #include "device-private.h"
38 #include "format-util.h"
41 #include "glob-util.h"
42 #include "hostname-util.h"
43 #include "id128-print.h"
45 #include "journal-def.h"
46 #include "journal-internal.h"
47 #include "journal-qrcode.h"
48 #include "journal-util.h"
49 #include "journal-vacuum.h"
50 #include "journal-verify.h"
51 #include "locale-util.h"
53 #include "logs-show.h"
54 #include "memory-util.h"
56 #include "mountpoint-util.h"
57 #include "nulstr-util.h"
59 #include "parse-util.h"
60 #include "path-util.h"
61 #include "pretty-print.h"
62 #include "rlimit-util.h"
65 #include "string-table.h"
67 #include "syslog-util.h"
68 #include "terminal-util.h"
69 #include "tmpfile-util.h"
70 #include "unit-name.h"
71 #include "user-util.h"
74 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
76 #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
79 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data
*, pcre2_match_data_free
);
80 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code
*, pcre2_code_free
);
82 static int pattern_compile(const char *pattern
, unsigned flags
, pcre2_code
**out
) {
84 PCRE2_SIZE erroroffset
;
87 p
= pcre2_compile((PCRE2_SPTR8
) pattern
,
88 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
90 unsigned char buf
[LINE_MAX
];
92 r
= pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
94 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
95 "Bad pattern \"%s\": %s", pattern
,
96 r
< 0 ? "unknown error" : (char *)buf
);
106 /* Special values for arg_lines */
107 ARG_LINES_DEFAULT
= -2,
111 static OutputMode arg_output
= OUTPUT_SHORT
;
112 static bool arg_utc
= false;
113 static bool arg_follow
= false;
114 static bool arg_full
= true;
115 static bool arg_all
= false;
116 static PagerFlags arg_pager_flags
= 0;
117 static int arg_lines
= ARG_LINES_DEFAULT
;
118 static bool arg_no_tail
= false;
119 static bool arg_quiet
= false;
120 static bool arg_merge
= false;
121 static bool arg_boot
= false;
122 static sd_id128_t arg_boot_id
= {};
123 static int arg_boot_offset
= 0;
124 static bool arg_dmesg
= false;
125 static bool arg_no_hostname
= false;
126 static const char *arg_cursor
= NULL
;
127 static const char *arg_cursor_file
= NULL
;
128 static const char *arg_after_cursor
= NULL
;
129 static bool arg_show_cursor
= false;
130 static const char *arg_directory
= NULL
;
131 static char **arg_file
= NULL
;
132 static bool arg_file_stdin
= false;
133 static int arg_priorities
= 0xFF;
134 static char *arg_verify_key
= NULL
;
136 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
137 static bool arg_force
= false;
139 static usec_t arg_since
, arg_until
;
140 static bool arg_since_set
= false, arg_until_set
= false;
141 static char **arg_syslog_identifier
= NULL
;
142 static char **arg_system_units
= NULL
;
143 static char **arg_user_units
= NULL
;
144 static const char *arg_field
= NULL
;
145 static bool arg_catalog
= false;
146 static bool arg_reverse
= false;
147 static int arg_journal_type
= 0;
148 static char *arg_root
= NULL
;
149 static const char *arg_machine
= NULL
;
150 static uint64_t arg_vacuum_size
= 0;
151 static uint64_t arg_vacuum_n_files
= 0;
152 static usec_t arg_vacuum_time
= 0;
153 static char **arg_output_fields
= NULL
;
156 static const char *arg_pattern
= NULL
;
157 static pcre2_code
*arg_compiled_pattern
= NULL
;
158 static int arg_case_sensitive
= -1; /* -1 means be smart */
170 ACTION_UPDATE_CATALOG
,
173 ACTION_RELINQUISH_VAR
,
177 ACTION_ROTATE_AND_VACUUM
,
179 ACTION_LIST_FIELD_NAMES
,
180 } arg_action
= ACTION_SHOW
;
182 typedef struct BootId
{
186 LIST_FIELDS(struct BootId
, boot_list
);
189 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
190 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
198 if (!path_startswith(devpath
, "/dev/")) {
199 log_error("Devpath does not start with /dev/");
203 if (stat(devpath
, &st
) < 0)
204 return log_error_errno(errno
, "Couldn't stat file: %m");
206 r
= device_new_from_stat_rdev(&device
, &st
);
208 return log_error_errno(r
, "Failed to get device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
210 for (d
= device
; d
; ) {
211 _cleanup_free_
char *match
= NULL
;
212 const char *subsys
, *sysname
, *devnode
;
215 r
= sd_device_get_subsystem(d
, &subsys
);
219 r
= sd_device_get_sysname(d
, &sysname
);
223 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
227 r
= sd_journal_add_match(j
, match
, 0);
229 return log_error_errno(r
, "Failed to add match: %m");
231 if (sd_device_get_devname(d
, &devnode
) >= 0) {
232 _cleanup_free_
char *match1
= NULL
;
234 r
= stat(devnode
, &st
);
236 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
238 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
242 r
= sd_journal_add_match(j
, match1
, 0);
244 return log_error_errno(r
, "Failed to add match: %m");
248 if (sd_device_get_parent(d
, &parent
) < 0)
254 r
= add_match_this_boot(j
, arg_machine
);
256 return log_error_errno(r
, "Failed to add match for the current boot: %m");
261 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
264 return format_timestamp_utc(buf
, l
, t
);
266 return format_timestamp(buf
, l
, t
);
269 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
270 sd_id128_t id
= SD_ID128_NULL
;
273 if (streq(x
, "all")) {
274 *boot_id
= SD_ID128_NULL
;
277 } else if (strlen(x
) >= 32) {
281 r
= sd_id128_from_string(t
, &id
);
285 if (!IN_SET(*x
, 0, '-', '+'))
289 r
= safe_atoi(x
, &off
);
294 r
= safe_atoi(x
, &off
);
308 static int help(void) {
309 _cleanup_free_
char *link
= NULL
;
312 (void) pager_open(arg_pager_flags
);
314 r
= terminal_urlify_man("journalctl", "1", &link
);
318 printf("%s [OPTIONS...] [MATCHES...]\n\n"
319 "Query the journal.\n\n"
321 " --system Show the system journal\n"
322 " --user Show the user journal for the current user\n"
323 " -M --machine=CONTAINER Operate on local container\n"
324 " -S --since=DATE Show entries not older than the specified date\n"
325 " -U --until=DATE Show entries not newer than the specified date\n"
326 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
327 " --after-cursor=CURSOR Show entries after the specified cursor\n"
328 " --show-cursor Print the cursor after all the entries\n"
329 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
330 " -b --boot[=ID] Show current boot or the specified boot\n"
331 " --list-boots Show terse information about recorded boots\n"
332 " -k --dmesg Show kernel message log from the current boot\n"
333 " -u --unit=UNIT Show logs from the specified unit\n"
334 " --user-unit=UNIT Show logs from the specified user unit\n"
335 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
336 " -p --priority=RANGE Show entries with the specified priority\n"
337 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
338 " --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n"
339 " -e --pager-end Immediately jump to the end in the pager\n"
340 " -f --follow Follow the journal\n"
341 " -n --lines[=INTEGER] Number of journal entries to show\n"
342 " --no-tail Show all lines, even in follow mode\n"
343 " -r --reverse Show the newest entries first\n"
344 " -o --output=STRING Change journal output mode (short, short-precise,\n"
345 " short-iso, short-iso-precise, short-full,\n"
346 " short-monotonic, short-unix, verbose, export,\n"
347 " json, json-pretty, json-sse, json-seq, cat,\n"
349 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
350 " --utc Express time in Coordinated Universal Time (UTC)\n"
351 " -x --catalog Add message explanations where available\n"
352 " --no-full Ellipsize fields\n"
353 " -a --all Show all fields, including long and unprintable\n"
354 " -q --quiet Do not show info messages and privilege warning\n"
355 " --no-pager Do not pipe output into a pager\n"
356 " --no-hostname Suppress output of hostname field\n"
357 " -m --merge Show entries from all available journals\n"
358 " -D --directory=PATH Show journal files from directory\n"
359 " --file=PATH Show journal file\n"
360 " --root=ROOT Operate on files below a root directory\n"
361 " --interval=TIME Time interval for changing the FSS sealing key\n"
362 " --verify-key=KEY Specify FSS verification key\n"
363 " --force Override of the FSS key pair with --setup-keys\n"
365 " -h --help Show this help text\n"
366 " --version Show package version\n"
367 " -N --fields List all field names currently used\n"
368 " -F --field=FIELD List all values that a specified field takes\n"
369 " --disk-usage Show total disk usage of all journal files\n"
370 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
371 " --vacuum-files=INT Leave only the specified number of journal files\n"
372 " --vacuum-time=TIME Remove journal files older than specified time\n"
373 " --verify Verify journal file consistency\n"
374 " --sync Synchronize unwritten journal messages to disk\n"
375 " --relinquish-var Stop logging to disk, log to temporary file system\n"
376 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
377 " --flush Flush all journal data from /run into /var\n"
378 " --rotate Request immediate rotation of the journal files\n"
379 " --header Show journal header information\n"
380 " --list-catalog Show all message IDs in the catalog\n"
381 " --dump-catalog Show entries in the message catalog\n"
382 " --update-catalog Update the message catalog database\n"
383 " --setup-keys Generate a new FSS key pair\n"
384 "\nSee the %s for details.\n"
385 , program_invocation_short_name
392 static int parse_argv(int argc
, char *argv
[]) {
425 ARG_SMART_RELINQUISH_VAR
,
434 static const struct option options
[] = {
435 { "help", no_argument
, NULL
, 'h' },
436 { "version" , no_argument
, NULL
, ARG_VERSION
},
437 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
438 { "pager-end", no_argument
, NULL
, 'e' },
439 { "follow", no_argument
, NULL
, 'f' },
440 { "force", no_argument
, NULL
, ARG_FORCE
},
441 { "output", required_argument
, NULL
, 'o' },
442 { "all", no_argument
, NULL
, 'a' },
443 { "full", no_argument
, NULL
, 'l' },
444 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
445 { "lines", optional_argument
, NULL
, 'n' },
446 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
447 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
448 { "quiet", no_argument
, NULL
, 'q' },
449 { "merge", no_argument
, NULL
, 'm' },
450 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
451 { "boot", optional_argument
, NULL
, 'b' },
452 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
453 { "dmesg", no_argument
, NULL
, 'k' },
454 { "system", no_argument
, NULL
, ARG_SYSTEM
},
455 { "user", no_argument
, NULL
, ARG_USER
},
456 { "directory", required_argument
, NULL
, 'D' },
457 { "file", required_argument
, NULL
, ARG_FILE
},
458 { "root", required_argument
, NULL
, ARG_ROOT
},
459 { "header", no_argument
, NULL
, ARG_HEADER
},
460 { "identifier", required_argument
, NULL
, 't' },
461 { "priority", required_argument
, NULL
, 'p' },
462 { "grep", required_argument
, NULL
, 'g' },
463 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
464 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
465 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
466 { "verify", no_argument
, NULL
, ARG_VERIFY
},
467 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
468 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
469 { "cursor", required_argument
, NULL
, 'c' },
470 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
471 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
472 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
473 { "since", required_argument
, NULL
, 'S' },
474 { "until", required_argument
, NULL
, 'U' },
475 { "unit", required_argument
, NULL
, 'u' },
476 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
477 { "field", required_argument
, NULL
, 'F' },
478 { "fields", no_argument
, NULL
, 'N' },
479 { "catalog", no_argument
, NULL
, 'x' },
480 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
481 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
482 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
483 { "reverse", no_argument
, NULL
, 'r' },
484 { "machine", required_argument
, NULL
, 'M' },
485 { "utc", no_argument
, NULL
, ARG_UTC
},
486 { "flush", no_argument
, NULL
, ARG_FLUSH
},
487 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
488 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
489 { "sync", no_argument
, NULL
, ARG_SYNC
},
490 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
491 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
492 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
493 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
494 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
495 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
504 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
515 arg_pager_flags
|= PAGER_DISABLE
;
519 arg_pager_flags
|= PAGER_JUMP_TO_END
;
521 if (arg_lines
== ARG_LINES_DEFAULT
)
531 if (streq(optarg
, "help")) {
532 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
536 arg_output
= output_mode_from_string(optarg
);
537 if (arg_output
< 0) {
538 log_error("Unknown output format '%s'.", optarg
);
542 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
561 if (streq(optarg
, "all"))
562 arg_lines
= ARG_LINES_ALL
;
564 r
= safe_atoi(optarg
, &arg_lines
);
565 if (r
< 0 || arg_lines
< 0) {
566 log_error("Failed to parse lines '%s'", optarg
);
573 /* Hmm, no argument? Maybe the next
574 * word on the command line is
575 * supposed to be the argument? Let's
576 * see if there is one, and is
580 if (streq(argv
[optind
], "all")) {
581 arg_lines
= ARG_LINES_ALL
;
583 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
597 arg_action
= ACTION_NEW_ID128
;
610 arg_boot_id
= SD_ID128_NULL
;
616 arg_boot_id
= SD_ID128_NULL
;
620 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
622 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
626 /* Hmm, no argument? Maybe the next
627 * word on the command line is
628 * supposed to be the argument? Let's
629 * see if there is one and is parsable
630 * as a boot descriptor... */
631 } else if (optind
< argc
) {
632 r
= parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
641 arg_action
= ACTION_LIST_BOOTS
;
645 arg_boot
= arg_dmesg
= true;
649 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
653 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
657 arg_machine
= optarg
;
661 arg_directory
= optarg
;
665 if (streq(optarg
, "-"))
666 /* An undocumented feature: we can read journal files from STDIN. We don't document
667 * this though, since after all we only support this for mmap-able, seekable files, and
668 * not for example pipes which are probably the primary usecase for reading things from
669 * STDIN. To avoid confusion we hence don't document this feature. */
670 arg_file_stdin
= true;
672 r
= glob_extend(&arg_file
, optarg
);
674 return log_error_errno(r
, "Failed to add paths: %m");
679 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
688 case ARG_CURSOR_FILE
:
689 arg_cursor_file
= optarg
;
692 case ARG_AFTER_CURSOR
:
693 arg_after_cursor
= optarg
;
696 case ARG_SHOW_CURSOR
:
697 arg_show_cursor
= true;
701 arg_action
= ACTION_PRINT_HEADER
;
705 arg_action
= ACTION_VERIFY
;
709 arg_action
= ACTION_DISK_USAGE
;
712 case ARG_VACUUM_SIZE
:
713 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
715 log_error("Failed to parse vacuum size: %s", optarg
);
719 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
722 case ARG_VACUUM_FILES
:
723 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
725 log_error("Failed to parse vacuum files: %s", optarg
);
729 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
732 case ARG_VACUUM_TIME
:
733 r
= parse_sec(optarg
, &arg_vacuum_time
);
735 log_error("Failed to parse vacuum time: %s", optarg
);
739 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
748 arg_action
= ACTION_SETUP_KEYS
;
752 arg_action
= ACTION_VERIFY
;
753 r
= free_and_strdup(&arg_verify_key
, optarg
);
756 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
757 * in ps or htop output. */
758 memset(optarg
, 'x', strlen(optarg
));
764 r
= parse_sec(optarg
, &arg_interval
);
765 if (r
< 0 || arg_interval
<= 0) {
766 log_error("Failed to parse sealing key change interval: %s", optarg
);
775 log_error("Compiled without forward-secure sealing support.");
782 dots
= strstr(optarg
, "..");
788 a
= strndup(optarg
, dots
- optarg
);
792 from
= log_level_from_string(a
);
793 to
= log_level_from_string(dots
+ 2);
796 if (from
< 0 || to
< 0) {
797 log_error("Failed to parse log level range %s", optarg
);
804 for (i
= from
; i
<= to
; i
++)
805 arg_priorities
|= 1 << i
;
807 for (i
= to
; i
<= from
; i
++)
808 arg_priorities
|= 1 << i
;
814 p
= log_level_from_string(optarg
);
816 log_error("Unknown log level %s", optarg
);
822 for (i
= 0; i
<= p
; i
++)
823 arg_priorities
|= 1 << i
;
831 arg_pattern
= optarg
;
834 case ARG_CASE_SENSITIVE
:
836 r
= parse_boolean(optarg
);
838 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
839 arg_case_sensitive
= r
;
841 arg_case_sensitive
= true;
846 case ARG_CASE_SENSITIVE
:
847 return log_error("Compiled without pattern matching support");
851 r
= parse_timestamp(optarg
, &arg_since
);
853 log_error("Failed to parse timestamp: %s", optarg
);
856 arg_since_set
= true;
860 r
= parse_timestamp(optarg
, &arg_until
);
862 log_error("Failed to parse timestamp: %s", optarg
);
865 arg_until_set
= true;
869 r
= strv_extend(&arg_syslog_identifier
, optarg
);
875 r
= strv_extend(&arg_system_units
, optarg
);
881 r
= strv_extend(&arg_user_units
, optarg
);
887 arg_action
= ACTION_LIST_FIELDS
;
892 arg_action
= ACTION_LIST_FIELD_NAMES
;
895 case ARG_NO_HOSTNAME
:
896 arg_no_hostname
= true;
903 case ARG_LIST_CATALOG
:
904 arg_action
= ACTION_LIST_CATALOG
;
907 case ARG_DUMP_CATALOG
:
908 arg_action
= ACTION_DUMP_CATALOG
;
911 case ARG_UPDATE_CATALOG
:
912 arg_action
= ACTION_UPDATE_CATALOG
;
924 arg_action
= ACTION_FLUSH
;
927 case ARG_SMART_RELINQUISH_VAR
: {
928 int root_mnt_id
, log_mnt_id
;
930 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
931 * if it's on the same mount as the root file system there's no point in
932 * relinquishing access and we can leave journald write to it until the very last
935 r
= path_get_mnt_id("/", &root_mnt_id
);
937 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
939 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
941 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
942 else if (root_mnt_id
== log_mnt_id
) {
943 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
946 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
952 case ARG_RELINQUISH_VAR
:
953 arg_action
= ACTION_RELINQUISH_VAR
;
957 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
961 arg_action
= ACTION_SYNC
;
964 case ARG_OUTPUT_FIELDS
: {
965 _cleanup_strv_free_
char **v
= NULL
;
967 v
= strv_split(optarg
, ",");
971 if (!arg_output_fields
)
972 arg_output_fields
= TAKE_PTR(v
);
974 r
= strv_extend_strv(&arg_output_fields
, v
, true);
985 assert_not_reached("Unhandled option");
988 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
991 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
> 1) {
992 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
996 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
997 log_error("--since= must be before --until=.");
1001 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
1002 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
1006 if (arg_follow
&& arg_reverse
) {
1007 log_error("Please specify either --reverse= or --follow=, not both.");
1011 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
1012 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
1016 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
1017 log_error("Using --boot or --list-boots with --merge is not supported.");
1021 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
1022 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1023 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1024 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1025 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
1029 arg_system_units
= strv_free(arg_system_units
);
1036 if (arg_case_sensitive
>= 0)
1037 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
1039 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
1041 _cleanup_(pcre2_code_freep
) pcre2_code
*cs
= NULL
;
1043 md
= pcre2_match_data_create(1, NULL
);
1047 r
= pattern_compile("[[:upper:]]", 0, &cs
);
1051 r
= pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
1054 flags
= !has_case
* PCRE2_CASELESS
;
1057 log_debug("Doing case %s matching based on %s",
1058 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
1059 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
1061 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1070 static int add_matches(sd_journal
*j
, char **args
) {
1072 bool have_term
= false;
1076 STRV_FOREACH(i
, args
) {
1079 if (streq(*i
, "+")) {
1082 r
= sd_journal_add_disjunction(j
);
1085 } else if (path_is_absolute(*i
)) {
1086 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1089 r
= chase_symlinks(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
);
1091 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1093 if (lstat(p
, &st
) < 0)
1094 return log_error_errno(errno
, "Couldn't stat file: %m");
1096 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1097 if (executable_is_script(p
, &interpreter
) > 0) {
1098 _cleanup_free_
char *comm
;
1100 comm
= strndup(basename(p
), 15);
1104 t
= strappend("_COMM=", comm
);
1108 /* Append _EXE only if the interpreter is not a link.
1109 Otherwise, it might be outdated often. */
1110 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1111 t2
= strappend("_EXE=", interpreter
);
1116 t
= strappend("_EXE=", p
);
1121 r
= sd_journal_add_match(j
, t
, 0);
1124 r
= sd_journal_add_match(j
, t2
, 0);
1126 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1127 r
= add_matches_for_device(j
, p
);
1131 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1132 "File is neither a device node, nor regular file, nor executable: %s",
1137 r
= sd_journal_add_match(j
, *i
, 0);
1142 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1145 if (!strv_isempty(args
) && !have_term
)
1146 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1147 "\"+\" can only be used between terms");
1152 static void boot_id_free_all(BootId
*l
) {
1156 LIST_REMOVE(boot_list
, l
, i
);
1161 static int discover_next_boot(sd_journal
*j
,
1162 sd_id128_t previous_boot_id
,
1166 _cleanup_free_ BootId
*next_boot
= NULL
;
1167 char match
[9+32+1] = "_BOOT_ID=";
1174 /* We expect the journal to be on the last position of a boot
1175 * (in relation to the direction we are going), so that the next
1176 * invocation of sd_journal_next/previous will be from a different
1177 * boot. We then collect any information we desire and then jump
1178 * to the last location of the new boot by using a _BOOT_ID match
1179 * coming from the other journal direction. */
1181 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1182 * we can actually advance to a *different* boot. */
1183 sd_journal_flush_matches(j
);
1187 r
= sd_journal_previous(j
);
1189 r
= sd_journal_next(j
);
1193 return 0; /* End of journal, yay. */
1195 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1199 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1200 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1201 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1202 * complete than the main entry array, and hence might reference an entry that's not actually the last
1203 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1204 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1207 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1209 next_boot
= new0(BootId
, 1);
1213 next_boot
->id
= boot_id
;
1215 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1219 /* Now seek to the last occurrence of this boot ID. */
1220 sd_id128_to_string(next_boot
->id
, match
+ 9);
1221 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1226 r
= sd_journal_seek_head(j
);
1228 r
= sd_journal_seek_tail(j
);
1233 r
= sd_journal_next(j
);
1235 r
= sd_journal_previous(j
);
1239 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA
),
1240 "Whoopsie! We found a boot ID but can't read its last entry."); /* This shouldn't happen. We just came from this very boot ID. */
1242 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1246 *ret
= TAKE_PTR(next_boot
);
1251 static int get_boots(
1254 sd_id128_t
*boot_id
,
1259 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1260 const bool advance_older
= boot_id
&& offset
<= 0;
1261 sd_id128_t previous_boot_id
;
1265 /* Adjust for the asymmetry that offset 0 is
1266 * the last (and current) boot, while 1 is considered the
1267 * (chronological) first boot in the journal. */
1268 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1270 /* Advance to the earliest/latest occurrence of our reference
1271 * boot ID (taking our lookup direction into account), so that
1272 * discover_next_boot() can do its job.
1273 * If no reference is given, the journal head/tail will do,
1274 * they're "virtual" boots after all. */
1275 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1276 char match
[9+32+1] = "_BOOT_ID=";
1278 sd_journal_flush_matches(j
);
1280 sd_id128_to_string(*boot_id
, match
+ 9);
1281 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1286 r
= sd_journal_seek_head(j
); /* seek to oldest */
1288 r
= sd_journal_seek_tail(j
); /* seek to newest */
1293 r
= sd_journal_next(j
); /* read the oldest entry */
1295 r
= sd_journal_previous(j
); /* read the most recently added entry */
1300 else if (offset
== 0) {
1305 /* At this point the read pointer is positioned at the oldest/newest occurrence of the reference boot
1306 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1307 * the following entry, which must then have an older/newer boot ID */
1311 r
= sd_journal_seek_tail(j
); /* seek to newest */
1313 r
= sd_journal_seek_head(j
); /* seek to oldest */
1317 /* No sd_journal_next()/_previous() here.
1319 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1320 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1324 previous_boot_id
= SD_ID128_NULL
;
1326 _cleanup_free_ BootId
*current
= NULL
;
1328 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1330 boot_id_free_all(head
);
1337 previous_boot_id
= current
->id
;
1341 offset
+= advance_older
? 1 : -1;
1346 *boot_id
= current
->id
;
1350 LIST_FOREACH(boot_list
, id
, head
) {
1351 if (sd_id128_equal(id
->id
, current
->id
)) {
1352 /* boot id already stored, something wrong with the journal files */
1353 /* exiting as otherwise this problem would cause forever loop */
1357 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1358 tail
= TAKE_PTR(current
);
1367 sd_journal_flush_matches(j
);
1372 static int list_boots(sd_journal
*j
) {
1374 BootId
*id
, *all_ids
;
1378 count
= get_boots(j
, &all_ids
, NULL
, 0);
1380 return log_error_errno(count
, "Failed to determine boots: %m");
1384 (void) pager_open(arg_pager_flags
);
1386 /* numbers are one less, but we need an extra char for the sign */
1387 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1390 LIST_FOREACH(boot_list
, id
, all_ids
) {
1391 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1393 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1395 SD_ID128_FORMAT_VAL(id
->id
),
1396 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1397 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1401 boot_id_free_all(all_ids
);
1406 static int add_boot(sd_journal
*j
) {
1407 char match
[9+32+1] = "_BOOT_ID=";
1416 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1417 * We can do this only when we logs are coming from the current machine,
1418 * so take the slow path if log location is specified. */
1419 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1420 !arg_directory
&& !arg_file
&& !arg_root
)
1422 return add_match_this_boot(j
, arg_machine
);
1424 boot_id
= arg_boot_id
;
1425 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1428 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror_safe(r
);
1430 if (sd_id128_is_null(arg_boot_id
))
1431 log_error("Data from the specified boot (%+i) is not available: %s",
1432 arg_boot_offset
, reason
);
1434 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1435 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1437 return r
== 0 ? -ENODATA
: r
;
1440 sd_id128_to_string(boot_id
, match
+ 9);
1442 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1444 return log_error_errno(r
, "Failed to add match: %m");
1446 r
= sd_journal_add_conjunction(j
);
1448 return log_error_errno(r
, "Failed to add conjunction: %m");
1453 static int add_dmesg(sd_journal
*j
) {
1460 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1461 STRLEN("_TRANSPORT=kernel"));
1463 return log_error_errno(r
, "Failed to add match: %m");
1465 r
= sd_journal_add_conjunction(j
);
1467 return log_error_errno(r
, "Failed to add conjunction: %m");
1472 static int get_possible_units(
1478 _cleanup_set_free_free_ Set
*found
;
1482 found
= set_new(&string_hash_ops
);
1486 NULSTR_FOREACH(field
, fields
) {
1490 r
= sd_journal_query_unique(j
, field
);
1494 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1495 char **pattern
, *eq
;
1497 _cleanup_free_
char *u
= NULL
;
1499 eq
= memchr(data
, '=', size
);
1501 prefix
= eq
- (char*) data
+ 1;
1505 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1509 STRV_FOREACH(pattern
, patterns
)
1510 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1511 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1513 r
= set_consume(found
, u
);
1515 if (r
< 0 && r
!= -EEXIST
)
1523 *units
= TAKE_PTR(found
);
1528 /* This list is supposed to return the superset of unit names
1529 * possibly matched by rules added with add_matches_for_unit... */
1530 #define SYSTEM_UNITS \
1534 "OBJECT_SYSTEMD_UNIT\0" \
1537 /* ... and add_matches_for_user_unit */
1538 #define USER_UNITS \
1539 "_SYSTEMD_USER_UNIT\0" \
1541 "COREDUMP_USER_UNIT\0" \
1542 "OBJECT_SYSTEMD_USER_UNIT\0"
1544 static int add_units(sd_journal
*j
) {
1545 _cleanup_strv_free_
char **patterns
= NULL
;
1551 STRV_FOREACH(i
, arg_system_units
) {
1552 _cleanup_free_
char *u
= NULL
;
1554 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1558 if (string_is_glob(u
)) {
1559 r
= strv_push(&patterns
, u
);
1564 r
= add_matches_for_unit(j
, u
);
1567 r
= sd_journal_add_disjunction(j
);
1574 if (!strv_isempty(patterns
)) {
1575 _cleanup_set_free_free_ Set
*units
= NULL
;
1579 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1583 SET_FOREACH(u
, units
, it
) {
1584 r
= add_matches_for_unit(j
, u
);
1587 r
= sd_journal_add_disjunction(j
);
1594 patterns
= strv_free(patterns
);
1596 STRV_FOREACH(i
, arg_user_units
) {
1597 _cleanup_free_
char *u
= NULL
;
1599 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1603 if (string_is_glob(u
)) {
1604 r
= strv_push(&patterns
, u
);
1609 r
= add_matches_for_user_unit(j
, u
, getuid());
1612 r
= sd_journal_add_disjunction(j
);
1619 if (!strv_isempty(patterns
)) {
1620 _cleanup_set_free_free_ Set
*units
= NULL
;
1624 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1628 SET_FOREACH(u
, units
, it
) {
1629 r
= add_matches_for_user_unit(j
, u
, getuid());
1632 r
= sd_journal_add_disjunction(j
);
1639 /* Complain if the user request matches but nothing whatsoever was
1640 * found, since otherwise everything would be matched. */
1641 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1644 r
= sd_journal_add_conjunction(j
);
1651 static int add_priorities(sd_journal
*j
) {
1652 char match
[] = "PRIORITY=0";
1656 if (arg_priorities
== 0xFF)
1659 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1660 if (arg_priorities
& (1 << i
)) {
1661 match
[sizeof(match
)-2] = '0' + i
;
1663 r
= sd_journal_add_match(j
, match
, strlen(match
));
1665 return log_error_errno(r
, "Failed to add match: %m");
1668 r
= sd_journal_add_conjunction(j
);
1670 return log_error_errno(r
, "Failed to add conjunction: %m");
1675 static int add_syslog_identifier(sd_journal
*j
) {
1681 STRV_FOREACH(i
, arg_syslog_identifier
) {
1682 _cleanup_free_
char *u
= NULL
;
1684 u
= strjoin("SYSLOG_IDENTIFIER=", *i
);
1687 r
= sd_journal_add_match(j
, u
, 0);
1690 r
= sd_journal_add_disjunction(j
);
1695 r
= sd_journal_add_conjunction(j
);
1702 static int setup_keys(void) {
1704 size_t mpk_size
, seed_size
, state_size
, i
;
1705 uint8_t *mpk
, *seed
, *state
;
1707 sd_id128_t machine
, boot
;
1708 char *p
= NULL
, *k
= NULL
;
1713 r
= stat("/var/log/journal", &st
);
1714 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1715 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1717 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1718 log_error("%s is not a directory, must be using persistent logging for FSS.",
1719 "/var/log/journal");
1720 return r
< 0 ? -errno
: -ENOTDIR
;
1723 r
= sd_id128_get_machine(&machine
);
1725 return log_error_errno(r
, "Failed to get machine ID: %m");
1727 r
= sd_id128_get_boot(&boot
);
1729 return log_error_errno(r
, "Failed to get boot ID: %m");
1731 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1732 SD_ID128_FORMAT_VAL(machine
)) < 0)
1737 if (r
< 0 && errno
!= ENOENT
) {
1738 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1741 } else if (access(p
, F_OK
) >= 0) {
1742 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1747 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1748 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1753 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1754 mpk
= alloca(mpk_size
);
1756 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1757 seed
= alloca(seed_size
);
1759 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1760 state
= alloca(state_size
);
1762 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1764 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1768 log_info("Generating seed...");
1769 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1771 log_error_errno(r
, "Failed to read random seed: %m");
1775 log_info("Generating key pair...");
1776 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1778 log_info("Generating sealing key...");
1779 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1781 assert(arg_interval
> 0);
1783 n
= now(CLOCK_REALTIME
);
1787 fd
= mkostemp_safe(k
);
1789 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1793 /* Enable secure remove, exclusion from dump, synchronous
1794 * writing and in-place updating */
1795 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
, NULL
);
1797 log_warning_errno(r
, "Failed to set file attributes: %m");
1800 memcpy(h
.signature
, "KSHHRHLP", 8);
1801 h
.machine_id
= machine
;
1803 h
.header_size
= htole64(sizeof(h
));
1804 h
.start_usec
= htole64(n
* arg_interval
);
1805 h
.interval_usec
= htole64(arg_interval
);
1806 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1807 h
.fsprg_state_size
= htole64(state_size
);
1809 r
= loop_write(fd
, &h
, sizeof(h
), false);
1811 log_error_errno(r
, "Failed to write header: %m");
1815 r
= loop_write(fd
, state
, state_size
, false);
1817 log_error_errno(r
, "Failed to write state: %m");
1821 if (link(k
, p
) < 0) {
1822 r
= log_error_errno(errno
, "Failed to link file: %m");
1829 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1830 "the following local file. This key file is automatically updated when the\n"
1831 "sealing key is advanced. It should not be used on multiple hosts.\n"
1835 "Please write down the following %ssecret verification key%s. It should be stored\n"
1836 "at a safe location and should not be saved locally on disk.\n"
1838 ansi_highlight(), ansi_normal(),
1840 ansi_highlight(), ansi_normal(),
1841 ansi_highlight_red());
1844 for (i
= 0; i
< seed_size
; i
++) {
1845 if (i
> 0 && i
% 3 == 0)
1847 printf("%02x", ((uint8_t*) seed
)[i
]);
1850 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1853 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1857 "The sealing key is automatically changed every %s.\n",
1859 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1861 hn
= gethostname_malloc();
1864 hostname_cleanup(hn
);
1865 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1867 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1870 /* If this is not an UTF-8 system don't print any QR codes */
1871 if (is_locale_utf8()) {
1872 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1873 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1893 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1894 "Forward-secure sealing not available.");
1898 static int verify(sd_journal
*j
) {
1905 log_show_color(true);
1907 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1909 usec_t first
= 0, validated
= 0, last
= 0;
1912 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1913 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1916 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1918 /* If the key was invalid give up right-away. */
1921 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1924 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1925 log_info("PASS: %s", f
->path
);
1927 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1928 if (validated
> 0) {
1929 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1930 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1931 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1932 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1933 } else if (last
> 0)
1934 log_info("=> No sealing yet, %s of entries not sealed.",
1935 format_timespan(c
, sizeof(c
), last
- first
, 0));
1937 log_info("=> No sealing yet, no entries in file.");
1945 static int simple_varlink_call(const char *option
, const char *method
) {
1946 _cleanup_(varlink_flush_close_unrefp
) Varlink
*link
= NULL
;
1951 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "%s is not supported in conjunction with --machine=.", option
);
1953 r
= varlink_connect_address(&link
, "/run/systemd/journal/io.systemd.journal");
1955 return log_error_errno(r
, "Failed to connect to /run/systemd/journal/io.systemd.journal: %m");
1957 (void) varlink_set_description(link
, "journal");
1958 (void) varlink_set_relative_timeout(link
, USEC_INFINITY
);
1960 r
= varlink_call(link
, method
, NULL
, NULL
, &error
, NULL
);
1962 return log_error_errno(r
, "Failed to execute varlink call: %m");
1964 return log_error_errno(SYNTHETIC_ERRNO(ENOANO
),
1965 "Failed to execute varlink call: %s", error
);
1970 static int flush_to_var(void) {
1971 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
1974 static int relinquish_var(void) {
1975 return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
1978 static int rotate(void) {
1979 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
1982 static int sync_journal(void) {
1983 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
1986 static int wait_for_change(sd_journal
*j
, int poll_fd
) {
1987 struct pollfd pollfds
[] = {
1988 { .fd
= poll_fd
, .events
= POLLIN
},
1989 { .fd
= STDOUT_FILENO
},
1997 assert(poll_fd
>= 0);
1999 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
2000 * i.e. when it is closed. */
2002 r
= sd_journal_get_timeout(j
, &timeout
);
2004 return log_error_errno(r
, "Failed to determine journal waiting time: %m");
2006 if (ppoll(pollfds
, ELEMENTSOF(pollfds
),
2007 timeout
== USEC_INFINITY
? NULL
: timespec_store(&ts
, timeout
), NULL
) < 0) {
2011 return log_error_errno(errno
, "Couldn't wait for journal event: %m");
2014 if (pollfds
[1].revents
& (POLLHUP
|POLLERR
)) /* STDOUT has been closed? */
2015 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED
),
2016 "Standard output has been closed.");
2018 r
= sd_journal_process(j
);
2020 return log_error_errno(r
, "Failed to process journal events: %m");
2025 int main(int argc
, char *argv
[]) {
2026 bool previous_boot_id_valid
= false, first_line
= true, ellipsized
= false, need_seek
= false;
2027 bool use_cursor
= false, after_cursor
= false;
2028 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2029 sd_id128_t previous_boot_id
;
2030 int n_shown
= 0, r
, poll_fd
= -1;
2032 setlocale(LC_ALL
, "");
2033 log_show_color(true);
2034 log_parse_environment();
2037 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2038 * split up into many files. */
2039 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
2041 r
= parse_argv(argc
, argv
);
2045 signal(SIGWINCH
, columns_lines_cache_reset
);
2048 switch (arg_action
) {
2050 case ACTION_NEW_ID128
:
2051 r
= id128_print_new(true);
2054 case ACTION_SETUP_KEYS
:
2058 case ACTION_LIST_CATALOG
:
2059 case ACTION_DUMP_CATALOG
:
2060 case ACTION_UPDATE_CATALOG
: {
2061 _cleanup_free_
char *database
;
2063 database
= path_join(arg_root
, CATALOG_DATABASE
);
2069 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2070 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2072 log_error_errno(r
, "Failed to list catalog: %m");
2074 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2076 (void) pager_open(arg_pager_flags
);
2079 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2081 r
= catalog_list(stdout
, database
, oneline
);
2083 log_error_errno(r
, "Failed to list catalog: %m");
2093 case ACTION_RELINQUISH_VAR
:
2094 r
= relinquish_var();
2106 case ACTION_PRINT_HEADER
:
2108 case ACTION_DISK_USAGE
:
2109 case ACTION_LIST_BOOTS
:
2111 case ACTION_ROTATE_AND_VACUUM
:
2112 case ACTION_LIST_FIELDS
:
2113 case ACTION_LIST_FIELD_NAMES
:
2114 /* These ones require access to the journal files, continue below. */
2118 assert_not_reached("Unknown action");
2122 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2124 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2125 else if (arg_file_stdin
) {
2126 int ifd
= STDIN_FILENO
;
2127 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2128 } else if (arg_file
)
2129 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2130 else if (arg_machine
) {
2131 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2132 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2133 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2136 if (geteuid() != 0) {
2137 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2138 * the container, thus we need root privileges to override them. */
2139 log_error("Using the --machine= switch requires root privileges.");
2144 r
= sd_bus_open_system(&bus
);
2146 log_error_errno(r
, "Failed to open system bus: %m");
2150 r
= sd_bus_call_method(
2152 "org.freedesktop.machine1",
2153 "/org/freedesktop/machine1",
2154 "org.freedesktop.machine1.Manager",
2155 "OpenMachineRootDirectory",
2160 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2164 r
= sd_bus_message_read(reply
, "h", &fd
);
2166 bus_log_parse_error(r
);
2170 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2172 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2176 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2180 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2182 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2186 r
= journal_access_check_and_warn(j
, arg_quiet
,
2187 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2191 switch (arg_action
) {
2193 case ACTION_NEW_ID128
:
2194 case ACTION_SETUP_KEYS
:
2195 case ACTION_LIST_CATALOG
:
2196 case ACTION_DUMP_CATALOG
:
2197 case ACTION_UPDATE_CATALOG
:
2201 assert_not_reached("Unexpected action.");
2203 case ACTION_PRINT_HEADER
:
2204 journal_print_header(j
);
2212 case ACTION_DISK_USAGE
: {
2214 char sbytes
[FORMAT_BYTES_MAX
];
2216 r
= sd_journal_get_usage(j
, &bytes
);
2220 printf("Archived and active journals take up %s in the file system.\n",
2221 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2225 case ACTION_LIST_BOOTS
:
2229 case ACTION_ROTATE_AND_VACUUM
:
2237 case ACTION_VACUUM
: {
2241 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2247 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2249 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2257 case ACTION_LIST_FIELD_NAMES
: {
2260 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2261 printf("%s\n", field
);
2270 case ACTION_LIST_FIELDS
:
2274 assert_not_reached("Unknown action");
2277 if (arg_boot_offset
!= 0 &&
2278 sd_journal_has_runtime_files(j
) > 0 &&
2279 sd_journal_has_persistent_files(j
) == 0) {
2280 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2284 /* add_boot() must be called first!
2285 * It may need to seek the journal to find parent boot IDs. */
2296 log_error_errno(r
, "Failed to add filter for units: %m");
2300 r
= add_syslog_identifier(j
);
2302 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2306 r
= add_priorities(j
);
2310 r
= add_matches(j
, argv
+ optind
);
2314 if (DEBUG_LOGGING
) {
2315 _cleanup_free_
char *filter
;
2317 filter
= journal_make_match_string(j
);
2321 log_debug("Journal filter: %s", filter
);
2324 if (arg_action
== ACTION_LIST_FIELDS
) {
2330 r
= sd_journal_set_data_threshold(j
, 0);
2332 log_error_errno(r
, "Failed to unset data size threshold: %m");
2336 r
= sd_journal_query_unique(j
, arg_field
);
2338 log_error_errno(r
, "Failed to query unique data objects: %m");
2342 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2345 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2348 eq
= memchr(data
, '=', size
);
2350 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2352 printf("%.*s\n", (int) size
, (const char*) data
);
2361 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2363 poll_fd
= sd_journal_get_fd(j
);
2364 if (poll_fd
== -EMFILE
) {
2365 log_warning_errno(poll_fd
, "Insufficient watch descriptors available. Reverting to -n.");
2367 } else if (poll_fd
== -EMEDIUMTYPE
) {
2368 log_error_errno(poll_fd
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2370 } else if (poll_fd
< 0) {
2371 log_error_errno(poll_fd
, "Failed to get journal fd: %m");
2376 if (arg_cursor
|| arg_after_cursor
|| arg_cursor_file
) {
2377 _cleanup_free_
char *cursor_from_file
= NULL
;
2378 const char *cursor
= arg_cursor
?: arg_after_cursor
;
2380 if (arg_cursor_file
) {
2381 r
= read_one_line_file(arg_cursor_file
, &cursor_from_file
);
2382 if (r
< 0 && r
!= -ENOENT
) {
2383 log_error_errno(r
, "Failed to read cursor file %s: %m", arg_cursor_file
);
2388 cursor
= cursor_from_file
;
2389 after_cursor
= true;
2392 after_cursor
= !!arg_after_cursor
;
2395 r
= sd_journal_seek_cursor(j
, cursor
);
2397 log_error_errno(r
, "Failed to seek to cursor: %m");
2406 r
= sd_journal_next_skip(j
, 1 + after_cursor
);
2408 r
= sd_journal_previous_skip(j
, 1 + after_cursor
);
2410 if (after_cursor
&& r
< 2) {
2411 /* We couldn't find the next entry after the cursor. */
2418 } else if (arg_since_set
&& !arg_reverse
) {
2419 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2421 log_error_errno(r
, "Failed to seek to date: %m");
2424 r
= sd_journal_next(j
);
2426 } else if (arg_until_set
&& arg_reverse
) {
2427 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2429 log_error_errno(r
, "Failed to seek to date: %m");
2432 r
= sd_journal_previous(j
);
2434 } else if (arg_lines
>= 0) {
2435 r
= sd_journal_seek_tail(j
);
2437 log_error_errno(r
, "Failed to seek to tail: %m");
2441 r
= sd_journal_previous_skip(j
, arg_lines
);
2443 } else if (arg_reverse
) {
2444 r
= sd_journal_seek_tail(j
);
2446 log_error_errno(r
, "Failed to seek to tail: %m");
2450 r
= sd_journal_previous(j
);
2453 r
= sd_journal_seek_head(j
);
2455 log_error_errno(r
, "Failed to seek to head: %m");
2459 r
= sd_journal_next(j
);
2463 log_error_errno(r
, "Failed to iterate through journal: %m");
2470 (void) pager_open(arg_pager_flags
);
2472 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2474 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2476 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2478 log_error_errno(r
, "Failed to get cutoff: %m");
2484 printf("-- Logs begin at %s. --\n",
2485 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2487 printf("-- Logs begin at %s, end at %s. --\n",
2488 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2489 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2494 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2496 size_t highlight
[2] = {};
2500 r
= sd_journal_next(j
);
2502 r
= sd_journal_previous(j
);
2504 log_error_errno(r
, "Failed to iterate through journal: %m");
2511 if (arg_until_set
&& !arg_reverse
) {
2514 r
= sd_journal_get_realtime_usec(j
, &usec
);
2516 log_error_errno(r
, "Failed to determine timestamp: %m");
2519 if (usec
> arg_until
)
2523 if (arg_since_set
&& arg_reverse
) {
2526 r
= sd_journal_get_realtime_usec(j
, &usec
);
2528 log_error_errno(r
, "Failed to determine timestamp: %m");
2531 if (usec
< arg_since
)
2535 if (!arg_merge
&& !arg_quiet
) {
2538 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2540 if (previous_boot_id_valid
&&
2541 !sd_id128_equal(boot_id
, previous_boot_id
))
2542 printf("%s-- Reboot --%s\n",
2543 ansi_highlight(), ansi_normal());
2545 previous_boot_id
= boot_id
;
2546 previous_boot_id_valid
= true;
2551 if (arg_compiled_pattern
) {
2552 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2553 const void *message
;
2557 md
= pcre2_match_data_create(1, NULL
);
2561 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2568 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2572 assert_se(message
= startswith(message
, "MESSAGE="));
2574 r
= pcre2_match(arg_compiled_pattern
,
2576 len
- strlen("MESSAGE="),
2577 0, /* start at offset 0 in the subject */
2578 0, /* default options */
2581 if (r
== PCRE2_ERROR_NOMATCH
) {
2586 unsigned char buf
[LINE_MAX
];
2589 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2590 log_error("Pattern matching failed: %s",
2591 r2
< 0 ? "unknown error" : (char*) buf
);
2596 ovec
= pcre2_get_ovector_pointer(md
);
2597 highlight
[0] = ovec
[0];
2598 highlight
[1] = ovec
[1];
2603 arg_all
* OUTPUT_SHOW_ALL
|
2604 arg_full
* OUTPUT_FULL_WIDTH
|
2605 colors_enabled() * OUTPUT_COLOR
|
2606 arg_catalog
* OUTPUT_CATALOG
|
2607 arg_utc
* OUTPUT_UTC
|
2608 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2610 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2611 arg_output_fields
, highlight
, &ellipsized
);
2613 if (r
== -EADDRNOTAVAIL
)
2620 /* If journalctl take a long time to process messages, and during that time journal file
2621 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2622 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2623 * in the "following" case. By periodically calling sd_journal_process() during the processing
2624 * loop we shrink the window of time a client instance has open file descriptors for rotated
2625 * (deleted) journal files. */
2626 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2627 r
= sd_journal_process(j
);
2629 log_error_errno(r
, "Failed to process inotify events: %m");
2636 if (n_shown
== 0 && !arg_quiet
)
2637 printf("-- No entries --\n");
2639 if (arg_show_cursor
|| arg_cursor_file
) {
2640 _cleanup_free_
char *cursor
= NULL
;
2642 r
= sd_journal_get_cursor(j
, &cursor
);
2643 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2644 log_error_errno(r
, "Failed to get cursor: %m");
2646 if (arg_show_cursor
)
2647 printf("-- cursor: %s\n", cursor
);
2649 if (arg_cursor_file
) {
2650 r
= write_string_file(arg_cursor_file
, cursor
,
2651 WRITE_STRING_FILE_CREATE
|
2652 WRITE_STRING_FILE_ATOMIC
);
2655 "Failed to write new cursor to %s: %m",
2666 r
= wait_for_change(j
, poll_fd
);
2677 strv_free(arg_file
);
2679 strv_free(arg_syslog_identifier
);
2680 strv_free(arg_system_units
);
2681 strv_free(arg_user_units
);
2682 strv_free(arg_output_fields
);
2685 free(arg_verify_key
);
2688 if (arg_compiled_pattern
) {
2689 pcre2_code_free(arg_compiled_pattern
);
2691 /* --grep was used, no error was thrown, but the pattern didn't
2692 * match anything. Let's mimic grep's behavior here and return
2693 * a non-zero exit code, so journalctl --grep can be used
2694 * in scripts and such */
2695 if (r
== 0 && n_shown
== 0)
2700 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;