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"
55 #include "parse-util.h"
56 #include "path-util.h"
57 #include "pretty-print.h"
58 #include "rlimit-util.h"
61 #include "string-table.h"
63 #include "syslog-util.h"
64 #include "terminal-util.h"
65 #include "tmpfile-util.h"
66 #include "unit-name.h"
67 #include "user-util.h"
69 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
71 #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
74 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data
*, pcre2_match_data_free
);
75 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code
*, pcre2_code_free
);
77 static int pattern_compile(const char *pattern
, unsigned flags
, pcre2_code
**out
) {
79 PCRE2_SIZE erroroffset
;
82 p
= pcre2_compile((PCRE2_SPTR8
) pattern
,
83 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
85 unsigned char buf
[LINE_MAX
];
87 r
= pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
89 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
90 "Bad pattern \"%s\": %s", pattern
,
91 r
< 0 ? "unknown error" : (char *)buf
);
101 /* Special values for arg_lines */
102 ARG_LINES_DEFAULT
= -2,
106 static OutputMode arg_output
= OUTPUT_SHORT
;
107 static bool arg_utc
= false;
108 static bool arg_follow
= false;
109 static bool arg_full
= true;
110 static bool arg_all
= false;
111 static PagerFlags arg_pager_flags
= 0;
112 static int arg_lines
= ARG_LINES_DEFAULT
;
113 static bool arg_no_tail
= false;
114 static bool arg_quiet
= false;
115 static bool arg_merge
= false;
116 static bool arg_boot
= false;
117 static sd_id128_t arg_boot_id
= {};
118 static int arg_boot_offset
= 0;
119 static bool arg_dmesg
= false;
120 static bool arg_no_hostname
= false;
121 static const char *arg_cursor
= NULL
;
122 static const char *arg_cursor_file
= NULL
;
123 static const char *arg_after_cursor
= NULL
;
124 static bool arg_show_cursor
= false;
125 static const char *arg_directory
= NULL
;
126 static char **arg_file
= NULL
;
127 static bool arg_file_stdin
= false;
128 static int arg_priorities
= 0xFF;
129 static char *arg_verify_key
= NULL
;
131 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
132 static bool arg_force
= false;
134 static usec_t arg_since
, arg_until
;
135 static bool arg_since_set
= false, arg_until_set
= false;
136 static char **arg_syslog_identifier
= NULL
;
137 static char **arg_system_units
= NULL
;
138 static char **arg_user_units
= NULL
;
139 static const char *arg_field
= NULL
;
140 static bool arg_catalog
= false;
141 static bool arg_reverse
= false;
142 static int arg_journal_type
= 0;
143 static char *arg_root
= NULL
;
144 static const char *arg_machine
= NULL
;
145 static uint64_t arg_vacuum_size
= 0;
146 static uint64_t arg_vacuum_n_files
= 0;
147 static usec_t arg_vacuum_time
= 0;
148 static char **arg_output_fields
= NULL
;
151 static const char *arg_pattern
= NULL
;
152 static pcre2_code
*arg_compiled_pattern
= NULL
;
153 static int arg_case_sensitive
= -1; /* -1 means be smart */
165 ACTION_UPDATE_CATALOG
,
171 ACTION_ROTATE_AND_VACUUM
,
173 ACTION_LIST_FIELD_NAMES
,
174 } arg_action
= ACTION_SHOW
;
176 typedef struct BootId
{
180 LIST_FIELDS(struct BootId
, boot_list
);
183 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
184 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
192 if (!path_startswith(devpath
, "/dev/")) {
193 log_error("Devpath does not start with /dev/");
197 if (stat(devpath
, &st
) < 0)
198 return log_error_errno(errno
, "Couldn't stat file: %m");
200 r
= device_new_from_stat_rdev(&device
, &st
);
202 return log_error_errno(r
, "Failed to get device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
204 for (d
= device
; d
; ) {
205 _cleanup_free_
char *match
= NULL
;
206 const char *subsys
, *sysname
, *devnode
;
209 r
= sd_device_get_subsystem(d
, &subsys
);
213 r
= sd_device_get_sysname(d
, &sysname
);
217 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
221 r
= sd_journal_add_match(j
, match
, 0);
223 return log_error_errno(r
, "Failed to add match: %m");
225 if (sd_device_get_devname(d
, &devnode
) >= 0) {
226 _cleanup_free_
char *match1
= NULL
;
228 r
= stat(devnode
, &st
);
230 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
232 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
236 r
= sd_journal_add_match(j
, match1
, 0);
238 return log_error_errno(r
, "Failed to add match: %m");
242 if (sd_device_get_parent(d
, &parent
) < 0)
248 r
= add_match_this_boot(j
, arg_machine
);
250 return log_error_errno(r
, "Failed to add match for the current boot: %m");
255 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
258 return format_timestamp_utc(buf
, l
, t
);
260 return format_timestamp(buf
, l
, t
);
263 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
264 sd_id128_t id
= SD_ID128_NULL
;
267 if (strlen(x
) >= 32) {
271 r
= sd_id128_from_string(t
, &id
);
275 if (!IN_SET(*x
, 0, '-', '+'))
279 r
= safe_atoi(x
, &off
);
284 r
= safe_atoi(x
, &off
);
298 static int help(void) {
299 _cleanup_free_
char *link
= NULL
;
302 (void) pager_open(arg_pager_flags
);
304 r
= terminal_urlify_man("journalctl", "1", &link
);
308 printf("%s [OPTIONS...] [MATCHES...]\n\n"
309 "Query the journal.\n\n"
311 " --system Show the system journal\n"
312 " --user Show the user journal for the current user\n"
313 " -M --machine=CONTAINER Operate on local container\n"
314 " -S --since=DATE Show entries not older than the specified date\n"
315 " -U --until=DATE Show entries not newer than the specified date\n"
316 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
317 " --after-cursor=CURSOR Show entries after the specified cursor\n"
318 " --show-cursor Print the cursor after all the entries\n"
319 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
320 " -b --boot[=ID] Show current boot or the specified boot\n"
321 " --list-boots Show terse information about recorded boots\n"
322 " -k --dmesg Show kernel message log from the current boot\n"
323 " -u --unit=UNIT Show logs from the specified unit\n"
324 " --user-unit=UNIT Show logs from the specified user unit\n"
325 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
326 " -p --priority=RANGE Show entries with the specified priority\n"
327 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
328 " --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n"
329 " -e --pager-end Immediately jump to the end in the pager\n"
330 " -f --follow Follow the journal\n"
331 " -n --lines[=INTEGER] Number of journal entries to show\n"
332 " --no-tail Show all lines, even in follow mode\n"
333 " -r --reverse Show the newest entries first\n"
334 " -o --output=STRING Change journal output mode (short, short-precise,\n"
335 " short-iso, short-iso-precise, short-full,\n"
336 " short-monotonic, short-unix, verbose, export,\n"
337 " json, json-pretty, json-sse, json-seq, cat,\n"
339 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
340 " --utc Express time in Coordinated Universal Time (UTC)\n"
341 " -x --catalog Add message explanations where available\n"
342 " --no-full Ellipsize fields\n"
343 " -a --all Show all fields, including long and unprintable\n"
344 " -q --quiet Do not show info messages and privilege warning\n"
345 " --no-pager Do not pipe output into a pager\n"
346 " --no-hostname Suppress output of hostname field\n"
347 " -m --merge Show entries from all available journals\n"
348 " -D --directory=PATH Show journal files from directory\n"
349 " --file=PATH Show journal file\n"
350 " --root=ROOT Operate on files below a root directory\n"
351 " --interval=TIME Time interval for changing the FSS sealing key\n"
352 " --verify-key=KEY Specify FSS verification key\n"
353 " --force Override of the FSS key pair with --setup-keys\n"
355 " -h --help Show this help text\n"
356 " --version Show package version\n"
357 " -N --fields List all field names currently used\n"
358 " -F --field=FIELD List all values that a specified field takes\n"
359 " --disk-usage Show total disk usage of all journal files\n"
360 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
361 " --vacuum-files=INT Leave only the specified number of journal files\n"
362 " --vacuum-time=TIME Remove journal files older than specified time\n"
363 " --verify Verify journal file consistency\n"
364 " --sync Synchronize unwritten journal messages to disk\n"
365 " --flush Flush all journal data from /run into /var\n"
366 " --rotate Request immediate rotation of the journal files\n"
367 " --header Show journal header information\n"
368 " --list-catalog Show all message IDs in the catalog\n"
369 " --dump-catalog Show entries in the message catalog\n"
370 " --update-catalog Update the message catalog database\n"
371 " --setup-keys Generate a new FSS key pair\n"
372 "\nSee the %s for details.\n"
373 , program_invocation_short_name
380 static int parse_argv(int argc
, char *argv
[]) {
420 static const struct option options
[] = {
421 { "help", no_argument
, NULL
, 'h' },
422 { "version" , no_argument
, NULL
, ARG_VERSION
},
423 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
424 { "pager-end", no_argument
, NULL
, 'e' },
425 { "follow", no_argument
, NULL
, 'f' },
426 { "force", no_argument
, NULL
, ARG_FORCE
},
427 { "output", required_argument
, NULL
, 'o' },
428 { "all", no_argument
, NULL
, 'a' },
429 { "full", no_argument
, NULL
, 'l' },
430 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
431 { "lines", optional_argument
, NULL
, 'n' },
432 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
433 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
434 { "quiet", no_argument
, NULL
, 'q' },
435 { "merge", no_argument
, NULL
, 'm' },
436 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
437 { "boot", optional_argument
, NULL
, 'b' },
438 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
439 { "dmesg", no_argument
, NULL
, 'k' },
440 { "system", no_argument
, NULL
, ARG_SYSTEM
},
441 { "user", no_argument
, NULL
, ARG_USER
},
442 { "directory", required_argument
, NULL
, 'D' },
443 { "file", required_argument
, NULL
, ARG_FILE
},
444 { "root", required_argument
, NULL
, ARG_ROOT
},
445 { "header", no_argument
, NULL
, ARG_HEADER
},
446 { "identifier", required_argument
, NULL
, 't' },
447 { "priority", required_argument
, NULL
, 'p' },
448 { "grep", required_argument
, NULL
, 'g' },
449 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
450 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
451 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
452 { "verify", no_argument
, NULL
, ARG_VERIFY
},
453 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
454 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
455 { "cursor", required_argument
, NULL
, 'c' },
456 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
457 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
458 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
459 { "since", required_argument
, NULL
, 'S' },
460 { "until", required_argument
, NULL
, 'U' },
461 { "unit", required_argument
, NULL
, 'u' },
462 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
463 { "field", required_argument
, NULL
, 'F' },
464 { "fields", no_argument
, NULL
, 'N' },
465 { "catalog", no_argument
, NULL
, 'x' },
466 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
467 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
468 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
469 { "reverse", no_argument
, NULL
, 'r' },
470 { "machine", required_argument
, NULL
, 'M' },
471 { "utc", no_argument
, NULL
, ARG_UTC
},
472 { "flush", no_argument
, NULL
, ARG_FLUSH
},
473 { "sync", no_argument
, NULL
, ARG_SYNC
},
474 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
475 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
476 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
477 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
478 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
479 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
488 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
499 arg_pager_flags
|= PAGER_DISABLE
;
503 arg_pager_flags
|= PAGER_JUMP_TO_END
;
505 if (arg_lines
== ARG_LINES_DEFAULT
)
515 if (streq(optarg
, "help")) {
516 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
520 arg_output
= output_mode_from_string(optarg
);
521 if (arg_output
< 0) {
522 log_error("Unknown output format '%s'.", optarg
);
526 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
545 if (streq(optarg
, "all"))
546 arg_lines
= ARG_LINES_ALL
;
548 r
= safe_atoi(optarg
, &arg_lines
);
549 if (r
< 0 || arg_lines
< 0) {
550 log_error("Failed to parse lines '%s'", optarg
);
557 /* Hmm, no argument? Maybe the next
558 * word on the command line is
559 * supposed to be the argument? Let's
560 * see if there is one, and is
564 if (streq(argv
[optind
], "all")) {
565 arg_lines
= ARG_LINES_ALL
;
567 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
581 arg_action
= ACTION_NEW_ID128
;
600 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
602 log_error("Failed to parse boot descriptor '%s'", optarg
);
607 /* Hmm, no argument? Maybe the next
608 * word on the command line is
609 * supposed to be the argument? Let's
610 * see if there is one and is parsable
611 * as a boot descriptor... */
614 parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
) >= 0)
621 arg_action
= ACTION_LIST_BOOTS
;
625 arg_boot
= arg_dmesg
= true;
629 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
633 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
637 arg_machine
= optarg
;
641 arg_directory
= optarg
;
645 if (streq(optarg
, "-"))
646 /* An undocumented feature: we can read journal files from STDIN. We don't document
647 * this though, since after all we only support this for mmap-able, seekable files, and
648 * not for example pipes which are probably the primary usecase for reading things from
649 * STDIN. To avoid confusion we hence don't document this feature. */
650 arg_file_stdin
= true;
652 r
= glob_extend(&arg_file
, optarg
);
654 return log_error_errno(r
, "Failed to add paths: %m");
659 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
668 case ARG_CURSOR_FILE
:
669 arg_cursor_file
= optarg
;
672 case ARG_AFTER_CURSOR
:
673 arg_after_cursor
= optarg
;
676 case ARG_SHOW_CURSOR
:
677 arg_show_cursor
= true;
681 arg_action
= ACTION_PRINT_HEADER
;
685 arg_action
= ACTION_VERIFY
;
689 arg_action
= ACTION_DISK_USAGE
;
692 case ARG_VACUUM_SIZE
:
693 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
695 log_error("Failed to parse vacuum size: %s", optarg
);
699 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
702 case ARG_VACUUM_FILES
:
703 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
705 log_error("Failed to parse vacuum files: %s", optarg
);
709 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
712 case ARG_VACUUM_TIME
:
713 r
= parse_sec(optarg
, &arg_vacuum_time
);
715 log_error("Failed to parse vacuum time: %s", optarg
);
719 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
728 arg_action
= ACTION_SETUP_KEYS
;
732 arg_action
= ACTION_VERIFY
;
733 r
= free_and_strdup(&arg_verify_key
, optarg
);
736 /* Use memset not string_erase so this doesn't look confusing
737 * in ps or htop output. */
738 memset(optarg
, 'x', strlen(optarg
));
744 r
= parse_sec(optarg
, &arg_interval
);
745 if (r
< 0 || arg_interval
<= 0) {
746 log_error("Failed to parse sealing key change interval: %s", optarg
);
755 log_error("Compiled without forward-secure sealing support.");
762 dots
= strstr(optarg
, "..");
768 a
= strndup(optarg
, dots
- optarg
);
772 from
= log_level_from_string(a
);
773 to
= log_level_from_string(dots
+ 2);
776 if (from
< 0 || to
< 0) {
777 log_error("Failed to parse log level range %s", optarg
);
784 for (i
= from
; i
<= to
; i
++)
785 arg_priorities
|= 1 << i
;
787 for (i
= to
; i
<= from
; i
++)
788 arg_priorities
|= 1 << i
;
794 p
= log_level_from_string(optarg
);
796 log_error("Unknown log level %s", optarg
);
802 for (i
= 0; i
<= p
; i
++)
803 arg_priorities
|= 1 << i
;
811 arg_pattern
= optarg
;
814 case ARG_CASE_SENSITIVE
:
816 r
= parse_boolean(optarg
);
818 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
819 arg_case_sensitive
= r
;
821 arg_case_sensitive
= true;
826 case ARG_CASE_SENSITIVE
:
827 return log_error("Compiled without pattern matching support");
831 r
= parse_timestamp(optarg
, &arg_since
);
833 log_error("Failed to parse timestamp: %s", optarg
);
836 arg_since_set
= true;
840 r
= parse_timestamp(optarg
, &arg_until
);
842 log_error("Failed to parse timestamp: %s", optarg
);
845 arg_until_set
= true;
849 r
= strv_extend(&arg_syslog_identifier
, optarg
);
855 r
= strv_extend(&arg_system_units
, optarg
);
861 r
= strv_extend(&arg_user_units
, optarg
);
867 arg_action
= ACTION_LIST_FIELDS
;
872 arg_action
= ACTION_LIST_FIELD_NAMES
;
875 case ARG_NO_HOSTNAME
:
876 arg_no_hostname
= true;
883 case ARG_LIST_CATALOG
:
884 arg_action
= ACTION_LIST_CATALOG
;
887 case ARG_DUMP_CATALOG
:
888 arg_action
= ACTION_DUMP_CATALOG
;
891 case ARG_UPDATE_CATALOG
:
892 arg_action
= ACTION_UPDATE_CATALOG
;
904 arg_action
= ACTION_FLUSH
;
908 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
912 arg_action
= ACTION_SYNC
;
915 case ARG_OUTPUT_FIELDS
: {
916 _cleanup_strv_free_
char **v
= NULL
;
918 v
= strv_split(optarg
, ",");
922 if (!arg_output_fields
)
923 arg_output_fields
= TAKE_PTR(v
);
925 r
= strv_extend_strv(&arg_output_fields
, v
, true);
936 assert_not_reached("Unhandled option");
939 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
942 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
> 1) {
943 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
947 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
948 log_error("--since= must be before --until=.");
952 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
953 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
957 if (arg_follow
&& arg_reverse
) {
958 log_error("Please specify either --reverse= or --follow=, not both.");
962 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
963 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
967 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
968 log_error("Using --boot or --list-boots with --merge is not supported.");
972 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
973 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
974 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
975 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
976 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
980 arg_system_units
= strv_free(arg_system_units
);
987 if (arg_case_sensitive
>= 0)
988 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
990 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
992 _cleanup_(pcre2_code_freep
) pcre2_code
*cs
= NULL
;
994 md
= pcre2_match_data_create(1, NULL
);
998 r
= pattern_compile("[[:upper:]]", 0, &cs
);
1002 r
= pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
1005 flags
= !has_case
* PCRE2_CASELESS
;
1008 log_debug("Doing case %s matching based on %s",
1009 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
1010 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
1012 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1021 static int add_matches(sd_journal
*j
, char **args
) {
1023 bool have_term
= false;
1027 STRV_FOREACH(i
, args
) {
1030 if (streq(*i
, "+")) {
1033 r
= sd_journal_add_disjunction(j
);
1036 } else if (path_is_absolute(*i
)) {
1037 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1040 r
= chase_symlinks(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
);
1042 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1044 if (lstat(p
, &st
) < 0)
1045 return log_error_errno(errno
, "Couldn't stat file: %m");
1047 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1048 if (executable_is_script(p
, &interpreter
) > 0) {
1049 _cleanup_free_
char *comm
;
1051 comm
= strndup(basename(p
), 15);
1055 t
= strappend("_COMM=", comm
);
1059 /* Append _EXE only if the interpreter is not a link.
1060 Otherwise, it might be outdated often. */
1061 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1062 t2
= strappend("_EXE=", interpreter
);
1067 t
= strappend("_EXE=", p
);
1072 r
= sd_journal_add_match(j
, t
, 0);
1075 r
= sd_journal_add_match(j
, t2
, 0);
1077 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1078 r
= add_matches_for_device(j
, p
);
1082 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1083 "File is neither a device node, nor regular file, nor executable: %s",
1088 r
= sd_journal_add_match(j
, *i
, 0);
1093 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1096 if (!strv_isempty(args
) && !have_term
)
1097 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1098 "\"+\" can only be used between terms");
1103 static void boot_id_free_all(BootId
*l
) {
1107 LIST_REMOVE(boot_list
, l
, i
);
1112 static int discover_next_boot(sd_journal
*j
,
1113 sd_id128_t previous_boot_id
,
1117 _cleanup_free_ BootId
*next_boot
= NULL
;
1118 char match
[9+32+1] = "_BOOT_ID=";
1125 /* We expect the journal to be on the last position of a boot
1126 * (in relation to the direction we are going), so that the next
1127 * invocation of sd_journal_next/previous will be from a different
1128 * boot. We then collect any information we desire and then jump
1129 * to the last location of the new boot by using a _BOOT_ID match
1130 * coming from the other journal direction. */
1132 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1133 * we can actually advance to a *different* boot. */
1134 sd_journal_flush_matches(j
);
1138 r
= sd_journal_previous(j
);
1140 r
= sd_journal_next(j
);
1144 return 0; /* End of journal, yay. */
1146 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1150 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1151 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1152 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1153 * complete than the main entry array, and hence might reference an entry that's not actually the last
1154 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1155 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1158 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1160 next_boot
= new0(BootId
, 1);
1164 next_boot
->id
= boot_id
;
1166 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1170 /* Now seek to the last occurrence of this boot ID. */
1171 sd_id128_to_string(next_boot
->id
, match
+ 9);
1172 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1177 r
= sd_journal_seek_head(j
);
1179 r
= sd_journal_seek_tail(j
);
1184 r
= sd_journal_next(j
);
1186 r
= sd_journal_previous(j
);
1190 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA
),
1191 "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. */
1193 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1197 *ret
= TAKE_PTR(next_boot
);
1202 static int get_boots(
1205 sd_id128_t
*boot_id
,
1210 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1211 const bool advance_older
= boot_id
&& offset
<= 0;
1212 sd_id128_t previous_boot_id
;
1216 /* Adjust for the asymmetry that offset 0 is
1217 * the last (and current) boot, while 1 is considered the
1218 * (chronological) first boot in the journal. */
1219 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1221 /* Advance to the earliest/latest occurrence of our reference
1222 * boot ID (taking our lookup direction into account), so that
1223 * discover_next_boot() can do its job.
1224 * If no reference is given, the journal head/tail will do,
1225 * they're "virtual" boots after all. */
1226 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1227 char match
[9+32+1] = "_BOOT_ID=";
1229 sd_journal_flush_matches(j
);
1231 sd_id128_to_string(*boot_id
, match
+ 9);
1232 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1237 r
= sd_journal_seek_head(j
); /* seek to oldest */
1239 r
= sd_journal_seek_tail(j
); /* seek to newest */
1244 r
= sd_journal_next(j
); /* read the oldest entry */
1246 r
= sd_journal_previous(j
); /* read the most recently added entry */
1251 else if (offset
== 0) {
1256 /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
1257 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1258 * the following entry, which must then have an older/newer boot ID */
1262 r
= sd_journal_seek_tail(j
); /* seek to newest */
1264 r
= sd_journal_seek_head(j
); /* seek to oldest */
1268 /* No sd_journal_next()/_previous() here.
1270 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1271 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1275 previous_boot_id
= SD_ID128_NULL
;
1277 _cleanup_free_ BootId
*current
= NULL
;
1279 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1281 boot_id_free_all(head
);
1288 previous_boot_id
= current
->id
;
1292 offset
+= advance_older
? 1 : -1;
1297 *boot_id
= current
->id
;
1301 LIST_FOREACH(boot_list
, id
, head
) {
1302 if (sd_id128_equal(id
->id
, current
->id
)) {
1303 /* boot id already stored, something wrong with the journal files */
1304 /* exiting as otherwise this problem would cause forever loop */
1308 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1309 tail
= TAKE_PTR(current
);
1318 sd_journal_flush_matches(j
);
1323 static int list_boots(sd_journal
*j
) {
1325 BootId
*id
, *all_ids
;
1329 count
= get_boots(j
, &all_ids
, NULL
, 0);
1331 return log_error_errno(count
, "Failed to determine boots: %m");
1335 (void) pager_open(arg_pager_flags
);
1337 /* numbers are one less, but we need an extra char for the sign */
1338 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1341 LIST_FOREACH(boot_list
, id
, all_ids
) {
1342 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1344 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1346 SD_ID128_FORMAT_VAL(id
->id
),
1347 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1348 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1352 boot_id_free_all(all_ids
);
1357 static int add_boot(sd_journal
*j
) {
1358 char match
[9+32+1] = "_BOOT_ID=";
1367 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1368 * We can do this only when we logs are coming from the current machine,
1369 * so take the slow path if log location is specified. */
1370 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1371 !arg_directory
&& !arg_file
&& !arg_root
)
1373 return add_match_this_boot(j
, arg_machine
);
1375 boot_id
= arg_boot_id
;
1376 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1379 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror(-r
);
1381 if (sd_id128_is_null(arg_boot_id
))
1382 log_error("Data from the specified boot (%+i) is not available: %s",
1383 arg_boot_offset
, reason
);
1385 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1386 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1388 return r
== 0 ? -ENODATA
: r
;
1391 sd_id128_to_string(boot_id
, match
+ 9);
1393 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1395 return log_error_errno(r
, "Failed to add match: %m");
1397 r
= sd_journal_add_conjunction(j
);
1399 return log_error_errno(r
, "Failed to add conjunction: %m");
1404 static int add_dmesg(sd_journal
*j
) {
1411 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1412 STRLEN("_TRANSPORT=kernel"));
1414 return log_error_errno(r
, "Failed to add match: %m");
1416 r
= sd_journal_add_conjunction(j
);
1418 return log_error_errno(r
, "Failed to add conjunction: %m");
1423 static int get_possible_units(
1429 _cleanup_set_free_free_ Set
*found
;
1433 found
= set_new(&string_hash_ops
);
1437 NULSTR_FOREACH(field
, fields
) {
1441 r
= sd_journal_query_unique(j
, field
);
1445 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1446 char **pattern
, *eq
;
1448 _cleanup_free_
char *u
= NULL
;
1450 eq
= memchr(data
, '=', size
);
1452 prefix
= eq
- (char*) data
+ 1;
1456 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1460 STRV_FOREACH(pattern
, patterns
)
1461 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1462 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1464 r
= set_consume(found
, u
);
1466 if (r
< 0 && r
!= -EEXIST
)
1474 *units
= TAKE_PTR(found
);
1479 /* This list is supposed to return the superset of unit names
1480 * possibly matched by rules added with add_matches_for_unit... */
1481 #define SYSTEM_UNITS \
1485 "OBJECT_SYSTEMD_UNIT\0" \
1488 /* ... and add_matches_for_user_unit */
1489 #define USER_UNITS \
1490 "_SYSTEMD_USER_UNIT\0" \
1492 "COREDUMP_USER_UNIT\0" \
1493 "OBJECT_SYSTEMD_USER_UNIT\0"
1495 static int add_units(sd_journal
*j
) {
1496 _cleanup_strv_free_
char **patterns
= NULL
;
1502 STRV_FOREACH(i
, arg_system_units
) {
1503 _cleanup_free_
char *u
= NULL
;
1505 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1509 if (string_is_glob(u
)) {
1510 r
= strv_push(&patterns
, u
);
1515 r
= add_matches_for_unit(j
, u
);
1518 r
= sd_journal_add_disjunction(j
);
1525 if (!strv_isempty(patterns
)) {
1526 _cleanup_set_free_free_ Set
*units
= NULL
;
1530 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1534 SET_FOREACH(u
, units
, it
) {
1535 r
= add_matches_for_unit(j
, u
);
1538 r
= sd_journal_add_disjunction(j
);
1545 patterns
= strv_free(patterns
);
1547 STRV_FOREACH(i
, arg_user_units
) {
1548 _cleanup_free_
char *u
= NULL
;
1550 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1554 if (string_is_glob(u
)) {
1555 r
= strv_push(&patterns
, u
);
1560 r
= add_matches_for_user_unit(j
, u
, getuid());
1563 r
= sd_journal_add_disjunction(j
);
1570 if (!strv_isempty(patterns
)) {
1571 _cleanup_set_free_free_ Set
*units
= NULL
;
1575 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1579 SET_FOREACH(u
, units
, it
) {
1580 r
= add_matches_for_user_unit(j
, u
, getuid());
1583 r
= sd_journal_add_disjunction(j
);
1590 /* Complain if the user request matches but nothing whatsoever was
1591 * found, since otherwise everything would be matched. */
1592 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1595 r
= sd_journal_add_conjunction(j
);
1602 static int add_priorities(sd_journal
*j
) {
1603 char match
[] = "PRIORITY=0";
1607 if (arg_priorities
== 0xFF)
1610 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1611 if (arg_priorities
& (1 << i
)) {
1612 match
[sizeof(match
)-2] = '0' + i
;
1614 r
= sd_journal_add_match(j
, match
, strlen(match
));
1616 return log_error_errno(r
, "Failed to add match: %m");
1619 r
= sd_journal_add_conjunction(j
);
1621 return log_error_errno(r
, "Failed to add conjunction: %m");
1626 static int add_syslog_identifier(sd_journal
*j
) {
1632 STRV_FOREACH(i
, arg_syslog_identifier
) {
1635 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1636 r
= sd_journal_add_match(j
, u
, 0);
1639 r
= sd_journal_add_disjunction(j
);
1644 r
= sd_journal_add_conjunction(j
);
1651 static int setup_keys(void) {
1653 size_t mpk_size
, seed_size
, state_size
, i
;
1654 uint8_t *mpk
, *seed
, *state
;
1656 sd_id128_t machine
, boot
;
1657 char *p
= NULL
, *k
= NULL
;
1662 r
= stat("/var/log/journal", &st
);
1663 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1664 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1666 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1667 log_error("%s is not a directory, must be using persistent logging for FSS.",
1668 "/var/log/journal");
1669 return r
< 0 ? -errno
: -ENOTDIR
;
1672 r
= sd_id128_get_machine(&machine
);
1674 return log_error_errno(r
, "Failed to get machine ID: %m");
1676 r
= sd_id128_get_boot(&boot
);
1678 return log_error_errno(r
, "Failed to get boot ID: %m");
1680 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1681 SD_ID128_FORMAT_VAL(machine
)) < 0)
1686 if (r
< 0 && errno
!= ENOENT
) {
1687 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1690 } else if (access(p
, F_OK
) >= 0) {
1691 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1696 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1697 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1702 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1703 mpk
= alloca(mpk_size
);
1705 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1706 seed
= alloca(seed_size
);
1708 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1709 state
= alloca(state_size
);
1711 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1713 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1717 log_info("Generating seed...");
1718 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1720 log_error_errno(r
, "Failed to read random seed: %m");
1724 log_info("Generating key pair...");
1725 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1727 log_info("Generating sealing key...");
1728 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1730 assert(arg_interval
> 0);
1732 n
= now(CLOCK_REALTIME
);
1736 fd
= mkostemp_safe(k
);
1738 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1742 /* Enable secure remove, exclusion from dump, synchronous
1743 * writing and in-place updating */
1744 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
);
1746 log_warning_errno(r
, "Failed to set file attributes: %m");
1749 memcpy(h
.signature
, "KSHHRHLP", 8);
1750 h
.machine_id
= machine
;
1752 h
.header_size
= htole64(sizeof(h
));
1753 h
.start_usec
= htole64(n
* arg_interval
);
1754 h
.interval_usec
= htole64(arg_interval
);
1755 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1756 h
.fsprg_state_size
= htole64(state_size
);
1758 r
= loop_write(fd
, &h
, sizeof(h
), false);
1760 log_error_errno(r
, "Failed to write header: %m");
1764 r
= loop_write(fd
, state
, state_size
, false);
1766 log_error_errno(r
, "Failed to write state: %m");
1770 if (link(k
, p
) < 0) {
1771 r
= log_error_errno(errno
, "Failed to link file: %m");
1778 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1779 "the following local file. This key file is automatically updated when the\n"
1780 "sealing key is advanced. It should not be used on multiple hosts.\n"
1784 "Please write down the following %ssecret verification key%s. It should be stored\n"
1785 "at a safe location and should not be saved locally on disk.\n"
1787 ansi_highlight(), ansi_normal(),
1789 ansi_highlight(), ansi_normal(),
1790 ansi_highlight_red());
1793 for (i
= 0; i
< seed_size
; i
++) {
1794 if (i
> 0 && i
% 3 == 0)
1796 printf("%02x", ((uint8_t*) seed
)[i
]);
1799 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1802 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1806 "The sealing key is automatically changed every %s.\n",
1808 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1810 hn
= gethostname_malloc();
1813 hostname_cleanup(hn
);
1814 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1816 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1819 /* If this is not an UTF-8 system don't print any QR codes */
1820 if (is_locale_utf8()) {
1821 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1822 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1842 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1843 "Forward-secure sealing not available.");
1847 static int verify(sd_journal
*j
) {
1854 log_show_color(true);
1856 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1858 usec_t first
= 0, validated
= 0, last
= 0;
1861 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1862 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1865 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1867 /* If the key was invalid give up right-away. */
1870 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1873 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1874 log_info("PASS: %s", f
->path
);
1876 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1877 if (validated
> 0) {
1878 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1879 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1880 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1881 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1882 } else if (last
> 0)
1883 log_info("=> No sealing yet, %s of entries not sealed.",
1884 format_timespan(c
, sizeof(c
), last
- first
, 0));
1886 log_info("=> No sealing yet, no entries in file.");
1894 static int flush_to_var(void) {
1895 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1896 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1897 _cleanup_close_
int watch_fd
= -1;
1901 log_error("--flush is not supported in conjunction with --machine=.");
1906 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1909 /* OK, let's actually do the full logic, send SIGUSR1 to the
1910 * daemon and set up inotify to wait for the flushed file to appear */
1911 r
= bus_connect_system_systemd(&bus
);
1913 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1915 r
= sd_bus_call_method(
1917 "org.freedesktop.systemd1",
1918 "/org/freedesktop/systemd1",
1919 "org.freedesktop.systemd1.Manager",
1923 "ssi", "systemd-journald.service", "main", SIGUSR1
);
1925 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
1927 mkdir_p("/run/systemd/journal", 0755);
1929 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1931 return log_error_errno(errno
, "Failed to create inotify watch: %m");
1933 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_CREATE
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
1935 return log_error_errno(errno
, "Failed to watch journal directory: %m");
1938 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1941 if (errno
!= ENOENT
)
1942 return log_error_errno(errno
, "Failed to check for existence of /run/systemd/journal/flushed: %m");
1944 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
1946 return log_error_errno(r
, "Failed to wait for event: %m");
1948 r
= flush_fd(watch_fd
);
1950 return log_error_errno(r
, "Failed to flush inotify events: %m");
1956 static int send_signal_and_wait(int sig
, const char *watch_path
) {
1957 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1958 _cleanup_close_
int watch_fd
= -1;
1963 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
1967 start
= now(CLOCK_MONOTONIC
);
1969 /* This call sends the specified signal to journald, and waits
1970 * for acknowledgment by watching the mtime of the specified
1971 * flag file. This is used to trigger syncing or rotation and
1972 * then wait for the operation to complete. */
1977 /* See if a sync happened by now. */
1978 r
= read_timestamp_file(watch_path
, &tstamp
);
1979 if (r
< 0 && r
!= -ENOENT
)
1980 return log_error_errno(r
, "Failed to read %s: %m", watch_path
);
1981 if (r
>= 0 && tstamp
>= start
)
1984 /* Let's ask for a sync, but only once. */
1986 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1988 r
= bus_connect_system_systemd(&bus
);
1990 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1992 r
= sd_bus_call_method(
1994 "org.freedesktop.systemd1",
1995 "/org/freedesktop/systemd1",
1996 "org.freedesktop.systemd1.Manager",
2000 "ssi", "systemd-journald.service", "main", sig
);
2002 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
2007 /* Let's install the inotify watch, if we didn't do that yet. */
2010 mkdir_p("/run/systemd/journal", 0755);
2012 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
2014 return log_error_errno(errno
, "Failed to create inotify watch: %m");
2016 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_MOVED_TO
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
2018 return log_error_errno(errno
, "Failed to watch journal directory: %m");
2020 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
2024 /* OK, all preparatory steps done, let's wait until
2025 * inotify reports an event. */
2027 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
2029 return log_error_errno(r
, "Failed to wait for event: %m");
2031 r
= flush_fd(watch_fd
);
2033 return log_error_errno(r
, "Failed to flush inotify events: %m");
2039 static int rotate(void) {
2040 return send_signal_and_wait(SIGUSR2
, "/run/systemd/journal/rotated");
2043 static int sync_journal(void) {
2044 return send_signal_and_wait(SIGRTMIN
+1, "/run/systemd/journal/synced");
2047 static int wait_for_change(sd_journal
*j
, int poll_fd
) {
2048 struct pollfd pollfds
[] = {
2049 { .fd
= poll_fd
, .events
= POLLIN
},
2050 { .fd
= STDOUT_FILENO
},
2058 assert(poll_fd
>= 0);
2060 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
2061 * i.e. when it is closed. */
2063 r
= sd_journal_get_timeout(j
, &timeout
);
2065 return log_error_errno(r
, "Failed to determine journal waiting time: %m");
2067 if (ppoll(pollfds
, ELEMENTSOF(pollfds
),
2068 timeout
== USEC_INFINITY
? NULL
: timespec_store(&ts
, timeout
), NULL
) < 0) {
2072 return log_error_errno(errno
, "Couldn't wait for journal event: %m");
2075 if (pollfds
[1].revents
& (POLLHUP
|POLLERR
)) /* STDOUT has been closed? */
2076 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED
),
2077 "Standard output has been closed.");
2079 r
= sd_journal_process(j
);
2081 return log_error_errno(r
, "Failed to process journal events: %m");
2086 int main(int argc
, char *argv
[]) {
2087 bool previous_boot_id_valid
= false, first_line
= true, ellipsized
= false, need_seek
= false;
2088 bool use_cursor
= false, after_cursor
= false;
2089 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2090 sd_id128_t previous_boot_id
;
2091 int n_shown
= 0, r
, poll_fd
= -1;
2093 setlocale(LC_ALL
, "");
2094 log_parse_environment();
2097 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2098 * split up into many files. */
2099 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
2101 r
= parse_argv(argc
, argv
);
2105 signal(SIGWINCH
, columns_lines_cache_reset
);
2108 switch (arg_action
) {
2110 case ACTION_NEW_ID128
:
2111 r
= id128_print_new(true);
2114 case ACTION_SETUP_KEYS
:
2118 case ACTION_LIST_CATALOG
:
2119 case ACTION_DUMP_CATALOG
:
2120 case ACTION_UPDATE_CATALOG
: {
2121 _cleanup_free_
char *database
;
2123 database
= path_join(arg_root
, CATALOG_DATABASE
);
2129 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2130 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2132 log_error_errno(r
, "Failed to list catalog: %m");
2134 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2136 (void) pager_open(arg_pager_flags
);
2139 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2141 r
= catalog_list(stdout
, database
, oneline
);
2143 log_error_errno(r
, "Failed to list catalog: %m");
2162 case ACTION_PRINT_HEADER
:
2164 case ACTION_DISK_USAGE
:
2165 case ACTION_LIST_BOOTS
:
2167 case ACTION_ROTATE_AND_VACUUM
:
2168 case ACTION_LIST_FIELDS
:
2169 case ACTION_LIST_FIELD_NAMES
:
2170 /* These ones require access to the journal files, continue below. */
2174 assert_not_reached("Unknown action");
2178 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2180 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2181 else if (arg_file_stdin
) {
2182 int ifd
= STDIN_FILENO
;
2183 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2184 } else if (arg_file
)
2185 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2186 else if (arg_machine
) {
2187 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2188 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2189 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2192 if (geteuid() != 0) {
2193 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2194 * the container, thus we need root privileges to override them. */
2195 log_error("Using the --machine= switch requires root privileges.");
2200 r
= sd_bus_open_system(&bus
);
2202 log_error_errno(r
, "Failed to open system bus: %m");
2206 r
= sd_bus_call_method(
2208 "org.freedesktop.machine1",
2209 "/org/freedesktop/machine1",
2210 "org.freedesktop.machine1.Manager",
2211 "OpenMachineRootDirectory",
2216 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2220 r
= sd_bus_message_read(reply
, "h", &fd
);
2222 bus_log_parse_error(r
);
2226 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2228 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2232 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2236 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2238 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2242 r
= journal_access_check_and_warn(j
, arg_quiet
,
2243 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2247 switch (arg_action
) {
2249 case ACTION_NEW_ID128
:
2250 case ACTION_SETUP_KEYS
:
2251 case ACTION_LIST_CATALOG
:
2252 case ACTION_DUMP_CATALOG
:
2253 case ACTION_UPDATE_CATALOG
:
2257 assert_not_reached("Unexpected action.");
2259 case ACTION_PRINT_HEADER
:
2260 journal_print_header(j
);
2268 case ACTION_DISK_USAGE
: {
2270 char sbytes
[FORMAT_BYTES_MAX
];
2272 r
= sd_journal_get_usage(j
, &bytes
);
2276 printf("Archived and active journals take up %s in the file system.\n",
2277 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2281 case ACTION_LIST_BOOTS
:
2285 case ACTION_ROTATE_AND_VACUUM
:
2293 case ACTION_VACUUM
: {
2297 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2303 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2305 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2313 case ACTION_LIST_FIELD_NAMES
: {
2316 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2317 printf("%s\n", field
);
2326 case ACTION_LIST_FIELDS
:
2330 assert_not_reached("Unknown action");
2333 if (arg_boot_offset
!= 0 &&
2334 sd_journal_has_runtime_files(j
) > 0 &&
2335 sd_journal_has_persistent_files(j
) == 0) {
2336 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2340 /* add_boot() must be called first!
2341 * It may need to seek the journal to find parent boot IDs. */
2352 log_error_errno(r
, "Failed to add filter for units: %m");
2356 r
= add_syslog_identifier(j
);
2358 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2362 r
= add_priorities(j
);
2366 r
= add_matches(j
, argv
+ optind
);
2370 if (DEBUG_LOGGING
) {
2371 _cleanup_free_
char *filter
;
2373 filter
= journal_make_match_string(j
);
2377 log_debug("Journal filter: %s", filter
);
2380 if (arg_action
== ACTION_LIST_FIELDS
) {
2386 r
= sd_journal_set_data_threshold(j
, 0);
2388 log_error_errno(r
, "Failed to unset data size threshold: %m");
2392 r
= sd_journal_query_unique(j
, arg_field
);
2394 log_error_errno(r
, "Failed to query unique data objects: %m");
2398 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2401 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2404 eq
= memchr(data
, '=', size
);
2406 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2408 printf("%.*s\n", (int) size
, (const char*) data
);
2417 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2419 poll_fd
= sd_journal_get_fd(j
);
2420 if (poll_fd
== -EMFILE
) {
2421 log_warning_errno(poll_fd
, "Insufficent watch descriptors available. Reverting to -n.");
2423 } else if (poll_fd
== -EMEDIUMTYPE
) {
2424 log_error_errno(poll_fd
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2426 } else if (poll_fd
< 0) {
2427 log_error_errno(poll_fd
, "Failed to get journal fd: %m");
2432 if (arg_cursor
|| arg_after_cursor
|| arg_cursor_file
) {
2433 _cleanup_free_
char *cursor_from_file
= NULL
;
2434 const char *cursor
= arg_cursor
?: arg_after_cursor
;
2436 if (arg_cursor_file
) {
2437 r
= read_one_line_file(arg_cursor_file
, &cursor_from_file
);
2438 if (r
< 0 && r
!= -ENOENT
) {
2439 log_error_errno(r
, "Failed to read cursor file %s: %m", arg_cursor_file
);
2444 cursor
= cursor_from_file
;
2445 after_cursor
= true;
2448 after_cursor
= !!arg_after_cursor
;
2451 r
= sd_journal_seek_cursor(j
, cursor
);
2453 log_error_errno(r
, "Failed to seek to cursor: %m");
2462 r
= sd_journal_next_skip(j
, 1 + after_cursor
);
2464 r
= sd_journal_previous_skip(j
, 1 + after_cursor
);
2466 if (after_cursor
&& r
< 2) {
2467 /* We couldn't find the next entry after the cursor. */
2474 } else if (arg_since_set
&& !arg_reverse
) {
2475 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2477 log_error_errno(r
, "Failed to seek to date: %m");
2480 r
= sd_journal_next(j
);
2482 } else if (arg_until_set
&& arg_reverse
) {
2483 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2485 log_error_errno(r
, "Failed to seek to date: %m");
2488 r
= sd_journal_previous(j
);
2490 } else if (arg_lines
>= 0) {
2491 r
= sd_journal_seek_tail(j
);
2493 log_error_errno(r
, "Failed to seek to tail: %m");
2497 r
= sd_journal_previous_skip(j
, arg_lines
);
2499 } else if (arg_reverse
) {
2500 r
= sd_journal_seek_tail(j
);
2502 log_error_errno(r
, "Failed to seek to tail: %m");
2506 r
= sd_journal_previous(j
);
2509 r
= sd_journal_seek_head(j
);
2511 log_error_errno(r
, "Failed to seek to head: %m");
2515 r
= sd_journal_next(j
);
2519 log_error_errno(r
, "Failed to iterate through journal: %m");
2526 (void) pager_open(arg_pager_flags
);
2528 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2530 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2532 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2534 log_error_errno(r
, "Failed to get cutoff: %m");
2540 printf("-- Logs begin at %s. --\n",
2541 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2543 printf("-- Logs begin at %s, end at %s. --\n",
2544 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2545 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2550 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2552 size_t highlight
[2] = {};
2556 r
= sd_journal_next(j
);
2558 r
= sd_journal_previous(j
);
2560 log_error_errno(r
, "Failed to iterate through journal: %m");
2567 if (arg_until_set
&& !arg_reverse
) {
2570 r
= sd_journal_get_realtime_usec(j
, &usec
);
2572 log_error_errno(r
, "Failed to determine timestamp: %m");
2575 if (usec
> arg_until
)
2579 if (arg_since_set
&& arg_reverse
) {
2582 r
= sd_journal_get_realtime_usec(j
, &usec
);
2584 log_error_errno(r
, "Failed to determine timestamp: %m");
2587 if (usec
< arg_since
)
2591 if (!arg_merge
&& !arg_quiet
) {
2594 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2596 if (previous_boot_id_valid
&&
2597 !sd_id128_equal(boot_id
, previous_boot_id
))
2598 printf("%s-- Reboot --%s\n",
2599 ansi_highlight(), ansi_normal());
2601 previous_boot_id
= boot_id
;
2602 previous_boot_id_valid
= true;
2607 if (arg_compiled_pattern
) {
2608 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2609 const void *message
;
2613 md
= pcre2_match_data_create(1, NULL
);
2617 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2624 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2628 assert_se(message
= startswith(message
, "MESSAGE="));
2630 r
= pcre2_match(arg_compiled_pattern
,
2632 len
- strlen("MESSAGE="),
2633 0, /* start at offset 0 in the subject */
2634 0, /* default options */
2637 if (r
== PCRE2_ERROR_NOMATCH
) {
2642 unsigned char buf
[LINE_MAX
];
2645 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2646 log_error("Pattern matching failed: %s",
2647 r2
< 0 ? "unknown error" : (char*) buf
);
2652 ovec
= pcre2_get_ovector_pointer(md
);
2653 highlight
[0] = ovec
[0];
2654 highlight
[1] = ovec
[1];
2659 arg_all
* OUTPUT_SHOW_ALL
|
2660 arg_full
* OUTPUT_FULL_WIDTH
|
2661 colors_enabled() * OUTPUT_COLOR
|
2662 arg_catalog
* OUTPUT_CATALOG
|
2663 arg_utc
* OUTPUT_UTC
|
2664 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2666 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2667 arg_output_fields
, highlight
, &ellipsized
);
2669 if (r
== -EADDRNOTAVAIL
)
2676 /* If journalctl take a long time to process messages, and during that time journal file
2677 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2678 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2679 * in the "following" case. By periodically calling sd_journal_process() during the processing
2680 * loop we shrink the window of time a client instance has open file descriptors for rotated
2681 * (deleted) journal files. */
2682 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2683 r
= sd_journal_process(j
);
2685 log_error_errno(r
, "Failed to process inotify events: %m");
2692 if (n_shown
== 0 && !arg_quiet
)
2693 printf("-- No entries --\n");
2695 if (arg_show_cursor
|| arg_cursor_file
) {
2696 _cleanup_free_
char *cursor
= NULL
;
2698 r
= sd_journal_get_cursor(j
, &cursor
);
2699 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2700 log_error_errno(r
, "Failed to get cursor: %m");
2702 if (arg_show_cursor
)
2703 printf("-- cursor: %s\n", cursor
);
2705 if (arg_cursor_file
) {
2706 r
= write_string_file(arg_cursor_file
, cursor
,
2707 WRITE_STRING_FILE_CREATE
|
2708 WRITE_STRING_FILE_ATOMIC
);
2711 "Failed to write new cursor to %s: %m",
2722 r
= wait_for_change(j
, poll_fd
);
2733 strv_free(arg_file
);
2735 strv_free(arg_syslog_identifier
);
2736 strv_free(arg_system_units
);
2737 strv_free(arg_user_units
);
2738 strv_free(arg_output_fields
);
2741 free(arg_verify_key
);
2744 if (arg_compiled_pattern
)
2745 pcre2_code_free(arg_compiled_pattern
);
2748 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;