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"
346 " --interval=TIME Time interval for changing the FSS sealing key\n"
347 " --verify-key=KEY Specify FSS verification key\n"
348 " --force Override of the FSS key pair with --setup-keys\n"
351 " -h --help Show this help text\n"
352 " --version Show package version\n"
353 " -N --fields List all field names currently used\n"
354 " -F --field=FIELD List all values that a specified field takes\n"
355 " --disk-usage Show total disk usage of all journal files\n"
356 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
357 " --vacuum-files=INT Leave only the specified number of journal files\n"
358 " --vacuum-time=TIME Remove journal files older than specified time\n"
359 " --verify Verify journal file consistency\n"
360 " --sync Synchronize unwritten journal messages to disk\n"
361 " --flush Flush all journal data from /run into /var\n"
362 " --rotate Request immediate rotation of the journal files\n"
363 " --header Show journal header information\n"
364 " --list-catalog Show all message IDs in the catalog\n"
365 " --dump-catalog Show entries in the message catalog\n"
366 " --update-catalog Update the message catalog database\n"
367 " --new-id128 Generate a new 128-bit ID\n"
369 " --setup-keys Generate a new FSS key pair\n"
371 , program_invocation_short_name
);
374 static int parse_argv(int argc
, char *argv
[]) {
413 static const struct option options
[] = {
414 { "help", no_argument
, NULL
, 'h' },
415 { "version" , no_argument
, NULL
, ARG_VERSION
},
416 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
417 { "pager-end", no_argument
, NULL
, 'e' },
418 { "follow", no_argument
, NULL
, 'f' },
419 { "force", no_argument
, NULL
, ARG_FORCE
},
420 { "output", required_argument
, NULL
, 'o' },
421 { "all", no_argument
, NULL
, 'a' },
422 { "full", no_argument
, NULL
, 'l' },
423 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
424 { "lines", optional_argument
, NULL
, 'n' },
425 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
426 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
427 { "quiet", no_argument
, NULL
, 'q' },
428 { "merge", no_argument
, NULL
, 'm' },
429 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
430 { "boot", optional_argument
, NULL
, 'b' },
431 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
432 { "dmesg", no_argument
, NULL
, 'k' },
433 { "system", no_argument
, NULL
, ARG_SYSTEM
},
434 { "user", no_argument
, NULL
, ARG_USER
},
435 { "directory", required_argument
, NULL
, 'D' },
436 { "file", required_argument
, NULL
, ARG_FILE
},
437 { "root", required_argument
, NULL
, ARG_ROOT
},
438 { "header", no_argument
, NULL
, ARG_HEADER
},
439 { "identifier", required_argument
, NULL
, 't' },
440 { "priority", required_argument
, NULL
, 'p' },
441 { "grep", required_argument
, NULL
, 'g' },
442 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
443 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
444 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
445 { "verify", no_argument
, NULL
, ARG_VERIFY
},
446 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
447 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
448 { "cursor", required_argument
, NULL
, 'c' },
449 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
450 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
451 { "since", required_argument
, NULL
, 'S' },
452 { "until", required_argument
, NULL
, 'U' },
453 { "unit", required_argument
, NULL
, 'u' },
454 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
455 { "field", required_argument
, NULL
, 'F' },
456 { "fields", no_argument
, NULL
, 'N' },
457 { "catalog", no_argument
, NULL
, 'x' },
458 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
459 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
460 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
461 { "reverse", no_argument
, NULL
, 'r' },
462 { "machine", required_argument
, NULL
, 'M' },
463 { "utc", no_argument
, NULL
, ARG_UTC
},
464 { "flush", no_argument
, NULL
, ARG_FLUSH
},
465 { "sync", no_argument
, NULL
, ARG_SYNC
},
466 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
467 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
468 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
469 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
470 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
471 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
480 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
496 arg_pager_end
= true;
498 if (arg_lines
== ARG_LINES_DEFAULT
)
508 if (streq(optarg
, "help")) {
509 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
513 arg_output
= output_mode_from_string(optarg
);
514 if (arg_output
< 0) {
515 log_error("Unknown output format '%s'.", optarg
);
519 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_CAT
))
538 if (streq(optarg
, "all"))
539 arg_lines
= ARG_LINES_ALL
;
541 r
= safe_atoi(optarg
, &arg_lines
);
542 if (r
< 0 || arg_lines
< 0) {
543 log_error("Failed to parse lines '%s'", optarg
);
550 /* Hmm, no argument? Maybe the next
551 * word on the command line is
552 * supposed to be the argument? Let's
553 * see if there is one, and is
557 if (streq(argv
[optind
], "all")) {
558 arg_lines
= ARG_LINES_ALL
;
560 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
574 arg_action
= ACTION_NEW_ID128
;
593 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
595 log_error("Failed to parse boot descriptor '%s'", optarg
);
600 /* Hmm, no argument? Maybe the next
601 * word on the command line is
602 * supposed to be the argument? Let's
603 * see if there is one and is parsable
604 * as a boot descriptor... */
607 parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
) >= 0)
614 arg_action
= ACTION_LIST_BOOTS
;
618 arg_boot
= arg_dmesg
= true;
622 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
626 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
630 arg_machine
= optarg
;
634 arg_directory
= optarg
;
638 if (streq(optarg
, "-"))
639 /* An undocumented feature: we can read journal files from STDIN. We don't document
640 * this though, since after all we only support this for mmap-able, seekable files, and
641 * not for example pipes which are probably the primary usecase for reading things from
642 * STDIN. To avoid confusion we hence don't document this feature. */
643 arg_file_stdin
= true;
645 r
= glob_extend(&arg_file
, optarg
);
647 return log_error_errno(r
, "Failed to add paths: %m");
652 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
661 case ARG_AFTER_CURSOR
:
662 arg_after_cursor
= optarg
;
665 case ARG_SHOW_CURSOR
:
666 arg_show_cursor
= true;
670 arg_action
= ACTION_PRINT_HEADER
;
674 arg_action
= ACTION_VERIFY
;
678 arg_action
= ACTION_DISK_USAGE
;
681 case ARG_VACUUM_SIZE
:
682 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
684 log_error("Failed to parse vacuum size: %s", optarg
);
688 arg_action
= ACTION_VACUUM
;
691 case ARG_VACUUM_FILES
:
692 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
694 log_error("Failed to parse vacuum files: %s", optarg
);
698 arg_action
= ACTION_VACUUM
;
701 case ARG_VACUUM_TIME
:
702 r
= parse_sec(optarg
, &arg_vacuum_time
);
704 log_error("Failed to parse vacuum time: %s", optarg
);
708 arg_action
= ACTION_VACUUM
;
717 arg_action
= ACTION_SETUP_KEYS
;
721 arg_action
= ACTION_VERIFY
;
722 r
= free_and_strdup(&arg_verify_key
, optarg
);
725 /* Use memset not string_erase so this doesn't look confusing
726 * in ps or htop output. */
727 memset(optarg
, 'x', strlen(optarg
));
733 r
= parse_sec(optarg
, &arg_interval
);
734 if (r
< 0 || arg_interval
<= 0) {
735 log_error("Failed to parse sealing key change interval: %s", optarg
);
744 log_error("Forward-secure sealing not available.");
751 dots
= strstr(optarg
, "..");
757 a
= strndup(optarg
, dots
- optarg
);
761 from
= log_level_from_string(a
);
762 to
= log_level_from_string(dots
+ 2);
765 if (from
< 0 || to
< 0) {
766 log_error("Failed to parse log level range %s", optarg
);
773 for (i
= from
; i
<= to
; i
++)
774 arg_priorities
|= 1 << i
;
776 for (i
= to
; i
<= from
; i
++)
777 arg_priorities
|= 1 << i
;
783 p
= log_level_from_string(optarg
);
785 log_error("Unknown log level %s", optarg
);
791 for (i
= 0; i
<= p
; i
++)
792 arg_priorities
|= 1 << i
;
800 arg_pattern
= optarg
;
803 case ARG_CASE_SENSITIVE
:
805 r
= parse_boolean(optarg
);
807 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
808 arg_case_sensitive
= r
;
810 arg_case_sensitive
= true;
815 case ARG_CASE_SENSITIVE
:
816 return log_error("Compiled without pattern matching support");
820 r
= parse_timestamp(optarg
, &arg_since
);
822 log_error("Failed to parse timestamp: %s", optarg
);
825 arg_since_set
= true;
829 r
= parse_timestamp(optarg
, &arg_until
);
831 log_error("Failed to parse timestamp: %s", optarg
);
834 arg_until_set
= true;
838 r
= strv_extend(&arg_syslog_identifier
, optarg
);
844 r
= strv_extend(&arg_system_units
, optarg
);
850 r
= strv_extend(&arg_user_units
, optarg
);
856 arg_action
= ACTION_LIST_FIELDS
;
861 arg_action
= ACTION_LIST_FIELD_NAMES
;
864 case ARG_NO_HOSTNAME
:
865 arg_no_hostname
= true;
872 case ARG_LIST_CATALOG
:
873 arg_action
= ACTION_LIST_CATALOG
;
876 case ARG_DUMP_CATALOG
:
877 arg_action
= ACTION_DUMP_CATALOG
;
880 case ARG_UPDATE_CATALOG
:
881 arg_action
= ACTION_UPDATE_CATALOG
;
893 arg_action
= ACTION_FLUSH
;
897 arg_action
= ACTION_ROTATE
;
901 arg_action
= ACTION_SYNC
;
904 case ARG_OUTPUT_FIELDS
: {
905 _cleanup_strv_free_
char **v
= NULL
;
907 v
= strv_split(optarg
, ",");
911 if (!arg_output_fields
)
912 arg_output_fields
= TAKE_PTR(v
);
914 r
= strv_extend_strv(&arg_output_fields
, v
, true);
925 assert_not_reached("Unhandled option");
928 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
931 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
> 1) {
932 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
936 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
937 log_error("--since= must be before --until=.");
941 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
942 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
946 if (arg_follow
&& arg_reverse
) {
947 log_error("Please specify either --reverse= or --follow=, not both.");
951 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
952 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
956 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
957 log_error("Using --boot or --list-boots with --merge is not supported.");
961 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
962 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
963 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
964 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
965 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
969 arg_system_units
= strv_free(arg_system_units
);
976 if (arg_case_sensitive
>= 0)
977 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
979 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
981 _cleanup_(pcre2_code_freep
) pcre2_code
*cs
= NULL
;
983 md
= pcre2_match_data_create(1, NULL
);
987 r
= pattern_compile("[[:upper:]]", 0, &cs
);
991 r
= pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
994 flags
= !has_case
* PCRE2_CASELESS
;
997 log_debug("Doing case %s matching based on %s",
998 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
999 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
1001 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1010 static int generate_new_id128(void) {
1015 r
= sd_id128_randomize(&id
);
1017 return log_error_errno(r
, "Failed to generate ID: %m");
1019 printf("As string:\n"
1020 SD_ID128_FORMAT_STR
"\n\n"
1022 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
1023 "As man:sd-id128(3) macro:\n"
1024 "#define MESSAGE_XYZ SD_ID128_MAKE(",
1025 SD_ID128_FORMAT_VAL(id
),
1026 SD_ID128_FORMAT_VAL(id
));
1027 for (i
= 0; i
< 16; i
++)
1028 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
1029 fputs(")\n\n", stdout
);
1031 printf("As Python constant:\n"
1033 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
1034 SD_ID128_FORMAT_VAL(id
));
1039 static int add_matches(sd_journal
*j
, char **args
) {
1041 bool have_term
= false;
1045 STRV_FOREACH(i
, args
) {
1048 if (streq(*i
, "+")) {
1051 r
= sd_journal_add_disjunction(j
);
1054 } else if (path_is_absolute(*i
)) {
1055 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1058 r
= chase_symlinks(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
);
1060 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1062 if (lstat(p
, &st
) < 0)
1063 return log_error_errno(errno
, "Couldn't stat file: %m");
1065 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1066 if (executable_is_script(p
, &interpreter
) > 0) {
1067 _cleanup_free_
char *comm
;
1069 comm
= strndup(basename(p
), 15);
1073 t
= strappend("_COMM=", comm
);
1077 /* Append _EXE only if the interpreter is not a link.
1078 Otherwise, it might be outdated often. */
1079 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1080 t2
= strappend("_EXE=", interpreter
);
1085 t
= strappend("_EXE=", p
);
1090 r
= sd_journal_add_match(j
, t
, 0);
1093 r
= sd_journal_add_match(j
, t2
, 0);
1095 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1096 r
= add_matches_for_device(j
, p
);
1100 log_error("File is neither a device node, nor regular file, nor executable: %s", *i
);
1106 r
= sd_journal_add_match(j
, *i
, 0);
1111 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1114 if (!strv_isempty(args
) && !have_term
) {
1115 log_error("\"+\" can only be used between terms");
1122 static void boot_id_free_all(BootId
*l
) {
1126 LIST_REMOVE(boot_list
, l
, i
);
1131 static int discover_next_boot(sd_journal
*j
,
1132 sd_id128_t previous_boot_id
,
1136 _cleanup_free_ BootId
*next_boot
= NULL
;
1137 char match
[9+32+1] = "_BOOT_ID=";
1144 /* We expect the journal to be on the last position of a boot
1145 * (in relation to the direction we are going), so that the next
1146 * invocation of sd_journal_next/previous will be from a different
1147 * boot. We then collect any information we desire and then jump
1148 * to the last location of the new boot by using a _BOOT_ID match
1149 * coming from the other journal direction. */
1151 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1152 * we can actually advance to a *different* boot. */
1153 sd_journal_flush_matches(j
);
1157 r
= sd_journal_previous(j
);
1159 r
= sd_journal_next(j
);
1163 return 0; /* End of journal, yay. */
1165 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1169 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1170 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1171 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1172 * complete than the main entry array, and hence might reference an entry that's not actually the last
1173 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1174 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1177 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1179 next_boot
= new0(BootId
, 1);
1183 next_boot
->id
= boot_id
;
1185 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1189 /* Now seek to the last occurrence of this boot ID. */
1190 sd_id128_to_string(next_boot
->id
, match
+ 9);
1191 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1196 r
= sd_journal_seek_head(j
);
1198 r
= sd_journal_seek_tail(j
);
1203 r
= sd_journal_next(j
);
1205 r
= sd_journal_previous(j
);
1209 log_debug("Whoopsie! We found a boot ID but can't read its last entry.");
1210 return -ENODATA
; /* This shouldn't happen. We just came from this very boot ID. */
1213 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1217 *ret
= TAKE_PTR(next_boot
);
1222 static int get_boots(
1225 sd_id128_t
*boot_id
,
1230 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1231 const bool advance_older
= boot_id
&& offset
<= 0;
1232 sd_id128_t previous_boot_id
;
1236 /* Adjust for the asymmetry that offset 0 is
1237 * the last (and current) boot, while 1 is considered the
1238 * (chronological) first boot in the journal. */
1239 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1241 /* Advance to the earliest/latest occurrence of our reference
1242 * boot ID (taking our lookup direction into account), so that
1243 * discover_next_boot() can do its job.
1244 * If no reference is given, the journal head/tail will do,
1245 * they're "virtual" boots after all. */
1246 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1247 char match
[9+32+1] = "_BOOT_ID=";
1249 sd_journal_flush_matches(j
);
1251 sd_id128_to_string(*boot_id
, match
+ 9);
1252 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1257 r
= sd_journal_seek_head(j
); /* seek to oldest */
1259 r
= sd_journal_seek_tail(j
); /* seek to newest */
1264 r
= sd_journal_next(j
); /* read the oldest entry */
1266 r
= sd_journal_previous(j
); /* read the most recently added entry */
1271 else if (offset
== 0) {
1276 /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
1277 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1278 * the following entry, which must then have an older/newer boot ID */
1282 r
= sd_journal_seek_tail(j
); /* seek to newest */
1284 r
= sd_journal_seek_head(j
); /* seek to oldest */
1288 /* No sd_journal_next()/_previous() here.
1290 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1291 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1295 previous_boot_id
= SD_ID128_NULL
;
1297 _cleanup_free_ BootId
*current
= NULL
;
1299 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1301 boot_id_free_all(head
);
1308 previous_boot_id
= current
->id
;
1312 offset
+= advance_older
? 1 : -1;
1317 *boot_id
= current
->id
;
1321 LIST_FOREACH(boot_list
, id
, head
) {
1322 if (sd_id128_equal(id
->id
, current
->id
)) {
1323 /* boot id already stored, something wrong with the journal files */
1324 /* exiting as otherwise this problem would cause forever loop */
1328 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1329 tail
= TAKE_PTR(current
);
1338 sd_journal_flush_matches(j
);
1343 static int list_boots(sd_journal
*j
) {
1345 BootId
*id
, *all_ids
;
1349 count
= get_boots(j
, &all_ids
, NULL
, 0);
1351 return log_error_errno(count
, "Failed to determine boots: %m");
1355 (void) pager_open(arg_no_pager
, arg_pager_end
);
1357 /* numbers are one less, but we need an extra char for the sign */
1358 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1361 LIST_FOREACH(boot_list
, id
, all_ids
) {
1362 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1364 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1366 SD_ID128_FORMAT_VAL(id
->id
),
1367 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1368 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1372 boot_id_free_all(all_ids
);
1377 static int add_boot(sd_journal
*j
) {
1378 char match
[9+32+1] = "_BOOT_ID=";
1387 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1388 * We can do this only when we logs are coming from the current machine,
1389 * so take the slow path if log location is specified. */
1390 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1391 !arg_directory
&& !arg_file
&& !arg_root
)
1393 return add_match_this_boot(j
, arg_machine
);
1395 boot_id
= arg_boot_id
;
1396 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1399 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror(-r
);
1401 if (sd_id128_is_null(arg_boot_id
))
1402 log_error("Data from the specified boot (%+i) is not available: %s",
1403 arg_boot_offset
, reason
);
1405 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1406 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1408 return r
== 0 ? -ENODATA
: r
;
1411 sd_id128_to_string(boot_id
, match
+ 9);
1413 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1415 return log_error_errno(r
, "Failed to add match: %m");
1417 r
= sd_journal_add_conjunction(j
);
1419 return log_error_errno(r
, "Failed to add conjunction: %m");
1424 static int add_dmesg(sd_journal
*j
) {
1431 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1432 STRLEN("_TRANSPORT=kernel"));
1434 return log_error_errno(r
, "Failed to add match: %m");
1436 r
= sd_journal_add_conjunction(j
);
1438 return log_error_errno(r
, "Failed to add conjunction: %m");
1443 static int get_possible_units(
1449 _cleanup_set_free_free_ Set
*found
;
1453 found
= set_new(&string_hash_ops
);
1457 NULSTR_FOREACH(field
, fields
) {
1461 r
= sd_journal_query_unique(j
, field
);
1465 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1466 char **pattern
, *eq
;
1468 _cleanup_free_
char *u
= NULL
;
1470 eq
= memchr(data
, '=', size
);
1472 prefix
= eq
- (char*) data
+ 1;
1476 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1480 STRV_FOREACH(pattern
, patterns
)
1481 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1482 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1484 r
= set_consume(found
, u
);
1486 if (r
< 0 && r
!= -EEXIST
)
1494 *units
= TAKE_PTR(found
);
1499 /* This list is supposed to return the superset of unit names
1500 * possibly matched by rules added with add_matches_for_unit... */
1501 #define SYSTEM_UNITS \
1505 "OBJECT_SYSTEMD_UNIT\0" \
1508 /* ... and add_matches_for_user_unit */
1509 #define USER_UNITS \
1510 "_SYSTEMD_USER_UNIT\0" \
1512 "COREDUMP_USER_UNIT\0" \
1513 "OBJECT_SYSTEMD_USER_UNIT\0"
1515 static int add_units(sd_journal
*j
) {
1516 _cleanup_strv_free_
char **patterns
= NULL
;
1522 STRV_FOREACH(i
, arg_system_units
) {
1523 _cleanup_free_
char *u
= NULL
;
1525 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1529 if (string_is_glob(u
)) {
1530 r
= strv_push(&patterns
, u
);
1535 r
= add_matches_for_unit(j
, u
);
1538 r
= sd_journal_add_disjunction(j
);
1545 if (!strv_isempty(patterns
)) {
1546 _cleanup_set_free_free_ Set
*units
= NULL
;
1550 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1554 SET_FOREACH(u
, units
, it
) {
1555 r
= add_matches_for_unit(j
, u
);
1558 r
= sd_journal_add_disjunction(j
);
1565 patterns
= strv_free(patterns
);
1567 STRV_FOREACH(i
, arg_user_units
) {
1568 _cleanup_free_
char *u
= NULL
;
1570 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1574 if (string_is_glob(u
)) {
1575 r
= strv_push(&patterns
, u
);
1580 r
= add_matches_for_user_unit(j
, u
, getuid());
1583 r
= sd_journal_add_disjunction(j
);
1590 if (!strv_isempty(patterns
)) {
1591 _cleanup_set_free_free_ Set
*units
= NULL
;
1595 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1599 SET_FOREACH(u
, units
, it
) {
1600 r
= add_matches_for_user_unit(j
, u
, getuid());
1603 r
= sd_journal_add_disjunction(j
);
1610 /* Complain if the user request matches but nothing whatsoever was
1611 * found, since otherwise everything would be matched. */
1612 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1615 r
= sd_journal_add_conjunction(j
);
1622 static int add_priorities(sd_journal
*j
) {
1623 char match
[] = "PRIORITY=0";
1627 if (arg_priorities
== 0xFF)
1630 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1631 if (arg_priorities
& (1 << i
)) {
1632 match
[sizeof(match
)-2] = '0' + i
;
1634 r
= sd_journal_add_match(j
, match
, strlen(match
));
1636 return log_error_errno(r
, "Failed to add match: %m");
1639 r
= sd_journal_add_conjunction(j
);
1641 return log_error_errno(r
, "Failed to add conjunction: %m");
1646 static int add_syslog_identifier(sd_journal
*j
) {
1652 STRV_FOREACH(i
, arg_syslog_identifier
) {
1655 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1656 r
= sd_journal_add_match(j
, u
, 0);
1659 r
= sd_journal_add_disjunction(j
);
1664 r
= sd_journal_add_conjunction(j
);
1671 static int setup_keys(void) {
1673 size_t mpk_size
, seed_size
, state_size
, i
;
1674 uint8_t *mpk
, *seed
, *state
;
1676 sd_id128_t machine
, boot
;
1677 char *p
= NULL
, *k
= NULL
;
1682 r
= stat("/var/log/journal", &st
);
1683 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1684 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1686 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1687 log_error("%s is not a directory, must be using persistent logging for FSS.",
1688 "/var/log/journal");
1689 return r
< 0 ? -errno
: -ENOTDIR
;
1692 r
= sd_id128_get_machine(&machine
);
1694 return log_error_errno(r
, "Failed to get machine ID: %m");
1696 r
= sd_id128_get_boot(&boot
);
1698 return log_error_errno(r
, "Failed to get boot ID: %m");
1700 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1701 SD_ID128_FORMAT_VAL(machine
)) < 0)
1706 if (r
< 0 && errno
!= ENOENT
) {
1707 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1710 } else if (access(p
, F_OK
) >= 0) {
1711 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1716 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1717 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1722 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1723 mpk
= alloca(mpk_size
);
1725 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1726 seed
= alloca(seed_size
);
1728 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1729 state
= alloca(state_size
);
1731 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1733 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1737 log_info("Generating seed...");
1738 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1740 log_error_errno(r
, "Failed to read random seed: %m");
1744 log_info("Generating key pair...");
1745 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1747 log_info("Generating sealing key...");
1748 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1750 assert(arg_interval
> 0);
1752 n
= now(CLOCK_REALTIME
);
1756 fd
= mkostemp_safe(k
);
1758 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1762 /* Enable secure remove, exclusion from dump, synchronous
1763 * writing and in-place updating */
1764 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
);
1766 log_warning_errno(r
, "Failed to set file attributes: %m");
1769 memcpy(h
.signature
, "KSHHRHLP", 8);
1770 h
.machine_id
= machine
;
1772 h
.header_size
= htole64(sizeof(h
));
1773 h
.start_usec
= htole64(n
* arg_interval
);
1774 h
.interval_usec
= htole64(arg_interval
);
1775 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1776 h
.fsprg_state_size
= htole64(state_size
);
1778 r
= loop_write(fd
, &h
, sizeof(h
), false);
1780 log_error_errno(r
, "Failed to write header: %m");
1784 r
= loop_write(fd
, state
, state_size
, false);
1786 log_error_errno(r
, "Failed to write state: %m");
1790 if (link(k
, p
) < 0) {
1791 r
= log_error_errno(errno
, "Failed to link file: %m");
1798 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1799 "the following local file. This key file is automatically updated when the\n"
1800 "sealing key is advanced. It should not be used on multiple hosts.\n"
1804 "Please write down the following %ssecret verification key%s. It should be stored\n"
1805 "at a safe location and should not be saved locally on disk.\n"
1807 ansi_highlight(), ansi_normal(),
1809 ansi_highlight(), ansi_normal(),
1810 ansi_highlight_red());
1813 for (i
= 0; i
< seed_size
; i
++) {
1814 if (i
> 0 && i
% 3 == 0)
1816 printf("%02x", ((uint8_t*) seed
)[i
]);
1819 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1822 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1826 "The sealing key is automatically changed every %s.\n",
1828 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1830 hn
= gethostname_malloc();
1833 hostname_cleanup(hn
);
1834 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1836 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1839 /* If this is not an UTF-8 system don't print any QR codes */
1840 if (is_locale_utf8()) {
1841 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1842 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1862 log_error("Forward-secure sealing not available.");
1867 static int verify(sd_journal
*j
) {
1874 log_show_color(true);
1876 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1878 usec_t first
= 0, validated
= 0, last
= 0;
1881 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1882 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1885 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1887 /* If the key was invalid give up right-away. */
1890 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1893 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1894 log_info("PASS: %s", f
->path
);
1896 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1897 if (validated
> 0) {
1898 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1899 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1900 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1901 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1902 } else if (last
> 0)
1903 log_info("=> No sealing yet, %s of entries not sealed.",
1904 format_timespan(c
, sizeof(c
), last
- first
, 0));
1906 log_info("=> No sealing yet, no entries in file.");
1914 static int flush_to_var(void) {
1915 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1916 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1917 _cleanup_close_
int watch_fd
= -1;
1921 log_error("--flush is not supported in conjunction with --machine=.");
1926 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1929 /* OK, let's actually do the full logic, send SIGUSR1 to the
1930 * daemon and set up inotify to wait for the flushed file to appear */
1931 r
= bus_connect_system_systemd(&bus
);
1933 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1935 r
= sd_bus_call_method(
1937 "org.freedesktop.systemd1",
1938 "/org/freedesktop/systemd1",
1939 "org.freedesktop.systemd1.Manager",
1943 "ssi", "systemd-journald.service", "main", SIGUSR1
);
1945 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
1947 mkdir_p("/run/systemd/journal", 0755);
1949 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1951 return log_error_errno(errno
, "Failed to create inotify watch: %m");
1953 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_CREATE
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
1955 return log_error_errno(errno
, "Failed to watch journal directory: %m");
1958 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1961 if (errno
!= ENOENT
)
1962 return log_error_errno(errno
, "Failed to check for existence of /run/systemd/journal/flushed: %m");
1964 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
1966 return log_error_errno(r
, "Failed to wait for event: %m");
1968 r
= flush_fd(watch_fd
);
1970 return log_error_errno(r
, "Failed to flush inotify events: %m");
1976 static int send_signal_and_wait(int sig
, const char *watch_path
) {
1977 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1978 _cleanup_close_
int watch_fd
= -1;
1983 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
1987 start
= now(CLOCK_MONOTONIC
);
1989 /* This call sends the specified signal to journald, and waits
1990 * for acknowledgment by watching the mtime of the specified
1991 * flag file. This is used to trigger syncing or rotation and
1992 * then wait for the operation to complete. */
1997 /* See if a sync happened by now. */
1998 r
= read_timestamp_file(watch_path
, &tstamp
);
1999 if (r
< 0 && r
!= -ENOENT
)
2000 return log_error_errno(errno
, "Failed to read %s: %m", watch_path
);
2001 if (r
>= 0 && tstamp
>= start
)
2004 /* Let's ask for a sync, but only once. */
2006 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2008 r
= bus_connect_system_systemd(&bus
);
2010 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
2012 r
= sd_bus_call_method(
2014 "org.freedesktop.systemd1",
2015 "/org/freedesktop/systemd1",
2016 "org.freedesktop.systemd1.Manager",
2020 "ssi", "systemd-journald.service", "main", sig
);
2022 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
2027 /* Let's install the inotify watch, if we didn't do that yet. */
2030 mkdir_p("/run/systemd/journal", 0755);
2032 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
2034 return log_error_errno(errno
, "Failed to create inotify watch: %m");
2036 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_MOVED_TO
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
2038 return log_error_errno(errno
, "Failed to watch journal directory: %m");
2040 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
2044 /* OK, all preparatory steps done, let's wait until
2045 * inotify reports an event. */
2047 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
2049 return log_error_errno(r
, "Failed to wait for event: %m");
2051 r
= flush_fd(watch_fd
);
2053 return log_error_errno(r
, "Failed to flush inotify events: %m");
2059 static int rotate(void) {
2060 return send_signal_and_wait(SIGUSR2
, "/run/systemd/journal/rotated");
2063 static int sync_journal(void) {
2064 return send_signal_and_wait(SIGRTMIN
+1, "/run/systemd/journal/synced");
2067 int main(int argc
, char *argv
[]) {
2069 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2070 bool need_seek
= false;
2071 sd_id128_t previous_boot_id
;
2072 bool previous_boot_id_valid
= false, first_line
= true;
2074 bool ellipsized
= false;
2076 setlocale(LC_ALL
, "");
2077 log_parse_environment();
2080 r
= parse_argv(argc
, argv
);
2084 signal(SIGWINCH
, columns_lines_cache_reset
);
2087 /* Increase max number of open files to 16K if we can, we
2088 * might needs this when browsing journal files, which might
2089 * be split up into many files. */
2090 setrlimit_closest(RLIMIT_NOFILE
, &RLIMIT_MAKE_CONST(16384));
2092 switch (arg_action
) {
2094 case ACTION_NEW_ID128
:
2095 r
= generate_new_id128();
2098 case ACTION_SETUP_KEYS
:
2102 case ACTION_LIST_CATALOG
:
2103 case ACTION_DUMP_CATALOG
:
2104 case ACTION_UPDATE_CATALOG
: {
2105 _cleanup_free_
char *database
;
2107 database
= path_join(arg_root
, CATALOG_DATABASE
, NULL
);
2113 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2114 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2116 log_error_errno(r
, "Failed to list catalog: %m");
2118 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2120 (void) pager_open(arg_no_pager
, arg_pager_end
);
2123 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2125 r
= catalog_list(stdout
, database
, oneline
);
2127 log_error_errno(r
, "Failed to list catalog: %m");
2146 case ACTION_PRINT_HEADER
:
2148 case ACTION_DISK_USAGE
:
2149 case ACTION_LIST_BOOTS
:
2151 case ACTION_LIST_FIELDS
:
2152 case ACTION_LIST_FIELD_NAMES
:
2153 /* These ones require access to the journal files, continue below. */
2157 assert_not_reached("Unknown action");
2161 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2163 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2164 else if (arg_file_stdin
) {
2165 int ifd
= STDIN_FILENO
;
2166 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2167 } else if (arg_file
)
2168 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2169 else if (arg_machine
) {
2170 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2171 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2172 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2175 if (geteuid() != 0) {
2176 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2177 * the container, thus we need root privileges to override them. */
2178 log_error("Using the --machine= switch requires root privileges.");
2183 r
= sd_bus_open_system(&bus
);
2185 log_error_errno(r
, "Failed to open system bus: %m");
2189 r
= sd_bus_call_method(
2191 "org.freedesktop.machine1",
2192 "/org/freedesktop/machine1",
2193 "org.freedesktop.machine1.Manager",
2194 "OpenMachineRootDirectory",
2199 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2203 r
= sd_bus_message_read(reply
, "h", &fd
);
2205 bus_log_parse_error(r
);
2209 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2211 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2215 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2219 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2221 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2225 r
= journal_access_check_and_warn(j
, arg_quiet
,
2226 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2230 switch (arg_action
) {
2232 case ACTION_NEW_ID128
:
2233 case ACTION_SETUP_KEYS
:
2234 case ACTION_LIST_CATALOG
:
2235 case ACTION_DUMP_CATALOG
:
2236 case ACTION_UPDATE_CATALOG
:
2240 assert_not_reached("Unexpected action.");
2242 case ACTION_PRINT_HEADER
:
2243 journal_print_header(j
);
2251 case ACTION_DISK_USAGE
: {
2253 char sbytes
[FORMAT_BYTES_MAX
];
2255 r
= sd_journal_get_usage(j
, &bytes
);
2259 printf("Archived and active journals take up %s in the file system.\n",
2260 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2264 case ACTION_LIST_BOOTS
:
2268 case ACTION_VACUUM
: {
2272 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2278 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2280 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2288 case ACTION_LIST_FIELD_NAMES
: {
2291 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2292 printf("%s\n", field
);
2301 case ACTION_LIST_FIELDS
:
2305 assert_not_reached("Unknown action");
2308 if (arg_boot_offset
!= 0 &&
2309 sd_journal_has_runtime_files(j
) > 0 &&
2310 sd_journal_has_persistent_files(j
) == 0) {
2311 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2315 /* add_boot() must be called first!
2316 * It may need to seek the journal to find parent boot IDs. */
2327 log_error_errno(r
, "Failed to add filter for units: %m");
2331 r
= add_syslog_identifier(j
);
2333 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2337 r
= add_priorities(j
);
2341 r
= add_matches(j
, argv
+ optind
);
2345 if (DEBUG_LOGGING
) {
2346 _cleanup_free_
char *filter
;
2348 filter
= journal_make_match_string(j
);
2352 log_debug("Journal filter: %s", filter
);
2355 if (arg_action
== ACTION_LIST_FIELDS
) {
2361 r
= sd_journal_set_data_threshold(j
, 0);
2363 log_error_errno(r
, "Failed to unset data size threshold: %m");
2367 r
= sd_journal_query_unique(j
, arg_field
);
2369 log_error_errno(r
, "Failed to query unique data objects: %m");
2373 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2376 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2379 eq
= memchr(data
, '=', size
);
2381 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2383 printf("%.*s\n", (int) size
, (const char*) data
);
2392 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2394 r
= sd_journal_get_fd(j
);
2395 if (r
== -EMEDIUMTYPE
) {
2396 log_error_errno(r
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2400 log_error_errno(r
, "Failed to get journal fd: %m");
2405 if (arg_cursor
|| arg_after_cursor
) {
2406 r
= sd_journal_seek_cursor(j
, arg_cursor
?: arg_after_cursor
);
2408 log_error_errno(r
, "Failed to seek to cursor: %m");
2413 r
= sd_journal_next_skip(j
, 1 + !!arg_after_cursor
);
2415 r
= sd_journal_previous_skip(j
, 1 + !!arg_after_cursor
);
2417 if (arg_after_cursor
&& r
< 2) {
2418 /* We couldn't find the next entry after the cursor. */
2425 } else if (arg_since_set
&& !arg_reverse
) {
2426 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2428 log_error_errno(r
, "Failed to seek to date: %m");
2431 r
= sd_journal_next(j
);
2433 } else if (arg_until_set
&& arg_reverse
) {
2434 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2436 log_error_errno(r
, "Failed to seek to date: %m");
2439 r
= sd_journal_previous(j
);
2441 } else if (arg_lines
>= 0) {
2442 r
= sd_journal_seek_tail(j
);
2444 log_error_errno(r
, "Failed to seek to tail: %m");
2448 r
= sd_journal_previous_skip(j
, arg_lines
);
2450 } else if (arg_reverse
) {
2451 r
= sd_journal_seek_tail(j
);
2453 log_error_errno(r
, "Failed to seek to tail: %m");
2457 r
= sd_journal_previous(j
);
2460 r
= sd_journal_seek_head(j
);
2462 log_error_errno(r
, "Failed to seek to head: %m");
2466 r
= sd_journal_next(j
);
2470 log_error_errno(r
, "Failed to iterate through journal: %m");
2477 (void) pager_open(arg_no_pager
, arg_pager_end
);
2479 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2481 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2483 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2485 log_error_errno(r
, "Failed to get cutoff: %m");
2491 printf("-- Logs begin at %s. --\n",
2492 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2494 printf("-- Logs begin at %s, end at %s. --\n",
2495 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2496 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2501 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2503 size_t highlight
[2] = {};
2507 r
= sd_journal_next(j
);
2509 r
= sd_journal_previous(j
);
2511 log_error_errno(r
, "Failed to iterate through journal: %m");
2518 if (arg_until_set
&& !arg_reverse
) {
2521 r
= sd_journal_get_realtime_usec(j
, &usec
);
2523 log_error_errno(r
, "Failed to determine timestamp: %m");
2526 if (usec
> arg_until
)
2530 if (arg_since_set
&& arg_reverse
) {
2533 r
= sd_journal_get_realtime_usec(j
, &usec
);
2535 log_error_errno(r
, "Failed to determine timestamp: %m");
2538 if (usec
< arg_since
)
2542 if (!arg_merge
&& !arg_quiet
) {
2545 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2547 if (previous_boot_id_valid
&&
2548 !sd_id128_equal(boot_id
, previous_boot_id
))
2549 printf("%s-- Reboot --%s\n",
2550 ansi_highlight(), ansi_normal());
2552 previous_boot_id
= boot_id
;
2553 previous_boot_id_valid
= true;
2558 if (arg_compiled_pattern
) {
2559 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2560 const void *message
;
2564 md
= pcre2_match_data_create(1, NULL
);
2568 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2575 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2579 assert_se(message
= startswith(message
, "MESSAGE="));
2581 r
= pcre2_match(arg_compiled_pattern
,
2583 len
- strlen("MESSAGE="),
2584 0, /* start at offset 0 in the subject */
2585 0, /* default options */
2588 if (r
== PCRE2_ERROR_NOMATCH
) {
2593 unsigned char buf
[LINE_MAX
];
2596 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2597 log_error("Pattern matching failed: %s",
2598 r2
< 0 ? "unknown error" : (char*) buf
);
2603 ovec
= pcre2_get_ovector_pointer(md
);
2604 highlight
[0] = ovec
[0];
2605 highlight
[1] = ovec
[1];
2610 arg_all
* OUTPUT_SHOW_ALL
|
2611 arg_full
* OUTPUT_FULL_WIDTH
|
2612 colors_enabled() * OUTPUT_COLOR
|
2613 arg_catalog
* OUTPUT_CATALOG
|
2614 arg_utc
* OUTPUT_UTC
|
2615 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2617 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2618 arg_output_fields
, highlight
, &ellipsized
);
2620 if (r
== -EADDRNOTAVAIL
)
2622 else if (r
< 0 || ferror(stdout
))
2627 /* If journalctl take a long time to process messages, and during that time journal file
2628 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2629 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2630 * in the "following" case. By periodically calling sd_journal_process() during the processing
2631 * loop we shrink the window of time a client instance has open file descriptors for rotated
2632 * (deleted) journal files. */
2633 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2634 r
= sd_journal_process(j
);
2636 log_error_errno(r
, "Failed to process inotify events: %m");
2643 if (n_shown
== 0 && !arg_quiet
)
2644 printf("-- No entries --\n");
2646 if (arg_show_cursor
) {
2647 _cleanup_free_
char *cursor
= NULL
;
2649 r
= sd_journal_get_cursor(j
, &cursor
);
2650 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2651 log_error_errno(r
, "Failed to get cursor: %m");
2653 printf("-- cursor: %s\n", cursor
);
2660 r
= sd_journal_wait(j
, (uint64_t) -1);
2662 log_error_errno(r
, "Couldn't wait for journal event: %m");
2673 strv_free(arg_file
);
2675 strv_free(arg_syslog_identifier
);
2676 strv_free(arg_system_units
);
2677 strv_free(arg_user_units
);
2678 strv_free(arg_output_fields
);
2681 free(arg_verify_key
);
2684 if (arg_compiled_pattern
)
2685 pcre2_code_free(arg_compiled_pattern
);
2688 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;