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 string_erase 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(-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
) {
1684 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1685 r
= sd_journal_add_match(j
, u
, 0);
1688 r
= sd_journal_add_disjunction(j
);
1693 r
= sd_journal_add_conjunction(j
);
1700 static int setup_keys(void) {
1702 size_t mpk_size
, seed_size
, state_size
, i
;
1703 uint8_t *mpk
, *seed
, *state
;
1705 sd_id128_t machine
, boot
;
1706 char *p
= NULL
, *k
= NULL
;
1711 r
= stat("/var/log/journal", &st
);
1712 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1713 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1715 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1716 log_error("%s is not a directory, must be using persistent logging for FSS.",
1717 "/var/log/journal");
1718 return r
< 0 ? -errno
: -ENOTDIR
;
1721 r
= sd_id128_get_machine(&machine
);
1723 return log_error_errno(r
, "Failed to get machine ID: %m");
1725 r
= sd_id128_get_boot(&boot
);
1727 return log_error_errno(r
, "Failed to get boot ID: %m");
1729 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1730 SD_ID128_FORMAT_VAL(machine
)) < 0)
1735 if (r
< 0 && errno
!= ENOENT
) {
1736 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1739 } else if (access(p
, F_OK
) >= 0) {
1740 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1745 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1746 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1751 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1752 mpk
= alloca(mpk_size
);
1754 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1755 seed
= alloca(seed_size
);
1757 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1758 state
= alloca(state_size
);
1760 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1762 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1766 log_info("Generating seed...");
1767 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1769 log_error_errno(r
, "Failed to read random seed: %m");
1773 log_info("Generating key pair...");
1774 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1776 log_info("Generating sealing key...");
1777 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1779 assert(arg_interval
> 0);
1781 n
= now(CLOCK_REALTIME
);
1785 fd
= mkostemp_safe(k
);
1787 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1791 /* Enable secure remove, exclusion from dump, synchronous
1792 * writing and in-place updating */
1793 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
);
1795 log_warning_errno(r
, "Failed to set file attributes: %m");
1798 memcpy(h
.signature
, "KSHHRHLP", 8);
1799 h
.machine_id
= machine
;
1801 h
.header_size
= htole64(sizeof(h
));
1802 h
.start_usec
= htole64(n
* arg_interval
);
1803 h
.interval_usec
= htole64(arg_interval
);
1804 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1805 h
.fsprg_state_size
= htole64(state_size
);
1807 r
= loop_write(fd
, &h
, sizeof(h
), false);
1809 log_error_errno(r
, "Failed to write header: %m");
1813 r
= loop_write(fd
, state
, state_size
, false);
1815 log_error_errno(r
, "Failed to write state: %m");
1819 if (link(k
, p
) < 0) {
1820 r
= log_error_errno(errno
, "Failed to link file: %m");
1827 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1828 "the following local file. This key file is automatically updated when the\n"
1829 "sealing key is advanced. It should not be used on multiple hosts.\n"
1833 "Please write down the following %ssecret verification key%s. It should be stored\n"
1834 "at a safe location and should not be saved locally on disk.\n"
1836 ansi_highlight(), ansi_normal(),
1838 ansi_highlight(), ansi_normal(),
1839 ansi_highlight_red());
1842 for (i
= 0; i
< seed_size
; i
++) {
1843 if (i
> 0 && i
% 3 == 0)
1845 printf("%02x", ((uint8_t*) seed
)[i
]);
1848 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1851 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1855 "The sealing key is automatically changed every %s.\n",
1857 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1859 hn
= gethostname_malloc();
1862 hostname_cleanup(hn
);
1863 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1865 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1868 /* If this is not an UTF-8 system don't print any QR codes */
1869 if (is_locale_utf8()) {
1870 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1871 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1891 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1892 "Forward-secure sealing not available.");
1896 static int verify(sd_journal
*j
) {
1903 log_show_color(true);
1905 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1907 usec_t first
= 0, validated
= 0, last
= 0;
1910 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1911 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1914 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1916 /* If the key was invalid give up right-away. */
1919 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1922 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1923 log_info("PASS: %s", f
->path
);
1925 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1926 if (validated
> 0) {
1927 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1928 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1929 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1930 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1931 } else if (last
> 0)
1932 log_info("=> No sealing yet, %s of entries not sealed.",
1933 format_timespan(c
, sizeof(c
), last
- first
, 0));
1935 log_info("=> No sealing yet, no entries in file.");
1943 static int simple_varlink_call(const char *option
, const char *method
) {
1944 _cleanup_(varlink_flush_close_unrefp
) Varlink
*link
= NULL
;
1949 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "%s is not supported in conjunction with --machine=.", option
);
1951 r
= varlink_connect_address(&link
, "/run/systemd/journal/io.systemd.journal");
1953 return log_error_errno(r
, "Failed to connect to /run/systemd/journal/io.systemd.journal: %m");
1955 (void) varlink_set_description(link
, "journal");
1956 (void) varlink_set_relative_timeout(link
, USEC_INFINITY
);
1958 r
= varlink_call(link
, method
, NULL
, NULL
, &error
, NULL
);
1960 return log_error_errno(r
, "Failed to execute varlink call: %m");
1962 return log_error_errno(SYNTHETIC_ERRNO(ENOANO
),
1963 "Failed to execute varlink call: %s", error
);
1968 static int flush_to_var(void) {
1969 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
1972 static int relinquish_var(void) {
1973 return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
1976 static int rotate(void) {
1977 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
1980 static int sync_journal(void) {
1981 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
1984 static int wait_for_change(sd_journal
*j
, int poll_fd
) {
1985 struct pollfd pollfds
[] = {
1986 { .fd
= poll_fd
, .events
= POLLIN
},
1987 { .fd
= STDOUT_FILENO
},
1995 assert(poll_fd
>= 0);
1997 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
1998 * i.e. when it is closed. */
2000 r
= sd_journal_get_timeout(j
, &timeout
);
2002 return log_error_errno(r
, "Failed to determine journal waiting time: %m");
2004 if (ppoll(pollfds
, ELEMENTSOF(pollfds
),
2005 timeout
== USEC_INFINITY
? NULL
: timespec_store(&ts
, timeout
), NULL
) < 0) {
2009 return log_error_errno(errno
, "Couldn't wait for journal event: %m");
2012 if (pollfds
[1].revents
& (POLLHUP
|POLLERR
)) /* STDOUT has been closed? */
2013 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED
),
2014 "Standard output has been closed.");
2016 r
= sd_journal_process(j
);
2018 return log_error_errno(r
, "Failed to process journal events: %m");
2023 int main(int argc
, char *argv
[]) {
2024 bool previous_boot_id_valid
= false, first_line
= true, ellipsized
= false, need_seek
= false;
2025 bool use_cursor
= false, after_cursor
= false;
2026 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2027 sd_id128_t previous_boot_id
;
2028 int n_shown
= 0, r
, poll_fd
= -1;
2030 setlocale(LC_ALL
, "");
2031 log_show_color(true);
2032 log_parse_environment();
2035 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2036 * split up into many files. */
2037 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
2039 r
= parse_argv(argc
, argv
);
2043 signal(SIGWINCH
, columns_lines_cache_reset
);
2046 switch (arg_action
) {
2048 case ACTION_NEW_ID128
:
2049 r
= id128_print_new(true);
2052 case ACTION_SETUP_KEYS
:
2056 case ACTION_LIST_CATALOG
:
2057 case ACTION_DUMP_CATALOG
:
2058 case ACTION_UPDATE_CATALOG
: {
2059 _cleanup_free_
char *database
;
2061 database
= path_join(arg_root
, CATALOG_DATABASE
);
2067 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2068 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2070 log_error_errno(r
, "Failed to list catalog: %m");
2072 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2074 (void) pager_open(arg_pager_flags
);
2077 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2079 r
= catalog_list(stdout
, database
, oneline
);
2081 log_error_errno(r
, "Failed to list catalog: %m");
2091 case ACTION_RELINQUISH_VAR
:
2092 r
= relinquish_var();
2104 case ACTION_PRINT_HEADER
:
2106 case ACTION_DISK_USAGE
:
2107 case ACTION_LIST_BOOTS
:
2109 case ACTION_ROTATE_AND_VACUUM
:
2110 case ACTION_LIST_FIELDS
:
2111 case ACTION_LIST_FIELD_NAMES
:
2112 /* These ones require access to the journal files, continue below. */
2116 assert_not_reached("Unknown action");
2120 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2122 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2123 else if (arg_file_stdin
) {
2124 int ifd
= STDIN_FILENO
;
2125 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2126 } else if (arg_file
)
2127 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2128 else if (arg_machine
) {
2129 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2130 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2131 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2134 if (geteuid() != 0) {
2135 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2136 * the container, thus we need root privileges to override them. */
2137 log_error("Using the --machine= switch requires root privileges.");
2142 r
= sd_bus_open_system(&bus
);
2144 log_error_errno(r
, "Failed to open system bus: %m");
2148 r
= sd_bus_call_method(
2150 "org.freedesktop.machine1",
2151 "/org/freedesktop/machine1",
2152 "org.freedesktop.machine1.Manager",
2153 "OpenMachineRootDirectory",
2158 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2162 r
= sd_bus_message_read(reply
, "h", &fd
);
2164 bus_log_parse_error(r
);
2168 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2170 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2174 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2178 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2180 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2184 r
= journal_access_check_and_warn(j
, arg_quiet
,
2185 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2189 switch (arg_action
) {
2191 case ACTION_NEW_ID128
:
2192 case ACTION_SETUP_KEYS
:
2193 case ACTION_LIST_CATALOG
:
2194 case ACTION_DUMP_CATALOG
:
2195 case ACTION_UPDATE_CATALOG
:
2199 assert_not_reached("Unexpected action.");
2201 case ACTION_PRINT_HEADER
:
2202 journal_print_header(j
);
2210 case ACTION_DISK_USAGE
: {
2212 char sbytes
[FORMAT_BYTES_MAX
];
2214 r
= sd_journal_get_usage(j
, &bytes
);
2218 printf("Archived and active journals take up %s in the file system.\n",
2219 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2223 case ACTION_LIST_BOOTS
:
2227 case ACTION_ROTATE_AND_VACUUM
:
2235 case ACTION_VACUUM
: {
2239 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2245 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2247 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2255 case ACTION_LIST_FIELD_NAMES
: {
2258 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2259 printf("%s\n", field
);
2268 case ACTION_LIST_FIELDS
:
2272 assert_not_reached("Unknown action");
2275 if (arg_boot_offset
!= 0 &&
2276 sd_journal_has_runtime_files(j
) > 0 &&
2277 sd_journal_has_persistent_files(j
) == 0) {
2278 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2282 /* add_boot() must be called first!
2283 * It may need to seek the journal to find parent boot IDs. */
2294 log_error_errno(r
, "Failed to add filter for units: %m");
2298 r
= add_syslog_identifier(j
);
2300 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2304 r
= add_priorities(j
);
2308 r
= add_matches(j
, argv
+ optind
);
2312 if (DEBUG_LOGGING
) {
2313 _cleanup_free_
char *filter
;
2315 filter
= journal_make_match_string(j
);
2319 log_debug("Journal filter: %s", filter
);
2322 if (arg_action
== ACTION_LIST_FIELDS
) {
2328 r
= sd_journal_set_data_threshold(j
, 0);
2330 log_error_errno(r
, "Failed to unset data size threshold: %m");
2334 r
= sd_journal_query_unique(j
, arg_field
);
2336 log_error_errno(r
, "Failed to query unique data objects: %m");
2340 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2343 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2346 eq
= memchr(data
, '=', size
);
2348 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2350 printf("%.*s\n", (int) size
, (const char*) data
);
2359 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2361 poll_fd
= sd_journal_get_fd(j
);
2362 if (poll_fd
== -EMFILE
) {
2363 log_warning_errno(poll_fd
, "Insufficient watch descriptors available. Reverting to -n.");
2365 } else if (poll_fd
== -EMEDIUMTYPE
) {
2366 log_error_errno(poll_fd
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2368 } else if (poll_fd
< 0) {
2369 log_error_errno(poll_fd
, "Failed to get journal fd: %m");
2374 if (arg_cursor
|| arg_after_cursor
|| arg_cursor_file
) {
2375 _cleanup_free_
char *cursor_from_file
= NULL
;
2376 const char *cursor
= arg_cursor
?: arg_after_cursor
;
2378 if (arg_cursor_file
) {
2379 r
= read_one_line_file(arg_cursor_file
, &cursor_from_file
);
2380 if (r
< 0 && r
!= -ENOENT
) {
2381 log_error_errno(r
, "Failed to read cursor file %s: %m", arg_cursor_file
);
2386 cursor
= cursor_from_file
;
2387 after_cursor
= true;
2390 after_cursor
= !!arg_after_cursor
;
2393 r
= sd_journal_seek_cursor(j
, cursor
);
2395 log_error_errno(r
, "Failed to seek to cursor: %m");
2404 r
= sd_journal_next_skip(j
, 1 + after_cursor
);
2406 r
= sd_journal_previous_skip(j
, 1 + after_cursor
);
2408 if (after_cursor
&& r
< 2) {
2409 /* We couldn't find the next entry after the cursor. */
2416 } else if (arg_since_set
&& !arg_reverse
) {
2417 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2419 log_error_errno(r
, "Failed to seek to date: %m");
2422 r
= sd_journal_next(j
);
2424 } else if (arg_until_set
&& arg_reverse
) {
2425 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2427 log_error_errno(r
, "Failed to seek to date: %m");
2430 r
= sd_journal_previous(j
);
2432 } else if (arg_lines
>= 0) {
2433 r
= sd_journal_seek_tail(j
);
2435 log_error_errno(r
, "Failed to seek to tail: %m");
2439 r
= sd_journal_previous_skip(j
, arg_lines
);
2441 } else if (arg_reverse
) {
2442 r
= sd_journal_seek_tail(j
);
2444 log_error_errno(r
, "Failed to seek to tail: %m");
2448 r
= sd_journal_previous(j
);
2451 r
= sd_journal_seek_head(j
);
2453 log_error_errno(r
, "Failed to seek to head: %m");
2457 r
= sd_journal_next(j
);
2461 log_error_errno(r
, "Failed to iterate through journal: %m");
2468 (void) pager_open(arg_pager_flags
);
2470 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2472 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2474 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2476 log_error_errno(r
, "Failed to get cutoff: %m");
2482 printf("-- Logs begin at %s. --\n",
2483 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2485 printf("-- Logs begin at %s, end at %s. --\n",
2486 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2487 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2492 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2494 size_t highlight
[2] = {};
2498 r
= sd_journal_next(j
);
2500 r
= sd_journal_previous(j
);
2502 log_error_errno(r
, "Failed to iterate through journal: %m");
2509 if (arg_until_set
&& !arg_reverse
) {
2512 r
= sd_journal_get_realtime_usec(j
, &usec
);
2514 log_error_errno(r
, "Failed to determine timestamp: %m");
2517 if (usec
> arg_until
)
2521 if (arg_since_set
&& arg_reverse
) {
2524 r
= sd_journal_get_realtime_usec(j
, &usec
);
2526 log_error_errno(r
, "Failed to determine timestamp: %m");
2529 if (usec
< arg_since
)
2533 if (!arg_merge
&& !arg_quiet
) {
2536 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2538 if (previous_boot_id_valid
&&
2539 !sd_id128_equal(boot_id
, previous_boot_id
))
2540 printf("%s-- Reboot --%s\n",
2541 ansi_highlight(), ansi_normal());
2543 previous_boot_id
= boot_id
;
2544 previous_boot_id_valid
= true;
2549 if (arg_compiled_pattern
) {
2550 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2551 const void *message
;
2555 md
= pcre2_match_data_create(1, NULL
);
2559 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2566 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2570 assert_se(message
= startswith(message
, "MESSAGE="));
2572 r
= pcre2_match(arg_compiled_pattern
,
2574 len
- strlen("MESSAGE="),
2575 0, /* start at offset 0 in the subject */
2576 0, /* default options */
2579 if (r
== PCRE2_ERROR_NOMATCH
) {
2584 unsigned char buf
[LINE_MAX
];
2587 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2588 log_error("Pattern matching failed: %s",
2589 r2
< 0 ? "unknown error" : (char*) buf
);
2594 ovec
= pcre2_get_ovector_pointer(md
);
2595 highlight
[0] = ovec
[0];
2596 highlight
[1] = ovec
[1];
2601 arg_all
* OUTPUT_SHOW_ALL
|
2602 arg_full
* OUTPUT_FULL_WIDTH
|
2603 colors_enabled() * OUTPUT_COLOR
|
2604 arg_catalog
* OUTPUT_CATALOG
|
2605 arg_utc
* OUTPUT_UTC
|
2606 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2608 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2609 arg_output_fields
, highlight
, &ellipsized
);
2611 if (r
== -EADDRNOTAVAIL
)
2618 /* If journalctl take a long time to process messages, and during that time journal file
2619 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2620 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2621 * in the "following" case. By periodically calling sd_journal_process() during the processing
2622 * loop we shrink the window of time a client instance has open file descriptors for rotated
2623 * (deleted) journal files. */
2624 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2625 r
= sd_journal_process(j
);
2627 log_error_errno(r
, "Failed to process inotify events: %m");
2634 if (n_shown
== 0 && !arg_quiet
)
2635 printf("-- No entries --\n");
2637 if (arg_show_cursor
|| arg_cursor_file
) {
2638 _cleanup_free_
char *cursor
= NULL
;
2640 r
= sd_journal_get_cursor(j
, &cursor
);
2641 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2642 log_error_errno(r
, "Failed to get cursor: %m");
2644 if (arg_show_cursor
)
2645 printf("-- cursor: %s\n", cursor
);
2647 if (arg_cursor_file
) {
2648 r
= write_string_file(arg_cursor_file
, cursor
,
2649 WRITE_STRING_FILE_CREATE
|
2650 WRITE_STRING_FILE_ATOMIC
);
2653 "Failed to write new cursor to %s: %m",
2664 r
= wait_for_change(j
, poll_fd
);
2675 strv_free(arg_file
);
2677 strv_free(arg_syslog_identifier
);
2678 strv_free(arg_system_units
);
2679 strv_free(arg_user_units
);
2680 strv_free(arg_output_fields
);
2683 free(arg_verify_key
);
2686 if (arg_compiled_pattern
) {
2687 pcre2_code_free(arg_compiled_pattern
);
2689 /* --grep was used, no error was thrown, but the pattern didn't
2690 * match anything. Let's mimic grep's behavior here and return
2691 * a non-zero exit code, so journalctl --grep can be used
2692 * in scripts and such */
2693 if (r
== 0 && n_shown
== 0)
2698 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;