1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include <sys/inotify.h>
20 # define PCRE2_CODE_UNIT_WIDTH 8
25 #include "sd-journal.h"
28 #include "alloc-util.h"
29 #include "bus-error.h"
32 #include "chattr-util.h"
37 #include "glob-util.h"
38 #include "hostname-util.h"
40 #include "journal-def.h"
41 #include "journal-internal.h"
42 #include "journal-qrcode.h"
43 #include "journal-util.h"
44 #include "journal-vacuum.h"
45 #include "journal-verify.h"
46 #include "locale-util.h"
48 #include "logs-show.h"
51 #include "parse-util.h"
52 #include "path-util.h"
53 #include "rlimit-util.h"
56 #include "string-table.h"
58 #include "syslog-util.h"
59 #include "terminal-util.h"
60 #include "udev-util.h"
62 #include "unit-name.h"
63 #include "user-util.h"
65 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
67 #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
70 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data
*, pcre2_match_data_free
);
71 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code
*, pcre2_code_free
);
73 static int pattern_compile(const char *pattern
, unsigned flags
, pcre2_code
**out
) {
75 PCRE2_SIZE erroroffset
;
78 p
= pcre2_compile((PCRE2_SPTR8
) pattern
,
79 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
81 unsigned char buf
[LINE_MAX
];
83 r
= pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
85 log_error("Bad pattern \"%s\": %s",
87 r
< 0 ? "unknown error" : (char*) buf
);
98 /* Special values for arg_lines */
99 ARG_LINES_DEFAULT
= -2,
103 static OutputMode arg_output
= OUTPUT_SHORT
;
104 static bool arg_utc
= false;
105 static bool arg_pager_end
= false;
106 static bool arg_follow
= false;
107 static bool arg_full
= true;
108 static bool arg_all
= false;
109 static bool arg_no_pager
= false;
110 static int arg_lines
= ARG_LINES_DEFAULT
;
111 static bool arg_no_tail
= false;
112 static bool arg_quiet
= false;
113 static bool arg_merge
= false;
114 static bool arg_boot
= false;
115 static sd_id128_t arg_boot_id
= {};
116 static int arg_boot_offset
= 0;
117 static bool arg_dmesg
= false;
118 static bool arg_no_hostname
= false;
119 static const char *arg_cursor
= NULL
;
120 static const char *arg_after_cursor
= NULL
;
121 static bool arg_show_cursor
= false;
122 static const char *arg_directory
= NULL
;
123 static char **arg_file
= NULL
;
124 static bool arg_file_stdin
= false;
125 static int arg_priorities
= 0xFF;
126 static char *arg_verify_key
= NULL
;
128 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
129 static bool arg_force
= false;
131 static usec_t arg_since
, arg_until
;
132 static bool arg_since_set
= false, arg_until_set
= false;
133 static char **arg_syslog_identifier
= NULL
;
134 static char **arg_system_units
= NULL
;
135 static char **arg_user_units
= NULL
;
136 static const char *arg_field
= NULL
;
137 static bool arg_catalog
= false;
138 static bool arg_reverse
= false;
139 static int arg_journal_type
= 0;
140 static char *arg_root
= NULL
;
141 static const char *arg_machine
= NULL
;
142 static uint64_t arg_vacuum_size
= 0;
143 static uint64_t arg_vacuum_n_files
= 0;
144 static usec_t arg_vacuum_time
= 0;
145 static char **arg_output_fields
= NULL
;
148 static const char *arg_pattern
= NULL
;
149 static pcre2_code
*arg_compiled_pattern
= NULL
;
150 static int arg_case_sensitive
= -1; /* -1 means be smart */
162 ACTION_UPDATE_CATALOG
,
169 ACTION_LIST_FIELD_NAMES
,
170 } arg_action
= ACTION_SHOW
;
172 typedef struct BootId
{
176 LIST_FIELDS(struct BootId
, boot_list
);
179 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
180 _cleanup_(udev_unrefp
) struct udev
*udev
= NULL
;
181 _cleanup_(udev_device_unrefp
) struct udev_device
*device
= NULL
;
182 struct udev_device
*d
= NULL
;
189 if (!path_startswith(devpath
, "/dev/")) {
190 log_error("Devpath does not start with /dev/");
198 if (stat(devpath
, &st
) < 0)
199 return log_error_errno(errno
, "Couldn't stat file: %m");
201 r
= udev_device_new_from_stat_rdev(udev
, &st
, &device
);
203 return log_error_errno(r
, "Failed to get udev device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
207 _cleanup_free_
char *match
= NULL
;
208 const char *subsys
, *sysname
, *devnode
;
210 subsys
= udev_device_get_subsystem(d
);
212 d
= udev_device_get_parent(d
);
216 sysname
= udev_device_get_sysname(d
);
218 d
= udev_device_get_parent(d
);
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 devnode
= udev_device_get_devnode(d
);
232 _cleanup_free_
char *match1
= NULL
;
234 r
= stat(devnode
, &st
);
236 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
238 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
242 r
= sd_journal_add_match(j
, match1
, 0);
244 return log_error_errno(r
, "Failed to add match: %m");
247 d
= udev_device_get_parent(d
);
250 r
= add_match_this_boot(j
, arg_machine
);
252 return log_error_errno(r
, "Failed to add match for the current boot: %m");
257 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
260 return format_timestamp_utc(buf
, l
, t
);
262 return format_timestamp(buf
, l
, t
);
265 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
266 sd_id128_t id
= SD_ID128_NULL
;
269 if (strlen(x
) >= 32) {
273 r
= sd_id128_from_string(t
, &id
);
277 if (!IN_SET(*x
, 0, '-', '+'))
281 r
= safe_atoi(x
, &off
);
286 r
= safe_atoi(x
, &off
);
300 static void help(void) {
302 (void) pager_open(arg_no_pager
, arg_pager_end
);
304 printf("%s [OPTIONS...] [MATCHES...]\n\n"
305 "Query the journal.\n\n"
307 " --system Show the system journal\n"
308 " --user Show the user journal for the current user\n"
309 " -M --machine=CONTAINER Operate on local container\n"
310 " -S --since=DATE Show entries not older than the specified date\n"
311 " -U --until=DATE Show entries not newer than the specified date\n"
312 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
313 " --after-cursor=CURSOR Show entries after the specified cursor\n"
314 " --show-cursor Print the cursor after all the entries\n"
315 " -b --boot[=ID] Show current boot or the specified boot\n"
316 " --list-boots Show terse information about recorded boots\n"
317 " -k --dmesg Show kernel message log from the current boot\n"
318 " -u --unit=UNIT Show logs from the specified unit\n"
319 " --user-unit=UNIT Show logs from the specified user unit\n"
320 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
321 " -p --priority=RANGE Show entries with the specified priority\n"
322 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
323 " --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n"
324 " -e --pager-end Immediately jump to the end in the pager\n"
325 " -f --follow Follow the journal\n"
326 " -n --lines[=INTEGER] Number of journal entries to show\n"
327 " --no-tail Show all lines, even in follow mode\n"
328 " -r --reverse Show the newest entries first\n"
329 " -o --output=STRING Change journal output mode (short, short-precise,\n"
330 " short-iso, short-iso-precise, short-full,\n"
331 " short-monotonic, short-unix, verbose, export,\n"
332 " json, json-pretty, json-sse, cat, with-unit)\n"
333 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
334 " --utc Express time in Coordinated Universal Time (UTC)\n"
335 " -x --catalog Add message explanations where available\n"
336 " --no-full Ellipsize fields\n"
337 " -a --all Show all fields, including long and unprintable\n"
338 " -q --quiet Do not show info messages and privilege warning\n"
339 " --no-pager Do not pipe output into a pager\n"
340 " --no-hostname Suppress output of hostname field\n"
341 " -m --merge Show entries from all available journals\n"
342 " -D --directory=PATH Show journal files from directory\n"
343 " --file=PATH Show journal file\n"
344 " --root=ROOT Operate on files below a root directory\n"
345 " --interval=TIME Time interval for changing the FSS sealing key\n"
346 " --verify-key=KEY Specify FSS verification key\n"
347 " --force Override of the FSS key pair with --setup-keys\n"
349 " -h --help Show this help text\n"
350 " --version Show package version\n"
351 " -N --fields List all field names currently used\n"
352 " -F --field=FIELD List all values that a specified field takes\n"
353 " --disk-usage Show total disk usage of all journal files\n"
354 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
355 " --vacuum-files=INT Leave only the specified number of journal files\n"
356 " --vacuum-time=TIME Remove journal files older than specified time\n"
357 " --verify Verify journal file consistency\n"
358 " --sync Synchronize unwritten journal messages to disk\n"
359 " --flush Flush all journal data from /run into /var\n"
360 " --rotate Request immediate rotation of the journal files\n"
361 " --header Show journal header information\n"
362 " --list-catalog Show all message IDs in the catalog\n"
363 " --dump-catalog Show entries in the message catalog\n"
364 " --update-catalog Update the message catalog database\n"
365 " --new-id128 Generate a new 128-bit ID\n"
366 " --setup-keys Generate a new FSS key pair\n"
367 , program_invocation_short_name
);
370 static int parse_argv(int argc
, char *argv
[]) {
409 static const struct option options
[] = {
410 { "help", no_argument
, NULL
, 'h' },
411 { "version" , no_argument
, NULL
, ARG_VERSION
},
412 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
413 { "pager-end", no_argument
, NULL
, 'e' },
414 { "follow", no_argument
, NULL
, 'f' },
415 { "force", no_argument
, NULL
, ARG_FORCE
},
416 { "output", required_argument
, NULL
, 'o' },
417 { "all", no_argument
, NULL
, 'a' },
418 { "full", no_argument
, NULL
, 'l' },
419 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
420 { "lines", optional_argument
, NULL
, 'n' },
421 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
422 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
423 { "quiet", no_argument
, NULL
, 'q' },
424 { "merge", no_argument
, NULL
, 'm' },
425 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
426 { "boot", optional_argument
, NULL
, 'b' },
427 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
428 { "dmesg", no_argument
, NULL
, 'k' },
429 { "system", no_argument
, NULL
, ARG_SYSTEM
},
430 { "user", no_argument
, NULL
, ARG_USER
},
431 { "directory", required_argument
, NULL
, 'D' },
432 { "file", required_argument
, NULL
, ARG_FILE
},
433 { "root", required_argument
, NULL
, ARG_ROOT
},
434 { "header", no_argument
, NULL
, ARG_HEADER
},
435 { "identifier", required_argument
, NULL
, 't' },
436 { "priority", required_argument
, NULL
, 'p' },
437 { "grep", required_argument
, NULL
, 'g' },
438 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
439 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
440 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
441 { "verify", no_argument
, NULL
, ARG_VERIFY
},
442 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
443 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
444 { "cursor", required_argument
, NULL
, 'c' },
445 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
446 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
447 { "since", required_argument
, NULL
, 'S' },
448 { "until", required_argument
, NULL
, 'U' },
449 { "unit", required_argument
, NULL
, 'u' },
450 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
451 { "field", required_argument
, NULL
, 'F' },
452 { "fields", no_argument
, NULL
, 'N' },
453 { "catalog", no_argument
, NULL
, 'x' },
454 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
455 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
456 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
457 { "reverse", no_argument
, NULL
, 'r' },
458 { "machine", required_argument
, NULL
, 'M' },
459 { "utc", no_argument
, NULL
, ARG_UTC
},
460 { "flush", no_argument
, NULL
, ARG_FLUSH
},
461 { "sync", no_argument
, NULL
, ARG_SYNC
},
462 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
463 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
464 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
465 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
466 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
467 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
476 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
492 arg_pager_end
= true;
494 if (arg_lines
== ARG_LINES_DEFAULT
)
504 if (streq(optarg
, "help")) {
505 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
509 arg_output
= output_mode_from_string(optarg
);
510 if (arg_output
< 0) {
511 log_error("Unknown output format '%s'.", optarg
);
515 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_CAT
))
534 if (streq(optarg
, "all"))
535 arg_lines
= ARG_LINES_ALL
;
537 r
= safe_atoi(optarg
, &arg_lines
);
538 if (r
< 0 || arg_lines
< 0) {
539 log_error("Failed to parse lines '%s'", optarg
);
546 /* Hmm, no argument? Maybe the next
547 * word on the command line is
548 * supposed to be the argument? Let's
549 * see if there is one, and is
553 if (streq(argv
[optind
], "all")) {
554 arg_lines
= ARG_LINES_ALL
;
556 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
570 arg_action
= ACTION_NEW_ID128
;
589 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
591 log_error("Failed to parse boot descriptor '%s'", optarg
);
596 /* Hmm, no argument? Maybe the next
597 * word on the command line is
598 * supposed to be the argument? Let's
599 * see if there is one and is parsable
600 * as a boot descriptor... */
603 parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
) >= 0)
610 arg_action
= ACTION_LIST_BOOTS
;
614 arg_boot
= arg_dmesg
= true;
618 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
622 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
626 arg_machine
= optarg
;
630 arg_directory
= optarg
;
634 if (streq(optarg
, "-"))
635 /* An undocumented feature: we can read journal files from STDIN. We don't document
636 * this though, since after all we only support this for mmap-able, seekable files, and
637 * not for example pipes which are probably the primary usecase for reading things from
638 * STDIN. To avoid confusion we hence don't document this feature. */
639 arg_file_stdin
= true;
641 r
= glob_extend(&arg_file
, optarg
);
643 return log_error_errno(r
, "Failed to add paths: %m");
648 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
657 case ARG_AFTER_CURSOR
:
658 arg_after_cursor
= optarg
;
661 case ARG_SHOW_CURSOR
:
662 arg_show_cursor
= true;
666 arg_action
= ACTION_PRINT_HEADER
;
670 arg_action
= ACTION_VERIFY
;
674 arg_action
= ACTION_DISK_USAGE
;
677 case ARG_VACUUM_SIZE
:
678 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
680 log_error("Failed to parse vacuum size: %s", optarg
);
684 arg_action
= ACTION_VACUUM
;
687 case ARG_VACUUM_FILES
:
688 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
690 log_error("Failed to parse vacuum files: %s", optarg
);
694 arg_action
= ACTION_VACUUM
;
697 case ARG_VACUUM_TIME
:
698 r
= parse_sec(optarg
, &arg_vacuum_time
);
700 log_error("Failed to parse vacuum time: %s", optarg
);
704 arg_action
= ACTION_VACUUM
;
713 arg_action
= ACTION_SETUP_KEYS
;
717 arg_action
= ACTION_VERIFY
;
718 r
= free_and_strdup(&arg_verify_key
, optarg
);
721 /* Use memset not string_erase so this doesn't look confusing
722 * in ps or htop output. */
723 memset(optarg
, 'x', strlen(optarg
));
729 r
= parse_sec(optarg
, &arg_interval
);
730 if (r
< 0 || arg_interval
<= 0) {
731 log_error("Failed to parse sealing key change interval: %s", optarg
);
740 log_error("Compiled without forward-secure sealing support.");
747 dots
= strstr(optarg
, "..");
753 a
= strndup(optarg
, dots
- optarg
);
757 from
= log_level_from_string(a
);
758 to
= log_level_from_string(dots
+ 2);
761 if (from
< 0 || to
< 0) {
762 log_error("Failed to parse log level range %s", optarg
);
769 for (i
= from
; i
<= to
; i
++)
770 arg_priorities
|= 1 << i
;
772 for (i
= to
; i
<= from
; i
++)
773 arg_priorities
|= 1 << i
;
779 p
= log_level_from_string(optarg
);
781 log_error("Unknown log level %s", optarg
);
787 for (i
= 0; i
<= p
; i
++)
788 arg_priorities
|= 1 << i
;
796 arg_pattern
= optarg
;
799 case ARG_CASE_SENSITIVE
:
801 r
= parse_boolean(optarg
);
803 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
804 arg_case_sensitive
= r
;
806 arg_case_sensitive
= true;
811 case ARG_CASE_SENSITIVE
:
812 return log_error("Compiled without pattern matching support");
816 r
= parse_timestamp(optarg
, &arg_since
);
818 log_error("Failed to parse timestamp: %s", optarg
);
821 arg_since_set
= true;
825 r
= parse_timestamp(optarg
, &arg_until
);
827 log_error("Failed to parse timestamp: %s", optarg
);
830 arg_until_set
= true;
834 r
= strv_extend(&arg_syslog_identifier
, optarg
);
840 r
= strv_extend(&arg_system_units
, optarg
);
846 r
= strv_extend(&arg_user_units
, optarg
);
852 arg_action
= ACTION_LIST_FIELDS
;
857 arg_action
= ACTION_LIST_FIELD_NAMES
;
860 case ARG_NO_HOSTNAME
:
861 arg_no_hostname
= true;
868 case ARG_LIST_CATALOG
:
869 arg_action
= ACTION_LIST_CATALOG
;
872 case ARG_DUMP_CATALOG
:
873 arg_action
= ACTION_DUMP_CATALOG
;
876 case ARG_UPDATE_CATALOG
:
877 arg_action
= ACTION_UPDATE_CATALOG
;
889 arg_action
= ACTION_FLUSH
;
893 arg_action
= ACTION_ROTATE
;
897 arg_action
= ACTION_SYNC
;
900 case ARG_OUTPUT_FIELDS
: {
901 _cleanup_strv_free_
char **v
= NULL
;
903 v
= strv_split(optarg
, ",");
907 if (!arg_output_fields
)
908 arg_output_fields
= TAKE_PTR(v
);
910 r
= strv_extend_strv(&arg_output_fields
, v
, true);
921 assert_not_reached("Unhandled option");
924 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
927 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
> 1) {
928 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
932 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
933 log_error("--since= must be before --until=.");
937 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
938 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
942 if (arg_follow
&& arg_reverse
) {
943 log_error("Please specify either --reverse= or --follow=, not both.");
947 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
948 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
952 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
953 log_error("Using --boot or --list-boots with --merge is not supported.");
957 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
958 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
959 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
960 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
961 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
965 arg_system_units
= strv_free(arg_system_units
);
972 if (arg_case_sensitive
>= 0)
973 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
975 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
977 _cleanup_(pcre2_code_freep
) pcre2_code
*cs
= NULL
;
979 md
= pcre2_match_data_create(1, NULL
);
983 r
= pattern_compile("[[:upper:]]", 0, &cs
);
987 r
= pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
990 flags
= !has_case
* PCRE2_CASELESS
;
993 log_debug("Doing case %s matching based on %s",
994 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
995 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
997 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1006 static int generate_new_id128(void) {
1011 r
= sd_id128_randomize(&id
);
1013 return log_error_errno(r
, "Failed to generate ID: %m");
1015 printf("As string:\n"
1016 SD_ID128_FORMAT_STR
"\n\n"
1018 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
1019 "As man:sd-id128(3) macro:\n"
1020 "#define MESSAGE_XYZ SD_ID128_MAKE(",
1021 SD_ID128_FORMAT_VAL(id
),
1022 SD_ID128_FORMAT_VAL(id
));
1023 for (i
= 0; i
< 16; i
++)
1024 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
1025 fputs(")\n\n", stdout
);
1027 printf("As Python constant:\n"
1029 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
1030 SD_ID128_FORMAT_VAL(id
));
1035 static int add_matches(sd_journal
*j
, char **args
) {
1037 bool have_term
= false;
1041 STRV_FOREACH(i
, args
) {
1044 if (streq(*i
, "+")) {
1047 r
= sd_journal_add_disjunction(j
);
1050 } else if (path_is_absolute(*i
)) {
1051 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1054 r
= chase_symlinks(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
);
1056 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1058 if (lstat(p
, &st
) < 0)
1059 return log_error_errno(errno
, "Couldn't stat file: %m");
1061 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1062 if (executable_is_script(p
, &interpreter
) > 0) {
1063 _cleanup_free_
char *comm
;
1065 comm
= strndup(basename(p
), 15);
1069 t
= strappend("_COMM=", comm
);
1073 /* Append _EXE only if the interpreter is not a link.
1074 Otherwise, it might be outdated often. */
1075 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1076 t2
= strappend("_EXE=", interpreter
);
1081 t
= strappend("_EXE=", p
);
1086 r
= sd_journal_add_match(j
, t
, 0);
1089 r
= sd_journal_add_match(j
, t2
, 0);
1091 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1092 r
= add_matches_for_device(j
, p
);
1096 log_error("File is neither a device node, nor regular file, nor executable: %s", *i
);
1102 r
= sd_journal_add_match(j
, *i
, 0);
1107 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1110 if (!strv_isempty(args
) && !have_term
) {
1111 log_error("\"+\" can only be used between terms");
1118 static void boot_id_free_all(BootId
*l
) {
1122 LIST_REMOVE(boot_list
, l
, i
);
1127 static int discover_next_boot(sd_journal
*j
,
1128 sd_id128_t previous_boot_id
,
1132 _cleanup_free_ BootId
*next_boot
= NULL
;
1133 char match
[9+32+1] = "_BOOT_ID=";
1140 /* We expect the journal to be on the last position of a boot
1141 * (in relation to the direction we are going), so that the next
1142 * invocation of sd_journal_next/previous will be from a different
1143 * boot. We then collect any information we desire and then jump
1144 * to the last location of the new boot by using a _BOOT_ID match
1145 * coming from the other journal direction. */
1147 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1148 * we can actually advance to a *different* boot. */
1149 sd_journal_flush_matches(j
);
1153 r
= sd_journal_previous(j
);
1155 r
= sd_journal_next(j
);
1159 return 0; /* End of journal, yay. */
1161 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1165 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1166 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1167 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1168 * complete than the main entry array, and hence might reference an entry that's not actually the last
1169 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1170 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1173 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1175 next_boot
= new0(BootId
, 1);
1179 next_boot
->id
= boot_id
;
1181 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1185 /* Now seek to the last occurrence of this boot ID. */
1186 sd_id128_to_string(next_boot
->id
, match
+ 9);
1187 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1192 r
= sd_journal_seek_head(j
);
1194 r
= sd_journal_seek_tail(j
);
1199 r
= sd_journal_next(j
);
1201 r
= sd_journal_previous(j
);
1205 log_debug("Whoopsie! We found a boot ID but can't read its last entry.");
1206 return -ENODATA
; /* This shouldn't happen. We just came from this very boot ID. */
1209 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1213 *ret
= TAKE_PTR(next_boot
);
1218 static int get_boots(
1221 sd_id128_t
*boot_id
,
1226 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1227 const bool advance_older
= boot_id
&& offset
<= 0;
1228 sd_id128_t previous_boot_id
;
1232 /* Adjust for the asymmetry that offset 0 is
1233 * the last (and current) boot, while 1 is considered the
1234 * (chronological) first boot in the journal. */
1235 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1237 /* Advance to the earliest/latest occurrence of our reference
1238 * boot ID (taking our lookup direction into account), so that
1239 * discover_next_boot() can do its job.
1240 * If no reference is given, the journal head/tail will do,
1241 * they're "virtual" boots after all. */
1242 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1243 char match
[9+32+1] = "_BOOT_ID=";
1245 sd_journal_flush_matches(j
);
1247 sd_id128_to_string(*boot_id
, match
+ 9);
1248 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1253 r
= sd_journal_seek_head(j
); /* seek to oldest */
1255 r
= sd_journal_seek_tail(j
); /* seek to newest */
1260 r
= sd_journal_next(j
); /* read the oldest entry */
1262 r
= sd_journal_previous(j
); /* read the most recently added entry */
1267 else if (offset
== 0) {
1272 /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
1273 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1274 * the following entry, which must then have an older/newer boot ID */
1278 r
= sd_journal_seek_tail(j
); /* seek to newest */
1280 r
= sd_journal_seek_head(j
); /* seek to oldest */
1284 /* No sd_journal_next()/_previous() here.
1286 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1287 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1291 previous_boot_id
= SD_ID128_NULL
;
1293 _cleanup_free_ BootId
*current
= NULL
;
1295 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1297 boot_id_free_all(head
);
1304 previous_boot_id
= current
->id
;
1308 offset
+= advance_older
? 1 : -1;
1313 *boot_id
= current
->id
;
1317 LIST_FOREACH(boot_list
, id
, head
) {
1318 if (sd_id128_equal(id
->id
, current
->id
)) {
1319 /* boot id already stored, something wrong with the journal files */
1320 /* exiting as otherwise this problem would cause forever loop */
1324 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1325 tail
= TAKE_PTR(current
);
1334 sd_journal_flush_matches(j
);
1339 static int list_boots(sd_journal
*j
) {
1341 BootId
*id
, *all_ids
;
1345 count
= get_boots(j
, &all_ids
, NULL
, 0);
1347 return log_error_errno(count
, "Failed to determine boots: %m");
1351 (void) pager_open(arg_no_pager
, arg_pager_end
);
1353 /* numbers are one less, but we need an extra char for the sign */
1354 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1357 LIST_FOREACH(boot_list
, id
, all_ids
) {
1358 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1360 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1362 SD_ID128_FORMAT_VAL(id
->id
),
1363 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1364 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1368 boot_id_free_all(all_ids
);
1373 static int add_boot(sd_journal
*j
) {
1374 char match
[9+32+1] = "_BOOT_ID=";
1383 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1384 * We can do this only when we logs are coming from the current machine,
1385 * so take the slow path if log location is specified. */
1386 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1387 !arg_directory
&& !arg_file
&& !arg_root
)
1389 return add_match_this_boot(j
, arg_machine
);
1391 boot_id
= arg_boot_id
;
1392 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1395 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror(-r
);
1397 if (sd_id128_is_null(arg_boot_id
))
1398 log_error("Data from the specified boot (%+i) is not available: %s",
1399 arg_boot_offset
, reason
);
1401 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1402 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1404 return r
== 0 ? -ENODATA
: r
;
1407 sd_id128_to_string(boot_id
, match
+ 9);
1409 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1411 return log_error_errno(r
, "Failed to add match: %m");
1413 r
= sd_journal_add_conjunction(j
);
1415 return log_error_errno(r
, "Failed to add conjunction: %m");
1420 static int add_dmesg(sd_journal
*j
) {
1427 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1428 STRLEN("_TRANSPORT=kernel"));
1430 return log_error_errno(r
, "Failed to add match: %m");
1432 r
= sd_journal_add_conjunction(j
);
1434 return log_error_errno(r
, "Failed to add conjunction: %m");
1439 static int get_possible_units(
1445 _cleanup_set_free_free_ Set
*found
;
1449 found
= set_new(&string_hash_ops
);
1453 NULSTR_FOREACH(field
, fields
) {
1457 r
= sd_journal_query_unique(j
, field
);
1461 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1462 char **pattern
, *eq
;
1464 _cleanup_free_
char *u
= NULL
;
1466 eq
= memchr(data
, '=', size
);
1468 prefix
= eq
- (char*) data
+ 1;
1472 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1476 STRV_FOREACH(pattern
, patterns
)
1477 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1478 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1480 r
= set_consume(found
, u
);
1482 if (r
< 0 && r
!= -EEXIST
)
1490 *units
= TAKE_PTR(found
);
1495 /* This list is supposed to return the superset of unit names
1496 * possibly matched by rules added with add_matches_for_unit... */
1497 #define SYSTEM_UNITS \
1501 "OBJECT_SYSTEMD_UNIT\0" \
1504 /* ... and add_matches_for_user_unit */
1505 #define USER_UNITS \
1506 "_SYSTEMD_USER_UNIT\0" \
1508 "COREDUMP_USER_UNIT\0" \
1509 "OBJECT_SYSTEMD_USER_UNIT\0"
1511 static int add_units(sd_journal
*j
) {
1512 _cleanup_strv_free_
char **patterns
= NULL
;
1518 STRV_FOREACH(i
, arg_system_units
) {
1519 _cleanup_free_
char *u
= NULL
;
1521 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1525 if (string_is_glob(u
)) {
1526 r
= strv_push(&patterns
, u
);
1531 r
= add_matches_for_unit(j
, u
);
1534 r
= sd_journal_add_disjunction(j
);
1541 if (!strv_isempty(patterns
)) {
1542 _cleanup_set_free_free_ Set
*units
= NULL
;
1546 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1550 SET_FOREACH(u
, units
, it
) {
1551 r
= add_matches_for_unit(j
, u
);
1554 r
= sd_journal_add_disjunction(j
);
1561 patterns
= strv_free(patterns
);
1563 STRV_FOREACH(i
, arg_user_units
) {
1564 _cleanup_free_
char *u
= NULL
;
1566 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1570 if (string_is_glob(u
)) {
1571 r
= strv_push(&patterns
, u
);
1576 r
= add_matches_for_user_unit(j
, u
, getuid());
1579 r
= sd_journal_add_disjunction(j
);
1586 if (!strv_isempty(patterns
)) {
1587 _cleanup_set_free_free_ Set
*units
= NULL
;
1591 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1595 SET_FOREACH(u
, units
, it
) {
1596 r
= add_matches_for_user_unit(j
, u
, getuid());
1599 r
= sd_journal_add_disjunction(j
);
1606 /* Complain if the user request matches but nothing whatsoever was
1607 * found, since otherwise everything would be matched. */
1608 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1611 r
= sd_journal_add_conjunction(j
);
1618 static int add_priorities(sd_journal
*j
) {
1619 char match
[] = "PRIORITY=0";
1623 if (arg_priorities
== 0xFF)
1626 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1627 if (arg_priorities
& (1 << i
)) {
1628 match
[sizeof(match
)-2] = '0' + i
;
1630 r
= sd_journal_add_match(j
, match
, strlen(match
));
1632 return log_error_errno(r
, "Failed to add match: %m");
1635 r
= sd_journal_add_conjunction(j
);
1637 return log_error_errno(r
, "Failed to add conjunction: %m");
1642 static int add_syslog_identifier(sd_journal
*j
) {
1648 STRV_FOREACH(i
, arg_syslog_identifier
) {
1651 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1652 r
= sd_journal_add_match(j
, u
, 0);
1655 r
= sd_journal_add_disjunction(j
);
1660 r
= sd_journal_add_conjunction(j
);
1667 static int setup_keys(void) {
1669 size_t mpk_size
, seed_size
, state_size
, i
;
1670 uint8_t *mpk
, *seed
, *state
;
1672 sd_id128_t machine
, boot
;
1673 char *p
= NULL
, *k
= NULL
;
1678 r
= stat("/var/log/journal", &st
);
1679 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1680 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1682 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1683 log_error("%s is not a directory, must be using persistent logging for FSS.",
1684 "/var/log/journal");
1685 return r
< 0 ? -errno
: -ENOTDIR
;
1688 r
= sd_id128_get_machine(&machine
);
1690 return log_error_errno(r
, "Failed to get machine ID: %m");
1692 r
= sd_id128_get_boot(&boot
);
1694 return log_error_errno(r
, "Failed to get boot ID: %m");
1696 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1697 SD_ID128_FORMAT_VAL(machine
)) < 0)
1702 if (r
< 0 && errno
!= ENOENT
) {
1703 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1706 } else if (access(p
, F_OK
) >= 0) {
1707 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1712 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1713 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1718 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1719 mpk
= alloca(mpk_size
);
1721 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1722 seed
= alloca(seed_size
);
1724 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1725 state
= alloca(state_size
);
1727 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1729 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1733 log_info("Generating seed...");
1734 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1736 log_error_errno(r
, "Failed to read random seed: %m");
1740 log_info("Generating key pair...");
1741 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1743 log_info("Generating sealing key...");
1744 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1746 assert(arg_interval
> 0);
1748 n
= now(CLOCK_REALTIME
);
1752 fd
= mkostemp_safe(k
);
1754 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1758 /* Enable secure remove, exclusion from dump, synchronous
1759 * writing and in-place updating */
1760 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
);
1762 log_warning_errno(r
, "Failed to set file attributes: %m");
1765 memcpy(h
.signature
, "KSHHRHLP", 8);
1766 h
.machine_id
= machine
;
1768 h
.header_size
= htole64(sizeof(h
));
1769 h
.start_usec
= htole64(n
* arg_interval
);
1770 h
.interval_usec
= htole64(arg_interval
);
1771 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1772 h
.fsprg_state_size
= htole64(state_size
);
1774 r
= loop_write(fd
, &h
, sizeof(h
), false);
1776 log_error_errno(r
, "Failed to write header: %m");
1780 r
= loop_write(fd
, state
, state_size
, false);
1782 log_error_errno(r
, "Failed to write state: %m");
1786 if (link(k
, p
) < 0) {
1787 r
= log_error_errno(errno
, "Failed to link file: %m");
1794 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1795 "the following local file. This key file is automatically updated when the\n"
1796 "sealing key is advanced. It should not be used on multiple hosts.\n"
1800 "Please write down the following %ssecret verification key%s. It should be stored\n"
1801 "at a safe location and should not be saved locally on disk.\n"
1803 ansi_highlight(), ansi_normal(),
1805 ansi_highlight(), ansi_normal(),
1806 ansi_highlight_red());
1809 for (i
= 0; i
< seed_size
; i
++) {
1810 if (i
> 0 && i
% 3 == 0)
1812 printf("%02x", ((uint8_t*) seed
)[i
]);
1815 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1818 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1822 "The sealing key is automatically changed every %s.\n",
1824 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1826 hn
= gethostname_malloc();
1829 hostname_cleanup(hn
);
1830 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1832 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1835 /* If this is not an UTF-8 system don't print any QR codes */
1836 if (is_locale_utf8()) {
1837 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1838 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1858 log_error("Forward-secure sealing not available.");
1863 static int verify(sd_journal
*j
) {
1870 log_show_color(true);
1872 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1874 usec_t first
= 0, validated
= 0, last
= 0;
1877 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1878 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1881 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1883 /* If the key was invalid give up right-away. */
1886 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1889 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1890 log_info("PASS: %s", f
->path
);
1892 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1893 if (validated
> 0) {
1894 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1895 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1896 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1897 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1898 } else if (last
> 0)
1899 log_info("=> No sealing yet, %s of entries not sealed.",
1900 format_timespan(c
, sizeof(c
), last
- first
, 0));
1902 log_info("=> No sealing yet, no entries in file.");
1910 static int flush_to_var(void) {
1911 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1912 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1913 _cleanup_close_
int watch_fd
= -1;
1917 log_error("--flush is not supported in conjunction with --machine=.");
1922 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1925 /* OK, let's actually do the full logic, send SIGUSR1 to the
1926 * daemon and set up inotify to wait for the flushed file to appear */
1927 r
= bus_connect_system_systemd(&bus
);
1929 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1931 r
= sd_bus_call_method(
1933 "org.freedesktop.systemd1",
1934 "/org/freedesktop/systemd1",
1935 "org.freedesktop.systemd1.Manager",
1939 "ssi", "systemd-journald.service", "main", SIGUSR1
);
1941 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
1943 mkdir_p("/run/systemd/journal", 0755);
1945 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1947 return log_error_errno(errno
, "Failed to create inotify watch: %m");
1949 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_CREATE
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
1951 return log_error_errno(errno
, "Failed to watch journal directory: %m");
1954 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1957 if (errno
!= ENOENT
)
1958 return log_error_errno(errno
, "Failed to check for existence of /run/systemd/journal/flushed: %m");
1960 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
1962 return log_error_errno(r
, "Failed to wait for event: %m");
1964 r
= flush_fd(watch_fd
);
1966 return log_error_errno(r
, "Failed to flush inotify events: %m");
1972 static int send_signal_and_wait(int sig
, const char *watch_path
) {
1973 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1974 _cleanup_close_
int watch_fd
= -1;
1979 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
1983 start
= now(CLOCK_MONOTONIC
);
1985 /* This call sends the specified signal to journald, and waits
1986 * for acknowledgment by watching the mtime of the specified
1987 * flag file. This is used to trigger syncing or rotation and
1988 * then wait for the operation to complete. */
1993 /* See if a sync happened by now. */
1994 r
= read_timestamp_file(watch_path
, &tstamp
);
1995 if (r
< 0 && r
!= -ENOENT
)
1996 return log_error_errno(errno
, "Failed to read %s: %m", watch_path
);
1997 if (r
>= 0 && tstamp
>= start
)
2000 /* Let's ask for a sync, but only once. */
2002 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2004 r
= bus_connect_system_systemd(&bus
);
2006 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
2008 r
= sd_bus_call_method(
2010 "org.freedesktop.systemd1",
2011 "/org/freedesktop/systemd1",
2012 "org.freedesktop.systemd1.Manager",
2016 "ssi", "systemd-journald.service", "main", sig
);
2018 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
2023 /* Let's install the inotify watch, if we didn't do that yet. */
2026 mkdir_p("/run/systemd/journal", 0755);
2028 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
2030 return log_error_errno(errno
, "Failed to create inotify watch: %m");
2032 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_MOVED_TO
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
2034 return log_error_errno(errno
, "Failed to watch journal directory: %m");
2036 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
2040 /* OK, all preparatory steps done, let's wait until
2041 * inotify reports an event. */
2043 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
2045 return log_error_errno(r
, "Failed to wait for event: %m");
2047 r
= flush_fd(watch_fd
);
2049 return log_error_errno(r
, "Failed to flush inotify events: %m");
2055 static int rotate(void) {
2056 return send_signal_and_wait(SIGUSR2
, "/run/systemd/journal/rotated");
2059 static int sync_journal(void) {
2060 return send_signal_and_wait(SIGRTMIN
+1, "/run/systemd/journal/synced");
2063 int main(int argc
, char *argv
[]) {
2065 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2066 bool need_seek
= false;
2067 sd_id128_t previous_boot_id
;
2068 bool previous_boot_id_valid
= false, first_line
= true;
2070 bool ellipsized
= false;
2072 setlocale(LC_ALL
, "");
2073 log_parse_environment();
2076 r
= parse_argv(argc
, argv
);
2080 signal(SIGWINCH
, columns_lines_cache_reset
);
2083 /* Increase max number of open files to 16K if we can, we
2084 * might needs this when browsing journal files, which might
2085 * be split up into many files. */
2086 setrlimit_closest(RLIMIT_NOFILE
, &RLIMIT_MAKE_CONST(16384));
2088 switch (arg_action
) {
2090 case ACTION_NEW_ID128
:
2091 r
= generate_new_id128();
2094 case ACTION_SETUP_KEYS
:
2098 case ACTION_LIST_CATALOG
:
2099 case ACTION_DUMP_CATALOG
:
2100 case ACTION_UPDATE_CATALOG
: {
2101 _cleanup_free_
char *database
;
2103 database
= path_join(arg_root
, CATALOG_DATABASE
, NULL
);
2109 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2110 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2112 log_error_errno(r
, "Failed to list catalog: %m");
2114 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2116 (void) pager_open(arg_no_pager
, arg_pager_end
);
2119 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2121 r
= catalog_list(stdout
, database
, oneline
);
2123 log_error_errno(r
, "Failed to list catalog: %m");
2142 case ACTION_PRINT_HEADER
:
2144 case ACTION_DISK_USAGE
:
2145 case ACTION_LIST_BOOTS
:
2147 case ACTION_LIST_FIELDS
:
2148 case ACTION_LIST_FIELD_NAMES
:
2149 /* These ones require access to the journal files, continue below. */
2153 assert_not_reached("Unknown action");
2157 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2159 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2160 else if (arg_file_stdin
) {
2161 int ifd
= STDIN_FILENO
;
2162 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2163 } else if (arg_file
)
2164 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2165 else if (arg_machine
) {
2166 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2167 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2168 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2171 if (geteuid() != 0) {
2172 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2173 * the container, thus we need root privileges to override them. */
2174 log_error("Using the --machine= switch requires root privileges.");
2179 r
= sd_bus_open_system(&bus
);
2181 log_error_errno(r
, "Failed to open system bus: %m");
2185 r
= sd_bus_call_method(
2187 "org.freedesktop.machine1",
2188 "/org/freedesktop/machine1",
2189 "org.freedesktop.machine1.Manager",
2190 "OpenMachineRootDirectory",
2195 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2199 r
= sd_bus_message_read(reply
, "h", &fd
);
2201 bus_log_parse_error(r
);
2205 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2207 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2211 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2215 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2217 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2221 r
= journal_access_check_and_warn(j
, arg_quiet
,
2222 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2226 switch (arg_action
) {
2228 case ACTION_NEW_ID128
:
2229 case ACTION_SETUP_KEYS
:
2230 case ACTION_LIST_CATALOG
:
2231 case ACTION_DUMP_CATALOG
:
2232 case ACTION_UPDATE_CATALOG
:
2236 assert_not_reached("Unexpected action.");
2238 case ACTION_PRINT_HEADER
:
2239 journal_print_header(j
);
2247 case ACTION_DISK_USAGE
: {
2249 char sbytes
[FORMAT_BYTES_MAX
];
2251 r
= sd_journal_get_usage(j
, &bytes
);
2255 printf("Archived and active journals take up %s in the file system.\n",
2256 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2260 case ACTION_LIST_BOOTS
:
2264 case ACTION_VACUUM
: {
2268 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2274 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2276 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2284 case ACTION_LIST_FIELD_NAMES
: {
2287 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2288 printf("%s\n", field
);
2297 case ACTION_LIST_FIELDS
:
2301 assert_not_reached("Unknown action");
2304 if (arg_boot_offset
!= 0 &&
2305 sd_journal_has_runtime_files(j
) > 0 &&
2306 sd_journal_has_persistent_files(j
) == 0) {
2307 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2311 /* add_boot() must be called first!
2312 * It may need to seek the journal to find parent boot IDs. */
2323 log_error_errno(r
, "Failed to add filter for units: %m");
2327 r
= add_syslog_identifier(j
);
2329 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2333 r
= add_priorities(j
);
2337 r
= add_matches(j
, argv
+ optind
);
2341 if (DEBUG_LOGGING
) {
2342 _cleanup_free_
char *filter
;
2344 filter
= journal_make_match_string(j
);
2348 log_debug("Journal filter: %s", filter
);
2351 if (arg_action
== ACTION_LIST_FIELDS
) {
2357 r
= sd_journal_set_data_threshold(j
, 0);
2359 log_error_errno(r
, "Failed to unset data size threshold: %m");
2363 r
= sd_journal_query_unique(j
, arg_field
);
2365 log_error_errno(r
, "Failed to query unique data objects: %m");
2369 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2372 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2375 eq
= memchr(data
, '=', size
);
2377 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2379 printf("%.*s\n", (int) size
, (const char*) data
);
2388 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2390 r
= sd_journal_get_fd(j
);
2392 log_warning("Insufficent watch descriptors available. Reverting to -n.");
2394 } else if (r
== -EMEDIUMTYPE
) {
2395 log_error_errno(r
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2398 log_error_errno(r
, "Failed to get journal fd: %m");
2403 if (arg_cursor
|| arg_after_cursor
) {
2404 r
= sd_journal_seek_cursor(j
, arg_cursor
?: arg_after_cursor
);
2406 log_error_errno(r
, "Failed to seek to cursor: %m");
2411 r
= sd_journal_next_skip(j
, 1 + !!arg_after_cursor
);
2413 r
= sd_journal_previous_skip(j
, 1 + !!arg_after_cursor
);
2415 if (arg_after_cursor
&& r
< 2) {
2416 /* We couldn't find the next entry after the cursor. */
2423 } else if (arg_since_set
&& !arg_reverse
) {
2424 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2426 log_error_errno(r
, "Failed to seek to date: %m");
2429 r
= sd_journal_next(j
);
2431 } else if (arg_until_set
&& arg_reverse
) {
2432 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2434 log_error_errno(r
, "Failed to seek to date: %m");
2437 r
= sd_journal_previous(j
);
2439 } else if (arg_lines
>= 0) {
2440 r
= sd_journal_seek_tail(j
);
2442 log_error_errno(r
, "Failed to seek to tail: %m");
2446 r
= sd_journal_previous_skip(j
, arg_lines
);
2448 } else if (arg_reverse
) {
2449 r
= sd_journal_seek_tail(j
);
2451 log_error_errno(r
, "Failed to seek to tail: %m");
2455 r
= sd_journal_previous(j
);
2458 r
= sd_journal_seek_head(j
);
2460 log_error_errno(r
, "Failed to seek to head: %m");
2464 r
= sd_journal_next(j
);
2468 log_error_errno(r
, "Failed to iterate through journal: %m");
2475 (void) pager_open(arg_no_pager
, arg_pager_end
);
2477 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2479 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2481 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2483 log_error_errno(r
, "Failed to get cutoff: %m");
2489 printf("-- Logs begin at %s. --\n",
2490 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2492 printf("-- Logs begin at %s, end at %s. --\n",
2493 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2494 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2499 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2501 size_t highlight
[2] = {};
2505 r
= sd_journal_next(j
);
2507 r
= sd_journal_previous(j
);
2509 log_error_errno(r
, "Failed to iterate through journal: %m");
2516 if (arg_until_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_until
)
2528 if (arg_since_set
&& arg_reverse
) {
2531 r
= sd_journal_get_realtime_usec(j
, &usec
);
2533 log_error_errno(r
, "Failed to determine timestamp: %m");
2536 if (usec
< arg_since
)
2540 if (!arg_merge
&& !arg_quiet
) {
2543 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2545 if (previous_boot_id_valid
&&
2546 !sd_id128_equal(boot_id
, previous_boot_id
))
2547 printf("%s-- Reboot --%s\n",
2548 ansi_highlight(), ansi_normal());
2550 previous_boot_id
= boot_id
;
2551 previous_boot_id_valid
= true;
2556 if (arg_compiled_pattern
) {
2557 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2558 const void *message
;
2562 md
= pcre2_match_data_create(1, NULL
);
2566 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2573 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2577 assert_se(message
= startswith(message
, "MESSAGE="));
2579 r
= pcre2_match(arg_compiled_pattern
,
2581 len
- strlen("MESSAGE="),
2582 0, /* start at offset 0 in the subject */
2583 0, /* default options */
2586 if (r
== PCRE2_ERROR_NOMATCH
) {
2591 unsigned char buf
[LINE_MAX
];
2594 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2595 log_error("Pattern matching failed: %s",
2596 r2
< 0 ? "unknown error" : (char*) buf
);
2601 ovec
= pcre2_get_ovector_pointer(md
);
2602 highlight
[0] = ovec
[0];
2603 highlight
[1] = ovec
[1];
2608 arg_all
* OUTPUT_SHOW_ALL
|
2609 arg_full
* OUTPUT_FULL_WIDTH
|
2610 colors_enabled() * OUTPUT_COLOR
|
2611 arg_catalog
* OUTPUT_CATALOG
|
2612 arg_utc
* OUTPUT_UTC
|
2613 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2615 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2616 arg_output_fields
, highlight
, &ellipsized
);
2618 if (r
== -EADDRNOTAVAIL
)
2620 else if (r
< 0 || ferror(stdout
))
2625 /* If journalctl take a long time to process messages, and during that time journal file
2626 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2627 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2628 * in the "following" case. By periodically calling sd_journal_process() during the processing
2629 * loop we shrink the window of time a client instance has open file descriptors for rotated
2630 * (deleted) journal files. */
2631 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2632 r
= sd_journal_process(j
);
2634 log_error_errno(r
, "Failed to process inotify events: %m");
2641 if (n_shown
== 0 && !arg_quiet
)
2642 printf("-- No entries --\n");
2644 if (arg_show_cursor
) {
2645 _cleanup_free_
char *cursor
= NULL
;
2647 r
= sd_journal_get_cursor(j
, &cursor
);
2648 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2649 log_error_errno(r
, "Failed to get cursor: %m");
2651 printf("-- cursor: %s\n", cursor
);
2658 r
= sd_journal_wait(j
, (uint64_t) -1);
2660 log_error_errno(r
, "Couldn't wait for journal event: %m");
2671 strv_free(arg_file
);
2673 strv_free(arg_syslog_identifier
);
2674 strv_free(arg_system_units
);
2675 strv_free(arg_user_units
);
2676 strv_free(arg_output_fields
);
2679 free(arg_verify_key
);
2682 if (arg_compiled_pattern
)
2683 pcre2_code_free(arg_compiled_pattern
);
2686 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;