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"
40 #include "glob-util.h"
41 #include "hostname-util.h"
42 #include "id128-print.h"
44 #include "journal-def.h"
45 #include "journal-internal.h"
46 #include "journal-qrcode.h"
47 #include "journal-util.h"
48 #include "journal-vacuum.h"
49 #include "journal-verify.h"
50 #include "locale-util.h"
52 #include "logs-show.h"
53 #include "memory-util.h"
55 #include "mountpoint-util.h"
56 #include "nulstr-util.h"
58 #include "parse-util.h"
59 #include "path-util.h"
60 #include "pretty-print.h"
61 #include "rlimit-util.h"
64 #include "string-table.h"
66 #include "syslog-util.h"
67 #include "terminal-util.h"
68 #include "tmpfile-util.h"
69 #include "unit-name.h"
70 #include "user-util.h"
73 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
75 #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
78 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data
*, pcre2_match_data_free
);
79 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code
*, pcre2_code_free
);
81 static int pattern_compile(const char *pattern
, unsigned flags
, pcre2_code
**out
) {
83 PCRE2_SIZE erroroffset
;
86 p
= pcre2_compile((PCRE2_SPTR8
) pattern
,
87 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
89 unsigned char buf
[LINE_MAX
];
91 r
= pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
93 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
94 "Bad pattern \"%s\": %s", pattern
,
95 r
< 0 ? "unknown error" : (char *)buf
);
105 /* Special values for arg_lines */
106 ARG_LINES_DEFAULT
= -2,
110 static OutputMode arg_output
= OUTPUT_SHORT
;
111 static bool arg_utc
= false;
112 static bool arg_follow
= false;
113 static bool arg_full
= true;
114 static bool arg_all
= false;
115 static PagerFlags arg_pager_flags
= 0;
116 static int arg_lines
= ARG_LINES_DEFAULT
;
117 static bool arg_no_tail
= false;
118 static bool arg_quiet
= false;
119 static bool arg_merge
= false;
120 static bool arg_boot
= false;
121 static sd_id128_t arg_boot_id
= {};
122 static int arg_boot_offset
= 0;
123 static bool arg_dmesg
= false;
124 static bool arg_no_hostname
= false;
125 static const char *arg_cursor
= NULL
;
126 static const char *arg_cursor_file
= NULL
;
127 static const char *arg_after_cursor
= NULL
;
128 static bool arg_show_cursor
= false;
129 static const char *arg_directory
= NULL
;
130 static char **arg_file
= NULL
;
131 static bool arg_file_stdin
= false;
132 static int arg_priorities
= 0xFF;
133 static char *arg_verify_key
= NULL
;
135 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
136 static bool arg_force
= false;
138 static usec_t arg_since
, arg_until
;
139 static bool arg_since_set
= false, arg_until_set
= false;
140 static char **arg_syslog_identifier
= NULL
;
141 static char **arg_system_units
= NULL
;
142 static char **arg_user_units
= NULL
;
143 static const char *arg_field
= NULL
;
144 static bool arg_catalog
= false;
145 static bool arg_reverse
= false;
146 static int arg_journal_type
= 0;
147 static char *arg_root
= NULL
;
148 static const char *arg_machine
= NULL
;
149 static uint64_t arg_vacuum_size
= 0;
150 static uint64_t arg_vacuum_n_files
= 0;
151 static usec_t arg_vacuum_time
= 0;
152 static char **arg_output_fields
= NULL
;
155 static const char *arg_pattern
= NULL
;
156 static pcre2_code
*arg_compiled_pattern
= NULL
;
157 static int arg_case_sensitive
= -1; /* -1 means be smart */
169 ACTION_UPDATE_CATALOG
,
172 ACTION_RELINQUISH_VAR
,
176 ACTION_ROTATE_AND_VACUUM
,
178 ACTION_LIST_FIELD_NAMES
,
179 } arg_action
= ACTION_SHOW
;
181 typedef struct BootId
{
185 LIST_FIELDS(struct BootId
, boot_list
);
188 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
189 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
197 if (!path_startswith(devpath
, "/dev/")) {
198 log_error("Devpath does not start with /dev/");
202 if (stat(devpath
, &st
) < 0)
203 return log_error_errno(errno
, "Couldn't stat file: %m");
205 r
= device_new_from_stat_rdev(&device
, &st
);
207 return log_error_errno(r
, "Failed to get device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
209 for (d
= device
; d
; ) {
210 _cleanup_free_
char *match
= NULL
;
211 const char *subsys
, *sysname
, *devnode
;
214 r
= sd_device_get_subsystem(d
, &subsys
);
218 r
= sd_device_get_sysname(d
, &sysname
);
222 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
226 r
= sd_journal_add_match(j
, match
, 0);
228 return log_error_errno(r
, "Failed to add match: %m");
230 if (sd_device_get_devname(d
, &devnode
) >= 0) {
231 _cleanup_free_
char *match1
= NULL
;
233 r
= stat(devnode
, &st
);
235 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
237 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
241 r
= sd_journal_add_match(j
, match1
, 0);
243 return log_error_errno(r
, "Failed to add match: %m");
247 if (sd_device_get_parent(d
, &parent
) < 0)
253 r
= add_match_this_boot(j
, arg_machine
);
255 return log_error_errno(r
, "Failed to add match for the current boot: %m");
260 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
263 return format_timestamp_utc(buf
, l
, t
);
265 return format_timestamp(buf
, l
, t
);
268 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
269 sd_id128_t id
= SD_ID128_NULL
;
272 if (streq(x
, "all")) {
273 *boot_id
= SD_ID128_NULL
;
276 } else if (strlen(x
) >= 32) {
280 r
= sd_id128_from_string(t
, &id
);
284 if (!IN_SET(*x
, 0, '-', '+'))
288 r
= safe_atoi(x
, &off
);
293 r
= safe_atoi(x
, &off
);
307 static int help(void) {
308 _cleanup_free_
char *link
= NULL
;
311 (void) pager_open(arg_pager_flags
);
313 r
= terminal_urlify_man("journalctl", "1", &link
);
317 printf("%s [OPTIONS...] [MATCHES...]\n\n"
318 "Query the journal.\n\n"
320 " --system Show the system journal\n"
321 " --user Show the user journal for the current user\n"
322 " -M --machine=CONTAINER Operate on local container\n"
323 " -S --since=DATE Show entries not older than the specified date\n"
324 " -U --until=DATE Show entries not newer than the specified date\n"
325 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
326 " --after-cursor=CURSOR Show entries after the specified cursor\n"
327 " --show-cursor Print the cursor after all the entries\n"
328 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
329 " -b --boot[=ID] Show current boot or the specified boot\n"
330 " --list-boots Show terse information about recorded boots\n"
331 " -k --dmesg Show kernel message log from the current boot\n"
332 " -u --unit=UNIT Show logs from the specified unit\n"
333 " --user-unit=UNIT Show logs from the specified user unit\n"
334 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
335 " -p --priority=RANGE Show entries with the specified priority\n"
336 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
337 " --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n"
338 " -e --pager-end Immediately jump to the end in the pager\n"
339 " -f --follow Follow the journal\n"
340 " -n --lines[=INTEGER] Number of journal entries to show\n"
341 " --no-tail Show all lines, even in follow mode\n"
342 " -r --reverse Show the newest entries first\n"
343 " -o --output=STRING Change journal output mode (short, short-precise,\n"
344 " short-iso, short-iso-precise, short-full,\n"
345 " short-monotonic, short-unix, verbose, export,\n"
346 " json, json-pretty, json-sse, json-seq, cat,\n"
348 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
349 " --utc Express time in Coordinated Universal Time (UTC)\n"
350 " -x --catalog Add message explanations where available\n"
351 " --no-full Ellipsize fields\n"
352 " -a --all Show all fields, including long and unprintable\n"
353 " -q --quiet Do not show info messages and privilege warning\n"
354 " --no-pager Do not pipe output into a pager\n"
355 " --no-hostname Suppress output of hostname field\n"
356 " -m --merge Show entries from all available journals\n"
357 " -D --directory=PATH Show journal files from directory\n"
358 " --file=PATH Show journal file\n"
359 " --root=ROOT Operate on files below a root directory\n"
360 " --interval=TIME Time interval for changing the FSS sealing key\n"
361 " --verify-key=KEY Specify FSS verification key\n"
362 " --force Override of the FSS key pair with --setup-keys\n"
364 " -h --help Show this help text\n"
365 " --version Show package version\n"
366 " -N --fields List all field names currently used\n"
367 " -F --field=FIELD List all values that a specified field takes\n"
368 " --disk-usage Show total disk usage of all journal files\n"
369 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
370 " --vacuum-files=INT Leave only the specified number of journal files\n"
371 " --vacuum-time=TIME Remove journal files older than specified time\n"
372 " --verify Verify journal file consistency\n"
373 " --sync Synchronize unwritten journal messages to disk\n"
374 " --relinquish-var Stop logging to disk, log to temporary file system\n"
375 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
376 " --flush Flush all journal data from /run into /var\n"
377 " --rotate Request immediate rotation of the journal files\n"
378 " --header Show journal header information\n"
379 " --list-catalog Show all message IDs in the catalog\n"
380 " --dump-catalog Show entries in the message catalog\n"
381 " --update-catalog Update the message catalog database\n"
382 " --setup-keys Generate a new FSS key pair\n"
383 "\nSee the %s for details.\n"
384 , program_invocation_short_name
391 static int parse_argv(int argc
, char *argv
[]) {
424 ARG_SMART_RELINQUISH_VAR
,
433 static const struct option options
[] = {
434 { "help", no_argument
, NULL
, 'h' },
435 { "version" , no_argument
, NULL
, ARG_VERSION
},
436 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
437 { "pager-end", no_argument
, NULL
, 'e' },
438 { "follow", no_argument
, NULL
, 'f' },
439 { "force", no_argument
, NULL
, ARG_FORCE
},
440 { "output", required_argument
, NULL
, 'o' },
441 { "all", no_argument
, NULL
, 'a' },
442 { "full", no_argument
, NULL
, 'l' },
443 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
444 { "lines", optional_argument
, NULL
, 'n' },
445 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
446 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
447 { "quiet", no_argument
, NULL
, 'q' },
448 { "merge", no_argument
, NULL
, 'm' },
449 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
450 { "boot", optional_argument
, NULL
, 'b' },
451 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
452 { "dmesg", no_argument
, NULL
, 'k' },
453 { "system", no_argument
, NULL
, ARG_SYSTEM
},
454 { "user", no_argument
, NULL
, ARG_USER
},
455 { "directory", required_argument
, NULL
, 'D' },
456 { "file", required_argument
, NULL
, ARG_FILE
},
457 { "root", required_argument
, NULL
, ARG_ROOT
},
458 { "header", no_argument
, NULL
, ARG_HEADER
},
459 { "identifier", required_argument
, NULL
, 't' },
460 { "priority", required_argument
, NULL
, 'p' },
461 { "grep", required_argument
, NULL
, 'g' },
462 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
463 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
464 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
465 { "verify", no_argument
, NULL
, ARG_VERIFY
},
466 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
467 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
468 { "cursor", required_argument
, NULL
, 'c' },
469 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
470 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
471 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
472 { "since", required_argument
, NULL
, 'S' },
473 { "until", required_argument
, NULL
, 'U' },
474 { "unit", required_argument
, NULL
, 'u' },
475 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
476 { "field", required_argument
, NULL
, 'F' },
477 { "fields", no_argument
, NULL
, 'N' },
478 { "catalog", no_argument
, NULL
, 'x' },
479 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
480 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
481 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
482 { "reverse", no_argument
, NULL
, 'r' },
483 { "machine", required_argument
, NULL
, 'M' },
484 { "utc", no_argument
, NULL
, ARG_UTC
},
485 { "flush", no_argument
, NULL
, ARG_FLUSH
},
486 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
487 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
488 { "sync", no_argument
, NULL
, ARG_SYNC
},
489 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
490 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
491 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
492 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
493 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
494 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
503 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
514 arg_pager_flags
|= PAGER_DISABLE
;
518 arg_pager_flags
|= PAGER_JUMP_TO_END
;
520 if (arg_lines
== ARG_LINES_DEFAULT
)
530 if (streq(optarg
, "help")) {
531 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
535 arg_output
= output_mode_from_string(optarg
);
536 if (arg_output
< 0) {
537 log_error("Unknown output format '%s'.", optarg
);
541 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
560 if (streq(optarg
, "all"))
561 arg_lines
= ARG_LINES_ALL
;
563 r
= safe_atoi(optarg
, &arg_lines
);
564 if (r
< 0 || arg_lines
< 0) {
565 log_error("Failed to parse lines '%s'", optarg
);
572 /* Hmm, no argument? Maybe the next
573 * word on the command line is
574 * supposed to be the argument? Let's
575 * see if there is one, and is
579 if (streq(argv
[optind
], "all")) {
580 arg_lines
= ARG_LINES_ALL
;
582 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
596 arg_action
= ACTION_NEW_ID128
;
609 arg_boot_id
= SD_ID128_NULL
;
615 arg_boot_id
= SD_ID128_NULL
;
619 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
621 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
625 /* Hmm, no argument? Maybe the next
626 * word on the command line is
627 * supposed to be the argument? Let's
628 * see if there is one and is parsable
629 * as a boot descriptor... */
630 } else if (optind
< argc
) {
631 r
= parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
640 arg_action
= ACTION_LIST_BOOTS
;
644 arg_boot
= arg_dmesg
= true;
648 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
652 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
656 arg_machine
= optarg
;
660 arg_directory
= optarg
;
664 if (streq(optarg
, "-"))
665 /* An undocumented feature: we can read journal files from STDIN. We don't document
666 * this though, since after all we only support this for mmap-able, seekable files, and
667 * not for example pipes which are probably the primary usecase for reading things from
668 * STDIN. To avoid confusion we hence don't document this feature. */
669 arg_file_stdin
= true;
671 r
= glob_extend(&arg_file
, optarg
);
673 return log_error_errno(r
, "Failed to add paths: %m");
678 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
687 case ARG_CURSOR_FILE
:
688 arg_cursor_file
= optarg
;
691 case ARG_AFTER_CURSOR
:
692 arg_after_cursor
= optarg
;
695 case ARG_SHOW_CURSOR
:
696 arg_show_cursor
= true;
700 arg_action
= ACTION_PRINT_HEADER
;
704 arg_action
= ACTION_VERIFY
;
708 arg_action
= ACTION_DISK_USAGE
;
711 case ARG_VACUUM_SIZE
:
712 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
714 log_error("Failed to parse vacuum size: %s", optarg
);
718 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
721 case ARG_VACUUM_FILES
:
722 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
724 log_error("Failed to parse vacuum files: %s", optarg
);
728 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
731 case ARG_VACUUM_TIME
:
732 r
= parse_sec(optarg
, &arg_vacuum_time
);
734 log_error("Failed to parse vacuum time: %s", optarg
);
738 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
747 arg_action
= ACTION_SETUP_KEYS
;
751 arg_action
= ACTION_VERIFY
;
752 r
= free_and_strdup(&arg_verify_key
, optarg
);
755 /* Use memset not string_erase so this doesn't look confusing
756 * in ps or htop output. */
757 memset(optarg
, 'x', strlen(optarg
));
763 r
= parse_sec(optarg
, &arg_interval
);
764 if (r
< 0 || arg_interval
<= 0) {
765 log_error("Failed to parse sealing key change interval: %s", optarg
);
774 log_error("Compiled without forward-secure sealing support.");
781 dots
= strstr(optarg
, "..");
787 a
= strndup(optarg
, dots
- optarg
);
791 from
= log_level_from_string(a
);
792 to
= log_level_from_string(dots
+ 2);
795 if (from
< 0 || to
< 0) {
796 log_error("Failed to parse log level range %s", optarg
);
803 for (i
= from
; i
<= to
; i
++)
804 arg_priorities
|= 1 << i
;
806 for (i
= to
; i
<= from
; i
++)
807 arg_priorities
|= 1 << i
;
813 p
= log_level_from_string(optarg
);
815 log_error("Unknown log level %s", optarg
);
821 for (i
= 0; i
<= p
; i
++)
822 arg_priorities
|= 1 << i
;
830 arg_pattern
= optarg
;
833 case ARG_CASE_SENSITIVE
:
835 r
= parse_boolean(optarg
);
837 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
838 arg_case_sensitive
= r
;
840 arg_case_sensitive
= true;
845 case ARG_CASE_SENSITIVE
:
846 return log_error("Compiled without pattern matching support");
850 r
= parse_timestamp(optarg
, &arg_since
);
852 log_error("Failed to parse timestamp: %s", optarg
);
855 arg_since_set
= true;
859 r
= parse_timestamp(optarg
, &arg_until
);
861 log_error("Failed to parse timestamp: %s", optarg
);
864 arg_until_set
= true;
868 r
= strv_extend(&arg_syslog_identifier
, optarg
);
874 r
= strv_extend(&arg_system_units
, optarg
);
880 r
= strv_extend(&arg_user_units
, optarg
);
886 arg_action
= ACTION_LIST_FIELDS
;
891 arg_action
= ACTION_LIST_FIELD_NAMES
;
894 case ARG_NO_HOSTNAME
:
895 arg_no_hostname
= true;
902 case ARG_LIST_CATALOG
:
903 arg_action
= ACTION_LIST_CATALOG
;
906 case ARG_DUMP_CATALOG
:
907 arg_action
= ACTION_DUMP_CATALOG
;
910 case ARG_UPDATE_CATALOG
:
911 arg_action
= ACTION_UPDATE_CATALOG
;
923 arg_action
= ACTION_FLUSH
;
926 case ARG_SMART_RELINQUISH_VAR
: {
927 int root_mnt_id
, log_mnt_id
;
929 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
930 * if it's on the same mount as the root file system there's no point in
931 * relinquishing access and we can leave journald write to it until the very last
934 r
= path_get_mnt_id("/", &root_mnt_id
);
936 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
938 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
940 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
941 else if (root_mnt_id
== log_mnt_id
) {
942 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
945 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
951 case ARG_RELINQUISH_VAR
:
952 arg_action
= ACTION_RELINQUISH_VAR
;
956 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
960 arg_action
= ACTION_SYNC
;
963 case ARG_OUTPUT_FIELDS
: {
964 _cleanup_strv_free_
char **v
= NULL
;
966 v
= strv_split(optarg
, ",");
970 if (!arg_output_fields
)
971 arg_output_fields
= TAKE_PTR(v
);
973 r
= strv_extend_strv(&arg_output_fields
, v
, true);
984 assert_not_reached("Unhandled option");
987 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
990 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
> 1) {
991 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
995 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
996 log_error("--since= must be before --until=.");
1000 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
1001 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
1005 if (arg_follow
&& arg_reverse
) {
1006 log_error("Please specify either --reverse= or --follow=, not both.");
1010 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
1011 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
1015 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
1016 log_error("Using --boot or --list-boots with --merge is not supported.");
1020 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
1021 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1022 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1023 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1024 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
1028 arg_system_units
= strv_free(arg_system_units
);
1035 if (arg_case_sensitive
>= 0)
1036 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
1038 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
1040 _cleanup_(pcre2_code_freep
) pcre2_code
*cs
= NULL
;
1042 md
= pcre2_match_data_create(1, NULL
);
1046 r
= pattern_compile("[[:upper:]]", 0, &cs
);
1050 r
= pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
1053 flags
= !has_case
* PCRE2_CASELESS
;
1056 log_debug("Doing case %s matching based on %s",
1057 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
1058 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
1060 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1069 static int add_matches(sd_journal
*j
, char **args
) {
1071 bool have_term
= false;
1075 STRV_FOREACH(i
, args
) {
1078 if (streq(*i
, "+")) {
1081 r
= sd_journal_add_disjunction(j
);
1084 } else if (path_is_absolute(*i
)) {
1085 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1088 r
= chase_symlinks(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
);
1090 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1092 if (lstat(p
, &st
) < 0)
1093 return log_error_errno(errno
, "Couldn't stat file: %m");
1095 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1096 if (executable_is_script(p
, &interpreter
) > 0) {
1097 _cleanup_free_
char *comm
;
1099 comm
= strndup(basename(p
), 15);
1103 t
= strappend("_COMM=", comm
);
1107 /* Append _EXE only if the interpreter is not a link.
1108 Otherwise, it might be outdated often. */
1109 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1110 t2
= strappend("_EXE=", interpreter
);
1115 t
= strappend("_EXE=", p
);
1120 r
= sd_journal_add_match(j
, t
, 0);
1123 r
= sd_journal_add_match(j
, t2
, 0);
1125 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1126 r
= add_matches_for_device(j
, p
);
1130 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1131 "File is neither a device node, nor regular file, nor executable: %s",
1136 r
= sd_journal_add_match(j
, *i
, 0);
1141 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1144 if (!strv_isempty(args
) && !have_term
)
1145 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1146 "\"+\" can only be used between terms");
1151 static void boot_id_free_all(BootId
*l
) {
1155 LIST_REMOVE(boot_list
, l
, i
);
1160 static int discover_next_boot(sd_journal
*j
,
1161 sd_id128_t previous_boot_id
,
1165 _cleanup_free_ BootId
*next_boot
= NULL
;
1166 char match
[9+32+1] = "_BOOT_ID=";
1173 /* We expect the journal to be on the last position of a boot
1174 * (in relation to the direction we are going), so that the next
1175 * invocation of sd_journal_next/previous will be from a different
1176 * boot. We then collect any information we desire and then jump
1177 * to the last location of the new boot by using a _BOOT_ID match
1178 * coming from the other journal direction. */
1180 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1181 * we can actually advance to a *different* boot. */
1182 sd_journal_flush_matches(j
);
1186 r
= sd_journal_previous(j
);
1188 r
= sd_journal_next(j
);
1192 return 0; /* End of journal, yay. */
1194 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1198 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1199 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1200 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1201 * complete than the main entry array, and hence might reference an entry that's not actually the last
1202 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1203 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1206 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1208 next_boot
= new0(BootId
, 1);
1212 next_boot
->id
= boot_id
;
1214 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1218 /* Now seek to the last occurrence of this boot ID. */
1219 sd_id128_to_string(next_boot
->id
, match
+ 9);
1220 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1225 r
= sd_journal_seek_head(j
);
1227 r
= sd_journal_seek_tail(j
);
1232 r
= sd_journal_next(j
);
1234 r
= sd_journal_previous(j
);
1238 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA
),
1239 "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. */
1241 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1245 *ret
= TAKE_PTR(next_boot
);
1250 static int get_boots(
1253 sd_id128_t
*boot_id
,
1258 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1259 const bool advance_older
= boot_id
&& offset
<= 0;
1260 sd_id128_t previous_boot_id
;
1264 /* Adjust for the asymmetry that offset 0 is
1265 * the last (and current) boot, while 1 is considered the
1266 * (chronological) first boot in the journal. */
1267 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1269 /* Advance to the earliest/latest occurrence of our reference
1270 * boot ID (taking our lookup direction into account), so that
1271 * discover_next_boot() can do its job.
1272 * If no reference is given, the journal head/tail will do,
1273 * they're "virtual" boots after all. */
1274 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1275 char match
[9+32+1] = "_BOOT_ID=";
1277 sd_journal_flush_matches(j
);
1279 sd_id128_to_string(*boot_id
, match
+ 9);
1280 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1285 r
= sd_journal_seek_head(j
); /* seek to oldest */
1287 r
= sd_journal_seek_tail(j
); /* seek to newest */
1292 r
= sd_journal_next(j
); /* read the oldest entry */
1294 r
= sd_journal_previous(j
); /* read the most recently added entry */
1299 else if (offset
== 0) {
1304 /* At this point the read pointer is positioned at the oldest/newest occurrence of the reference boot
1305 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1306 * the following entry, which must then have an older/newer boot ID */
1310 r
= sd_journal_seek_tail(j
); /* seek to newest */
1312 r
= sd_journal_seek_head(j
); /* seek to oldest */
1316 /* No sd_journal_next()/_previous() here.
1318 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1319 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1323 previous_boot_id
= SD_ID128_NULL
;
1325 _cleanup_free_ BootId
*current
= NULL
;
1327 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1329 boot_id_free_all(head
);
1336 previous_boot_id
= current
->id
;
1340 offset
+= advance_older
? 1 : -1;
1345 *boot_id
= current
->id
;
1349 LIST_FOREACH(boot_list
, id
, head
) {
1350 if (sd_id128_equal(id
->id
, current
->id
)) {
1351 /* boot id already stored, something wrong with the journal files */
1352 /* exiting as otherwise this problem would cause forever loop */
1356 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1357 tail
= TAKE_PTR(current
);
1366 sd_journal_flush_matches(j
);
1371 static int list_boots(sd_journal
*j
) {
1373 BootId
*id
, *all_ids
;
1377 count
= get_boots(j
, &all_ids
, NULL
, 0);
1379 return log_error_errno(count
, "Failed to determine boots: %m");
1383 (void) pager_open(arg_pager_flags
);
1385 /* numbers are one less, but we need an extra char for the sign */
1386 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1389 LIST_FOREACH(boot_list
, id
, all_ids
) {
1390 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1392 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1394 SD_ID128_FORMAT_VAL(id
->id
),
1395 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1396 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1400 boot_id_free_all(all_ids
);
1405 static int add_boot(sd_journal
*j
) {
1406 char match
[9+32+1] = "_BOOT_ID=";
1415 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1416 * We can do this only when we logs are coming from the current machine,
1417 * so take the slow path if log location is specified. */
1418 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1419 !arg_directory
&& !arg_file
&& !arg_root
)
1421 return add_match_this_boot(j
, arg_machine
);
1423 boot_id
= arg_boot_id
;
1424 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1427 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror(-r
);
1429 if (sd_id128_is_null(arg_boot_id
))
1430 log_error("Data from the specified boot (%+i) is not available: %s",
1431 arg_boot_offset
, reason
);
1433 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1434 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1436 return r
== 0 ? -ENODATA
: r
;
1439 sd_id128_to_string(boot_id
, match
+ 9);
1441 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1443 return log_error_errno(r
, "Failed to add match: %m");
1445 r
= sd_journal_add_conjunction(j
);
1447 return log_error_errno(r
, "Failed to add conjunction: %m");
1452 static int add_dmesg(sd_journal
*j
) {
1459 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1460 STRLEN("_TRANSPORT=kernel"));
1462 return log_error_errno(r
, "Failed to add match: %m");
1464 r
= sd_journal_add_conjunction(j
);
1466 return log_error_errno(r
, "Failed to add conjunction: %m");
1471 static int get_possible_units(
1477 _cleanup_set_free_free_ Set
*found
;
1481 found
= set_new(&string_hash_ops
);
1485 NULSTR_FOREACH(field
, fields
) {
1489 r
= sd_journal_query_unique(j
, field
);
1493 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1494 char **pattern
, *eq
;
1496 _cleanup_free_
char *u
= NULL
;
1498 eq
= memchr(data
, '=', size
);
1500 prefix
= eq
- (char*) data
+ 1;
1504 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1508 STRV_FOREACH(pattern
, patterns
)
1509 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1510 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1512 r
= set_consume(found
, u
);
1514 if (r
< 0 && r
!= -EEXIST
)
1522 *units
= TAKE_PTR(found
);
1527 /* This list is supposed to return the superset of unit names
1528 * possibly matched by rules added with add_matches_for_unit... */
1529 #define SYSTEM_UNITS \
1533 "OBJECT_SYSTEMD_UNIT\0" \
1536 /* ... and add_matches_for_user_unit */
1537 #define USER_UNITS \
1538 "_SYSTEMD_USER_UNIT\0" \
1540 "COREDUMP_USER_UNIT\0" \
1541 "OBJECT_SYSTEMD_USER_UNIT\0"
1543 static int add_units(sd_journal
*j
) {
1544 _cleanup_strv_free_
char **patterns
= NULL
;
1550 STRV_FOREACH(i
, arg_system_units
) {
1551 _cleanup_free_
char *u
= NULL
;
1553 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1557 if (string_is_glob(u
)) {
1558 r
= strv_push(&patterns
, u
);
1563 r
= add_matches_for_unit(j
, u
);
1566 r
= sd_journal_add_disjunction(j
);
1573 if (!strv_isempty(patterns
)) {
1574 _cleanup_set_free_free_ Set
*units
= NULL
;
1578 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1582 SET_FOREACH(u
, units
, it
) {
1583 r
= add_matches_for_unit(j
, u
);
1586 r
= sd_journal_add_disjunction(j
);
1593 patterns
= strv_free(patterns
);
1595 STRV_FOREACH(i
, arg_user_units
) {
1596 _cleanup_free_
char *u
= NULL
;
1598 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1602 if (string_is_glob(u
)) {
1603 r
= strv_push(&patterns
, u
);
1608 r
= add_matches_for_user_unit(j
, u
, getuid());
1611 r
= sd_journal_add_disjunction(j
);
1618 if (!strv_isempty(patterns
)) {
1619 _cleanup_set_free_free_ Set
*units
= NULL
;
1623 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1627 SET_FOREACH(u
, units
, it
) {
1628 r
= add_matches_for_user_unit(j
, u
, getuid());
1631 r
= sd_journal_add_disjunction(j
);
1638 /* Complain if the user request matches but nothing whatsoever was
1639 * found, since otherwise everything would be matched. */
1640 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1643 r
= sd_journal_add_conjunction(j
);
1650 static int add_priorities(sd_journal
*j
) {
1651 char match
[] = "PRIORITY=0";
1655 if (arg_priorities
== 0xFF)
1658 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1659 if (arg_priorities
& (1 << i
)) {
1660 match
[sizeof(match
)-2] = '0' + i
;
1662 r
= sd_journal_add_match(j
, match
, strlen(match
));
1664 return log_error_errno(r
, "Failed to add match: %m");
1667 r
= sd_journal_add_conjunction(j
);
1669 return log_error_errno(r
, "Failed to add conjunction: %m");
1674 static int add_syslog_identifier(sd_journal
*j
) {
1680 STRV_FOREACH(i
, arg_syslog_identifier
) {
1683 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1684 r
= sd_journal_add_match(j
, u
, 0);
1687 r
= sd_journal_add_disjunction(j
);
1692 r
= sd_journal_add_conjunction(j
);
1699 static int setup_keys(void) {
1701 size_t mpk_size
, seed_size
, state_size
, i
;
1702 uint8_t *mpk
, *seed
, *state
;
1704 sd_id128_t machine
, boot
;
1705 char *p
= NULL
, *k
= NULL
;
1710 r
= stat("/var/log/journal", &st
);
1711 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1712 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1714 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1715 log_error("%s is not a directory, must be using persistent logging for FSS.",
1716 "/var/log/journal");
1717 return r
< 0 ? -errno
: -ENOTDIR
;
1720 r
= sd_id128_get_machine(&machine
);
1722 return log_error_errno(r
, "Failed to get machine ID: %m");
1724 r
= sd_id128_get_boot(&boot
);
1726 return log_error_errno(r
, "Failed to get boot ID: %m");
1728 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1729 SD_ID128_FORMAT_VAL(machine
)) < 0)
1734 if (r
< 0 && errno
!= ENOENT
) {
1735 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1738 } else if (access(p
, F_OK
) >= 0) {
1739 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1744 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1745 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1750 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1751 mpk
= alloca(mpk_size
);
1753 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1754 seed
= alloca(seed_size
);
1756 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1757 state
= alloca(state_size
);
1759 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1761 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1765 log_info("Generating seed...");
1766 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1768 log_error_errno(r
, "Failed to read random seed: %m");
1772 log_info("Generating key pair...");
1773 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1775 log_info("Generating sealing key...");
1776 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1778 assert(arg_interval
> 0);
1780 n
= now(CLOCK_REALTIME
);
1784 fd
= mkostemp_safe(k
);
1786 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1790 /* Enable secure remove, exclusion from dump, synchronous
1791 * writing and in-place updating */
1792 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
);
1794 log_warning_errno(r
, "Failed to set file attributes: %m");
1797 memcpy(h
.signature
, "KSHHRHLP", 8);
1798 h
.machine_id
= machine
;
1800 h
.header_size
= htole64(sizeof(h
));
1801 h
.start_usec
= htole64(n
* arg_interval
);
1802 h
.interval_usec
= htole64(arg_interval
);
1803 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1804 h
.fsprg_state_size
= htole64(state_size
);
1806 r
= loop_write(fd
, &h
, sizeof(h
), false);
1808 log_error_errno(r
, "Failed to write header: %m");
1812 r
= loop_write(fd
, state
, state_size
, false);
1814 log_error_errno(r
, "Failed to write state: %m");
1818 if (link(k
, p
) < 0) {
1819 r
= log_error_errno(errno
, "Failed to link file: %m");
1826 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1827 "the following local file. This key file is automatically updated when the\n"
1828 "sealing key is advanced. It should not be used on multiple hosts.\n"
1832 "Please write down the following %ssecret verification key%s. It should be stored\n"
1833 "at a safe location and should not be saved locally on disk.\n"
1835 ansi_highlight(), ansi_normal(),
1837 ansi_highlight(), ansi_normal(),
1838 ansi_highlight_red());
1841 for (i
= 0; i
< seed_size
; i
++) {
1842 if (i
> 0 && i
% 3 == 0)
1844 printf("%02x", ((uint8_t*) seed
)[i
]);
1847 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1850 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1854 "The sealing key is automatically changed every %s.\n",
1856 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1858 hn
= gethostname_malloc();
1861 hostname_cleanup(hn
);
1862 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1864 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1867 /* If this is not an UTF-8 system don't print any QR codes */
1868 if (is_locale_utf8()) {
1869 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1870 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1890 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1891 "Forward-secure sealing not available.");
1895 static int verify(sd_journal
*j
) {
1902 log_show_color(true);
1904 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1906 usec_t first
= 0, validated
= 0, last
= 0;
1909 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1910 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1913 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1915 /* If the key was invalid give up right-away. */
1918 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1921 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1922 log_info("PASS: %s", f
->path
);
1924 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1925 if (validated
> 0) {
1926 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1927 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1928 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1929 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1930 } else if (last
> 0)
1931 log_info("=> No sealing yet, %s of entries not sealed.",
1932 format_timespan(c
, sizeof(c
), last
- first
, 0));
1934 log_info("=> No sealing yet, no entries in file.");
1942 static int simple_varlink_call(const char *option
, const char *method
) {
1943 _cleanup_(varlink_flush_close_unrefp
) Varlink
*link
= NULL
;
1948 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "%s is not supported in conjunction with --machine=.", option
);
1950 r
= varlink_connect_address(&link
, "/run/systemd/journal/io.systemd.journal");
1952 return log_error_errno(r
, "Failed to connect to /run/systemd/journal/io.systemd.journal: %m");
1954 (void) varlink_set_description(link
, "journal");
1956 r
= varlink_call(link
, method
, NULL
, NULL
, &error
, NULL
);
1958 return log_error_errno(r
, "Failed to execute varlink call: %s", error
);
1963 static int flush_to_var(void) {
1964 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
1967 static int relinquish_var(void) {
1968 return simple_varlink_call("--relinquish-var", "io.systemd.Journal.RelinquishVar");
1971 static int rotate(void) {
1972 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
1975 static int sync_journal(void) {
1976 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
1979 static int wait_for_change(sd_journal
*j
, int poll_fd
) {
1980 struct pollfd pollfds
[] = {
1981 { .fd
= poll_fd
, .events
= POLLIN
},
1982 { .fd
= STDOUT_FILENO
},
1990 assert(poll_fd
>= 0);
1992 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
1993 * i.e. when it is closed. */
1995 r
= sd_journal_get_timeout(j
, &timeout
);
1997 return log_error_errno(r
, "Failed to determine journal waiting time: %m");
1999 if (ppoll(pollfds
, ELEMENTSOF(pollfds
),
2000 timeout
== USEC_INFINITY
? NULL
: timespec_store(&ts
, timeout
), NULL
) < 0) {
2004 return log_error_errno(errno
, "Couldn't wait for journal event: %m");
2007 if (pollfds
[1].revents
& (POLLHUP
|POLLERR
)) /* STDOUT has been closed? */
2008 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED
),
2009 "Standard output has been closed.");
2011 r
= sd_journal_process(j
);
2013 return log_error_errno(r
, "Failed to process journal events: %m");
2018 int main(int argc
, char *argv
[]) {
2019 bool previous_boot_id_valid
= false, first_line
= true, ellipsized
= false, need_seek
= false;
2020 bool use_cursor
= false, after_cursor
= false;
2021 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2022 sd_id128_t previous_boot_id
;
2023 int n_shown
= 0, r
, poll_fd
= -1;
2025 setlocale(LC_ALL
, "");
2026 log_show_color(true);
2027 log_parse_environment();
2030 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2031 * split up into many files. */
2032 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
2034 r
= parse_argv(argc
, argv
);
2038 signal(SIGWINCH
, columns_lines_cache_reset
);
2041 switch (arg_action
) {
2043 case ACTION_NEW_ID128
:
2044 r
= id128_print_new(true);
2047 case ACTION_SETUP_KEYS
:
2051 case ACTION_LIST_CATALOG
:
2052 case ACTION_DUMP_CATALOG
:
2053 case ACTION_UPDATE_CATALOG
: {
2054 _cleanup_free_
char *database
;
2056 database
= path_join(arg_root
, CATALOG_DATABASE
);
2062 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2063 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2065 log_error_errno(r
, "Failed to list catalog: %m");
2067 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2069 (void) pager_open(arg_pager_flags
);
2072 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2074 r
= catalog_list(stdout
, database
, oneline
);
2076 log_error_errno(r
, "Failed to list catalog: %m");
2086 case ACTION_RELINQUISH_VAR
:
2087 r
= relinquish_var();
2099 case ACTION_PRINT_HEADER
:
2101 case ACTION_DISK_USAGE
:
2102 case ACTION_LIST_BOOTS
:
2104 case ACTION_ROTATE_AND_VACUUM
:
2105 case ACTION_LIST_FIELDS
:
2106 case ACTION_LIST_FIELD_NAMES
:
2107 /* These ones require access to the journal files, continue below. */
2111 assert_not_reached("Unknown action");
2115 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2117 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2118 else if (arg_file_stdin
) {
2119 int ifd
= STDIN_FILENO
;
2120 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2121 } else if (arg_file
)
2122 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2123 else if (arg_machine
) {
2124 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2125 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2126 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2129 if (geteuid() != 0) {
2130 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2131 * the container, thus we need root privileges to override them. */
2132 log_error("Using the --machine= switch requires root privileges.");
2137 r
= sd_bus_open_system(&bus
);
2139 log_error_errno(r
, "Failed to open system bus: %m");
2143 r
= sd_bus_call_method(
2145 "org.freedesktop.machine1",
2146 "/org/freedesktop/machine1",
2147 "org.freedesktop.machine1.Manager",
2148 "OpenMachineRootDirectory",
2153 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2157 r
= sd_bus_message_read(reply
, "h", &fd
);
2159 bus_log_parse_error(r
);
2163 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2165 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2169 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2173 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2175 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2179 r
= journal_access_check_and_warn(j
, arg_quiet
,
2180 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2184 switch (arg_action
) {
2186 case ACTION_NEW_ID128
:
2187 case ACTION_SETUP_KEYS
:
2188 case ACTION_LIST_CATALOG
:
2189 case ACTION_DUMP_CATALOG
:
2190 case ACTION_UPDATE_CATALOG
:
2194 assert_not_reached("Unexpected action.");
2196 case ACTION_PRINT_HEADER
:
2197 journal_print_header(j
);
2205 case ACTION_DISK_USAGE
: {
2207 char sbytes
[FORMAT_BYTES_MAX
];
2209 r
= sd_journal_get_usage(j
, &bytes
);
2213 printf("Archived and active journals take up %s in the file system.\n",
2214 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2218 case ACTION_LIST_BOOTS
:
2222 case ACTION_ROTATE_AND_VACUUM
:
2230 case ACTION_VACUUM
: {
2234 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2240 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2242 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2250 case ACTION_LIST_FIELD_NAMES
: {
2253 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2254 printf("%s\n", field
);
2263 case ACTION_LIST_FIELDS
:
2267 assert_not_reached("Unknown action");
2270 if (arg_boot_offset
!= 0 &&
2271 sd_journal_has_runtime_files(j
) > 0 &&
2272 sd_journal_has_persistent_files(j
) == 0) {
2273 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2277 /* add_boot() must be called first!
2278 * It may need to seek the journal to find parent boot IDs. */
2289 log_error_errno(r
, "Failed to add filter for units: %m");
2293 r
= add_syslog_identifier(j
);
2295 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2299 r
= add_priorities(j
);
2303 r
= add_matches(j
, argv
+ optind
);
2307 if (DEBUG_LOGGING
) {
2308 _cleanup_free_
char *filter
;
2310 filter
= journal_make_match_string(j
);
2314 log_debug("Journal filter: %s", filter
);
2317 if (arg_action
== ACTION_LIST_FIELDS
) {
2323 r
= sd_journal_set_data_threshold(j
, 0);
2325 log_error_errno(r
, "Failed to unset data size threshold: %m");
2329 r
= sd_journal_query_unique(j
, arg_field
);
2331 log_error_errno(r
, "Failed to query unique data objects: %m");
2335 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2338 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2341 eq
= memchr(data
, '=', size
);
2343 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2345 printf("%.*s\n", (int) size
, (const char*) data
);
2354 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2356 poll_fd
= sd_journal_get_fd(j
);
2357 if (poll_fd
== -EMFILE
) {
2358 log_warning_errno(poll_fd
, "Insufficient watch descriptors available. Reverting to -n.");
2360 } else if (poll_fd
== -EMEDIUMTYPE
) {
2361 log_error_errno(poll_fd
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2363 } else if (poll_fd
< 0) {
2364 log_error_errno(poll_fd
, "Failed to get journal fd: %m");
2369 if (arg_cursor
|| arg_after_cursor
|| arg_cursor_file
) {
2370 _cleanup_free_
char *cursor_from_file
= NULL
;
2371 const char *cursor
= arg_cursor
?: arg_after_cursor
;
2373 if (arg_cursor_file
) {
2374 r
= read_one_line_file(arg_cursor_file
, &cursor_from_file
);
2375 if (r
< 0 && r
!= -ENOENT
) {
2376 log_error_errno(r
, "Failed to read cursor file %s: %m", arg_cursor_file
);
2381 cursor
= cursor_from_file
;
2382 after_cursor
= true;
2385 after_cursor
= !!arg_after_cursor
;
2388 r
= sd_journal_seek_cursor(j
, cursor
);
2390 log_error_errno(r
, "Failed to seek to cursor: %m");
2399 r
= sd_journal_next_skip(j
, 1 + after_cursor
);
2401 r
= sd_journal_previous_skip(j
, 1 + after_cursor
);
2403 if (after_cursor
&& r
< 2) {
2404 /* We couldn't find the next entry after the cursor. */
2411 } else if (arg_since_set
&& !arg_reverse
) {
2412 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2414 log_error_errno(r
, "Failed to seek to date: %m");
2417 r
= sd_journal_next(j
);
2419 } else if (arg_until_set
&& arg_reverse
) {
2420 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2422 log_error_errno(r
, "Failed to seek to date: %m");
2425 r
= sd_journal_previous(j
);
2427 } else if (arg_lines
>= 0) {
2428 r
= sd_journal_seek_tail(j
);
2430 log_error_errno(r
, "Failed to seek to tail: %m");
2434 r
= sd_journal_previous_skip(j
, arg_lines
);
2436 } else if (arg_reverse
) {
2437 r
= sd_journal_seek_tail(j
);
2439 log_error_errno(r
, "Failed to seek to tail: %m");
2443 r
= sd_journal_previous(j
);
2446 r
= sd_journal_seek_head(j
);
2448 log_error_errno(r
, "Failed to seek to head: %m");
2452 r
= sd_journal_next(j
);
2456 log_error_errno(r
, "Failed to iterate through journal: %m");
2463 (void) pager_open(arg_pager_flags
);
2465 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2467 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2469 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2471 log_error_errno(r
, "Failed to get cutoff: %m");
2477 printf("-- Logs begin at %s. --\n",
2478 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2480 printf("-- Logs begin at %s, end at %s. --\n",
2481 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2482 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2487 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2489 size_t highlight
[2] = {};
2493 r
= sd_journal_next(j
);
2495 r
= sd_journal_previous(j
);
2497 log_error_errno(r
, "Failed to iterate through journal: %m");
2504 if (arg_until_set
&& !arg_reverse
) {
2507 r
= sd_journal_get_realtime_usec(j
, &usec
);
2509 log_error_errno(r
, "Failed to determine timestamp: %m");
2512 if (usec
> arg_until
)
2516 if (arg_since_set
&& arg_reverse
) {
2519 r
= sd_journal_get_realtime_usec(j
, &usec
);
2521 log_error_errno(r
, "Failed to determine timestamp: %m");
2524 if (usec
< arg_since
)
2528 if (!arg_merge
&& !arg_quiet
) {
2531 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2533 if (previous_boot_id_valid
&&
2534 !sd_id128_equal(boot_id
, previous_boot_id
))
2535 printf("%s-- Reboot --%s\n",
2536 ansi_highlight(), ansi_normal());
2538 previous_boot_id
= boot_id
;
2539 previous_boot_id_valid
= true;
2544 if (arg_compiled_pattern
) {
2545 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2546 const void *message
;
2550 md
= pcre2_match_data_create(1, NULL
);
2554 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2561 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2565 assert_se(message
= startswith(message
, "MESSAGE="));
2567 r
= pcre2_match(arg_compiled_pattern
,
2569 len
- strlen("MESSAGE="),
2570 0, /* start at offset 0 in the subject */
2571 0, /* default options */
2574 if (r
== PCRE2_ERROR_NOMATCH
) {
2579 unsigned char buf
[LINE_MAX
];
2582 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2583 log_error("Pattern matching failed: %s",
2584 r2
< 0 ? "unknown error" : (char*) buf
);
2589 ovec
= pcre2_get_ovector_pointer(md
);
2590 highlight
[0] = ovec
[0];
2591 highlight
[1] = ovec
[1];
2596 arg_all
* OUTPUT_SHOW_ALL
|
2597 arg_full
* OUTPUT_FULL_WIDTH
|
2598 colors_enabled() * OUTPUT_COLOR
|
2599 arg_catalog
* OUTPUT_CATALOG
|
2600 arg_utc
* OUTPUT_UTC
|
2601 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2603 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2604 arg_output_fields
, highlight
, &ellipsized
);
2606 if (r
== -EADDRNOTAVAIL
)
2613 /* If journalctl take a long time to process messages, and during that time journal file
2614 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2615 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2616 * in the "following" case. By periodically calling sd_journal_process() during the processing
2617 * loop we shrink the window of time a client instance has open file descriptors for rotated
2618 * (deleted) journal files. */
2619 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2620 r
= sd_journal_process(j
);
2622 log_error_errno(r
, "Failed to process inotify events: %m");
2629 if (n_shown
== 0 && !arg_quiet
)
2630 printf("-- No entries --\n");
2632 if (arg_show_cursor
|| arg_cursor_file
) {
2633 _cleanup_free_
char *cursor
= NULL
;
2635 r
= sd_journal_get_cursor(j
, &cursor
);
2636 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2637 log_error_errno(r
, "Failed to get cursor: %m");
2639 if (arg_show_cursor
)
2640 printf("-- cursor: %s\n", cursor
);
2642 if (arg_cursor_file
) {
2643 r
= write_string_file(arg_cursor_file
, cursor
,
2644 WRITE_STRING_FILE_CREATE
|
2645 WRITE_STRING_FILE_ATOMIC
);
2648 "Failed to write new cursor to %s: %m",
2659 r
= wait_for_change(j
, poll_fd
);
2670 strv_free(arg_file
);
2672 strv_free(arg_syslog_identifier
);
2673 strv_free(arg_system_units
);
2674 strv_free(arg_user_units
);
2675 strv_free(arg_output_fields
);
2678 free(arg_verify_key
);
2681 if (arg_compiled_pattern
)
2682 pcre2_code_free(arg_compiled_pattern
);
2685 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;