1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
33 #include <sys/inotify.h>
38 # define PCRE2_CODE_UNIT_WIDTH 8
43 #include "sd-journal.h"
46 #include "alloc-util.h"
47 #include "bus-error.h"
50 #include "chattr-util.h"
55 #include "glob-util.h"
56 #include "hostname-util.h"
58 #include "journal-def.h"
59 #include "journal-internal.h"
60 #include "journal-qrcode.h"
61 #include "journal-util.h"
62 #include "journal-vacuum.h"
63 #include "journal-verify.h"
64 #include "locale-util.h"
66 #include "logs-show.h"
69 #include "parse-util.h"
70 #include "path-util.h"
71 #include "rlimit-util.h"
75 #include "syslog-util.h"
76 #include "terminal-util.h"
78 #include "udev-util.h"
79 #include "unit-name.h"
80 #include "user-util.h"
82 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
84 #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
87 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data
*, pcre2_match_data_free
);
88 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code
*, pcre2_code_free
);
90 static int pattern_compile(const char *pattern
, unsigned flags
, pcre2_code
**out
) {
92 PCRE2_SIZE erroroffset
;
95 p
= pcre2_compile((PCRE2_SPTR8
) pattern
,
96 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
98 unsigned char buf
[LINE_MAX
];
100 r
= pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
102 log_error("Bad pattern \"%s\": %s",
104 r
< 0 ? "unknown error" : (char*) buf
);
115 /* Special values for arg_lines */
116 ARG_LINES_DEFAULT
= -2,
120 static OutputMode arg_output
= OUTPUT_SHORT
;
121 static bool arg_utc
= false;
122 static bool arg_pager_end
= false;
123 static bool arg_follow
= false;
124 static bool arg_full
= true;
125 static bool arg_all
= false;
126 static bool arg_no_pager
= false;
127 static int arg_lines
= ARG_LINES_DEFAULT
;
128 static bool arg_no_tail
= false;
129 static bool arg_quiet
= false;
130 static bool arg_merge
= false;
131 static bool arg_boot
= false;
132 static sd_id128_t arg_boot_id
= {};
133 static int arg_boot_offset
= 0;
134 static bool arg_dmesg
= false;
135 static bool arg_no_hostname
= false;
136 static const char *arg_cursor
= NULL
;
137 static const char *arg_after_cursor
= NULL
;
138 static bool arg_show_cursor
= false;
139 static const char *arg_directory
= NULL
;
140 static char **arg_file
= NULL
;
141 static bool arg_file_stdin
= false;
142 static int arg_priorities
= 0xFF;
143 static char *arg_verify_key
= NULL
;
145 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
146 static bool arg_force
= false;
148 static usec_t arg_since
, arg_until
;
149 static bool arg_since_set
= false, arg_until_set
= false;
150 static char **arg_syslog_identifier
= NULL
;
151 static char **arg_system_units
= NULL
;
152 static char **arg_user_units
= NULL
;
153 static const char *arg_field
= NULL
;
154 static bool arg_catalog
= false;
155 static bool arg_reverse
= false;
156 static int arg_journal_type
= 0;
157 static char *arg_root
= NULL
;
158 static const char *arg_machine
= NULL
;
159 static uint64_t arg_vacuum_size
= 0;
160 static uint64_t arg_vacuum_n_files
= 0;
161 static usec_t arg_vacuum_time
= 0;
162 static char **arg_output_fields
= NULL
;
165 static const char *arg_pattern
= NULL
;
166 static pcre2_code
*arg_compiled_pattern
= NULL
;
167 static int arg_case_sensitive
= -1; /* -1 means be smart */
179 ACTION_UPDATE_CATALOG
,
186 ACTION_LIST_FIELD_NAMES
,
187 } arg_action
= ACTION_SHOW
;
189 typedef struct BootId
{
193 LIST_FIELDS(struct BootId
, boot_list
);
196 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
198 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
199 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
200 struct udev_device
*d
= NULL
;
206 if (!path_startswith(devpath
, "/dev/")) {
207 log_error("Devpath does not start with /dev/");
215 r
= stat(devpath
, &st
);
217 log_error_errno(errno
, "Couldn't stat file: %m");
219 d
= device
= udev_device_new_from_devnum(udev
, S_ISBLK(st
.st_mode
) ? 'b' : 'c', st
.st_rdev
);
221 return log_error_errno(errno
, "Failed to get udev device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
224 _cleanup_free_
char *match
= NULL
;
225 const char *subsys
, *sysname
, *devnode
;
227 subsys
= udev_device_get_subsystem(d
);
229 d
= udev_device_get_parent(d
);
233 sysname
= udev_device_get_sysname(d
);
235 d
= udev_device_get_parent(d
);
239 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
243 r
= sd_journal_add_match(j
, match
, 0);
245 return log_error_errno(r
, "Failed to add match: %m");
247 devnode
= udev_device_get_devnode(d
);
249 _cleanup_free_
char *match1
= NULL
;
251 r
= stat(devnode
, &st
);
253 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
255 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
259 r
= sd_journal_add_match(j
, match1
, 0);
261 return log_error_errno(r
, "Failed to add match: %m");
264 d
= udev_device_get_parent(d
);
267 r
= add_match_this_boot(j
, arg_machine
);
269 return log_error_errno(r
, "Failed to add match for the current boot: %m");
274 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
277 return format_timestamp_utc(buf
, l
, t
);
279 return format_timestamp(buf
, l
, t
);
282 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
283 sd_id128_t id
= SD_ID128_NULL
;
286 if (strlen(x
) >= 32) {
290 r
= sd_id128_from_string(t
, &id
);
294 if (!IN_SET(*x
, 0, '-', '+'))
298 r
= safe_atoi(x
, &off
);
303 r
= safe_atoi(x
, &off
);
317 static void help(void) {
319 pager_open(arg_no_pager
, arg_pager_end
);
321 printf("%s [OPTIONS...] [MATCHES...]\n\n"
322 "Query the journal.\n\n"
324 " --system Show the system journal\n"
325 " --user Show the user journal for the current user\n"
326 " -M --machine=CONTAINER Operate on local container\n"
327 " -S --since=DATE Show entries not older than the specified date\n"
328 " -U --until=DATE Show entries not newer than the specified date\n"
329 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
330 " --after-cursor=CURSOR Show entries after the specified cursor\n"
331 " --show-cursor Print the cursor after all the entries\n"
332 " -b --boot[=ID] Show current boot or the specified boot\n"
333 " --list-boots Show terse information about recorded boots\n"
334 " -k --dmesg Show kernel message log from the current boot\n"
335 " -u --unit=UNIT Show logs from the specified unit\n"
336 " --user-unit=UNIT Show logs from the specified user unit\n"
337 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
338 " -p --priority=RANGE Show entries with the specified priority\n"
339 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
340 " --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n"
341 " -e --pager-end Immediately jump to the end in the pager\n"
342 " -f --follow Follow the journal\n"
343 " -n --lines[=INTEGER] Number of journal entries to show\n"
344 " --no-tail Show all lines, even in follow mode\n"
345 " -r --reverse Show the newest entries first\n"
346 " -o --output=STRING Change journal output mode (short, short-precise,\n"
347 " short-iso, short-iso-precise, short-full,\n"
348 " short-monotonic, short-unix, verbose, export,\n"
349 " json, json-pretty, json-sse, cat)\n"
350 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
351 " --utc Express time in Coordinated Universal Time (UTC)\n"
352 " -x --catalog Add message explanations where available\n"
353 " --no-full Ellipsize fields\n"
354 " -a --all Show all fields, including long and unprintable\n"
355 " -q --quiet Do not show info messages and privilege warning\n"
356 " --no-pager Do not pipe output into a pager\n"
357 " --no-hostname Suppress output of hostname field\n"
358 " -m --merge Show entries from all available journals\n"
359 " -D --directory=PATH Show journal files from directory\n"
360 " --file=PATH Show journal file\n"
361 " --root=ROOT Operate on files below a root directory\n"
363 " --interval=TIME Time interval for changing the FSS sealing key\n"
364 " --verify-key=KEY Specify FSS verification key\n"
365 " --force Override of the FSS key pair with --setup-keys\n"
368 " -h --help Show this help text\n"
369 " --version Show package version\n"
370 " -N --fields List all field names currently used\n"
371 " -F --field=FIELD List all values that a specified field takes\n"
372 " --disk-usage Show total disk usage of all journal files\n"
373 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
374 " --vacuum-files=INT Leave only the specified number of journal files\n"
375 " --vacuum-time=TIME Remove journal files older than specified time\n"
376 " --verify Verify journal file consistency\n"
377 " --sync Synchronize unwritten journal messages to disk\n"
378 " --flush Flush all journal data from /run into /var\n"
379 " --rotate Request immediate rotation of the journal files\n"
380 " --header Show journal header information\n"
381 " --list-catalog Show all message IDs in the catalog\n"
382 " --dump-catalog Show entries in the message catalog\n"
383 " --update-catalog Update the message catalog database\n"
384 " --new-id128 Generate a new 128-bit ID\n"
386 " --setup-keys Generate a new FSS key pair\n"
388 , program_invocation_short_name
);
391 static int parse_argv(int argc
, char *argv
[]) {
430 static const struct option options
[] = {
431 { "help", no_argument
, NULL
, 'h' },
432 { "version" , no_argument
, NULL
, ARG_VERSION
},
433 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
434 { "pager-end", no_argument
, NULL
, 'e' },
435 { "follow", no_argument
, NULL
, 'f' },
436 { "force", no_argument
, NULL
, ARG_FORCE
},
437 { "output", required_argument
, NULL
, 'o' },
438 { "all", no_argument
, NULL
, 'a' },
439 { "full", no_argument
, NULL
, 'l' },
440 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
441 { "lines", optional_argument
, NULL
, 'n' },
442 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
443 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
444 { "quiet", no_argument
, NULL
, 'q' },
445 { "merge", no_argument
, NULL
, 'm' },
446 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
447 { "boot", optional_argument
, NULL
, 'b' },
448 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
449 { "dmesg", no_argument
, NULL
, 'k' },
450 { "system", no_argument
, NULL
, ARG_SYSTEM
},
451 { "user", no_argument
, NULL
, ARG_USER
},
452 { "directory", required_argument
, NULL
, 'D' },
453 { "file", required_argument
, NULL
, ARG_FILE
},
454 { "root", required_argument
, NULL
, ARG_ROOT
},
455 { "header", no_argument
, NULL
, ARG_HEADER
},
456 { "identifier", required_argument
, NULL
, 't' },
457 { "priority", required_argument
, NULL
, 'p' },
458 { "grep", required_argument
, NULL
, 'g' },
459 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
460 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
461 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
462 { "verify", no_argument
, NULL
, ARG_VERIFY
},
463 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
464 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
465 { "cursor", required_argument
, NULL
, 'c' },
466 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
467 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
468 { "since", required_argument
, NULL
, 'S' },
469 { "until", required_argument
, NULL
, 'U' },
470 { "unit", required_argument
, NULL
, 'u' },
471 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
472 { "field", required_argument
, NULL
, 'F' },
473 { "fields", no_argument
, NULL
, 'N' },
474 { "catalog", no_argument
, NULL
, 'x' },
475 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
476 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
477 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
478 { "reverse", no_argument
, NULL
, 'r' },
479 { "machine", required_argument
, NULL
, 'M' },
480 { "utc", no_argument
, NULL
, ARG_UTC
},
481 { "flush", no_argument
, NULL
, ARG_FLUSH
},
482 { "sync", no_argument
, NULL
, ARG_SYNC
},
483 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
484 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
485 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
486 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
487 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
488 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
497 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
513 arg_pager_end
= true;
515 if (arg_lines
== ARG_LINES_DEFAULT
)
525 arg_output
= output_mode_from_string(optarg
);
526 if (arg_output
< 0) {
527 log_error("Unknown output format '%s'.", optarg
);
531 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_CAT
))
550 if (streq(optarg
, "all"))
551 arg_lines
= ARG_LINES_ALL
;
553 r
= safe_atoi(optarg
, &arg_lines
);
554 if (r
< 0 || arg_lines
< 0) {
555 log_error("Failed to parse lines '%s'", optarg
);
562 /* Hmm, no argument? Maybe the next
563 * word on the command line is
564 * supposed to be the argument? Let's
565 * see if there is one, and is
569 if (streq(argv
[optind
], "all")) {
570 arg_lines
= ARG_LINES_ALL
;
572 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
586 arg_action
= ACTION_NEW_ID128
;
605 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
607 log_error("Failed to parse boot descriptor '%s'", optarg
);
612 /* Hmm, no argument? Maybe the next
613 * word on the command line is
614 * supposed to be the argument? Let's
615 * see if there is one and is parsable
616 * as a boot descriptor... */
619 parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
) >= 0)
626 arg_action
= ACTION_LIST_BOOTS
;
630 arg_boot
= arg_dmesg
= true;
634 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
638 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
642 arg_machine
= optarg
;
646 arg_directory
= optarg
;
650 if (streq(optarg
, "-"))
651 /* An undocumented feature: we can read journal files from STDIN. We don't document
652 * this though, since after all we only support this for mmap-able, seekable files, and
653 * not for example pipes which are probably the primary usecase for reading things from
654 * STDIN. To avoid confusion we hence don't document this feature. */
655 arg_file_stdin
= true;
657 r
= glob_extend(&arg_file
, optarg
);
659 return log_error_errno(r
, "Failed to add paths: %m");
664 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
673 case ARG_AFTER_CURSOR
:
674 arg_after_cursor
= optarg
;
677 case ARG_SHOW_CURSOR
:
678 arg_show_cursor
= true;
682 arg_action
= ACTION_PRINT_HEADER
;
686 arg_action
= ACTION_VERIFY
;
690 arg_action
= ACTION_DISK_USAGE
;
693 case ARG_VACUUM_SIZE
:
694 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
696 log_error("Failed to parse vacuum size: %s", optarg
);
700 arg_action
= ACTION_VACUUM
;
703 case ARG_VACUUM_FILES
:
704 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
706 log_error("Failed to parse vacuum files: %s", optarg
);
710 arg_action
= ACTION_VACUUM
;
713 case ARG_VACUUM_TIME
:
714 r
= parse_sec(optarg
, &arg_vacuum_time
);
716 log_error("Failed to parse vacuum time: %s", optarg
);
720 arg_action
= ACTION_VACUUM
;
729 arg_action
= ACTION_SETUP_KEYS
;
734 arg_action
= ACTION_VERIFY
;
735 r
= free_and_strdup(&arg_verify_key
, optarg
);
738 /* Use memset not string_erase so this doesn't look confusing
739 * in ps or htop output. */
740 memset(optarg
, 'x', strlen(optarg
));
746 r
= parse_sec(optarg
, &arg_interval
);
747 if (r
< 0 || arg_interval
<= 0) {
748 log_error("Failed to parse sealing key change interval: %s", optarg
);
757 log_error("Forward-secure sealing not available.");
764 dots
= strstr(optarg
, "..");
770 a
= strndup(optarg
, dots
- optarg
);
774 from
= log_level_from_string(a
);
775 to
= log_level_from_string(dots
+ 2);
778 if (from
< 0 || to
< 0) {
779 log_error("Failed to parse log level range %s", optarg
);
786 for (i
= from
; i
<= to
; i
++)
787 arg_priorities
|= 1 << i
;
789 for (i
= to
; i
<= from
; i
++)
790 arg_priorities
|= 1 << i
;
796 p
= log_level_from_string(optarg
);
798 log_error("Unknown log level %s", optarg
);
804 for (i
= 0; i
<= p
; i
++)
805 arg_priorities
|= 1 << i
;
813 arg_pattern
= optarg
;
816 case ARG_CASE_SENSITIVE
:
818 r
= parse_boolean(optarg
);
820 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
821 arg_case_sensitive
= r
;
823 arg_case_sensitive
= true;
828 case ARG_CASE_SENSITIVE
:
829 return log_error("Compiled without pattern matching support");
833 r
= parse_timestamp(optarg
, &arg_since
);
835 log_error("Failed to parse timestamp: %s", optarg
);
838 arg_since_set
= true;
842 r
= parse_timestamp(optarg
, &arg_until
);
844 log_error("Failed to parse timestamp: %s", optarg
);
847 arg_until_set
= true;
851 r
= strv_extend(&arg_syslog_identifier
, optarg
);
857 r
= strv_extend(&arg_system_units
, optarg
);
863 r
= strv_extend(&arg_user_units
, optarg
);
869 arg_action
= ACTION_LIST_FIELDS
;
874 arg_action
= ACTION_LIST_FIELD_NAMES
;
877 case ARG_NO_HOSTNAME
:
878 arg_no_hostname
= true;
885 case ARG_LIST_CATALOG
:
886 arg_action
= ACTION_LIST_CATALOG
;
889 case ARG_DUMP_CATALOG
:
890 arg_action
= ACTION_DUMP_CATALOG
;
893 case ARG_UPDATE_CATALOG
:
894 arg_action
= ACTION_UPDATE_CATALOG
;
906 arg_action
= ACTION_FLUSH
;
910 arg_action
= ACTION_ROTATE
;
914 arg_action
= ACTION_SYNC
;
917 case ARG_OUTPUT_FIELDS
: {
918 _cleanup_strv_free_
char **v
= NULL
;
920 v
= strv_split(optarg
, ",");
924 if (!arg_output_fields
) {
925 arg_output_fields
= v
;
928 r
= strv_extend_strv(&arg_output_fields
, v
, true);
939 assert_not_reached("Unhandled option");
942 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
945 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
> 1) {
946 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
950 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
951 log_error("--since= must be before --until=.");
955 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
956 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
960 if (arg_follow
&& arg_reverse
) {
961 log_error("Please specify either --reverse= or --follow=, not both.");
965 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
966 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
970 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
971 log_error("Using --boot or --list-boots with --merge is not supported.");
975 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
976 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
977 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
978 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
979 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
983 arg_system_units
= strv_free(arg_system_units
);
991 if (arg_case_sensitive
>= 0)
992 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
994 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
996 _cleanup_(pcre2_code_freep
) pcre2_code
*cs
= NULL
;
998 md
= pcre2_match_data_create(1, NULL
);
1002 r
= pattern_compile("[[:upper:]]", 0, &cs
);
1006 r
= pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
1009 flags
= !has_case
* PCRE2_CASELESS
;
1012 log_debug("Doing case %s matching based on %s",
1013 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
1014 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
1016 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1025 static int generate_new_id128(void) {
1030 r
= sd_id128_randomize(&id
);
1032 return log_error_errno(r
, "Failed to generate ID: %m");
1034 printf("As string:\n"
1035 SD_ID128_FORMAT_STR
"\n\n"
1037 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
1038 "As man:sd-id128(3) macro:\n"
1039 "#define MESSAGE_XYZ SD_ID128_MAKE(",
1040 SD_ID128_FORMAT_VAL(id
),
1041 SD_ID128_FORMAT_VAL(id
));
1042 for (i
= 0; i
< 16; i
++)
1043 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
1044 fputs(")\n\n", stdout
);
1046 printf("As Python constant:\n"
1048 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
1049 SD_ID128_FORMAT_VAL(id
));
1054 static int add_matches(sd_journal
*j
, char **args
) {
1056 bool have_term
= false;
1060 STRV_FOREACH(i
, args
) {
1063 if (streq(*i
, "+")) {
1066 r
= sd_journal_add_disjunction(j
);
1069 } else if (path_is_absolute(*i
)) {
1070 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1073 r
= chase_symlinks(*i
, NULL
, 0, &p
);
1075 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1077 if (lstat(p
, &st
) < 0)
1078 return log_error_errno(errno
, "Couldn't stat file: %m");
1080 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1081 if (executable_is_script(p
, &interpreter
) > 0) {
1082 _cleanup_free_
char *comm
;
1084 comm
= strndup(basename(p
), 15);
1088 t
= strappend("_COMM=", comm
);
1092 /* Append _EXE only if the interpreter is not a link.
1093 Otherwise, it might be outdated often. */
1094 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1095 t2
= strappend("_EXE=", interpreter
);
1100 t
= strappend("_EXE=", p
);
1105 r
= sd_journal_add_match(j
, t
, 0);
1108 r
= sd_journal_add_match(j
, t2
, 0);
1110 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1111 r
= add_matches_for_device(j
, p
);
1115 log_error("File is neither a device node, nor regular file, nor executable: %s", *i
);
1121 r
= sd_journal_add_match(j
, *i
, 0);
1126 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1129 if (!strv_isempty(args
) && !have_term
) {
1130 log_error("\"+\" can only be used between terms");
1137 static void boot_id_free_all(BootId
*l
) {
1141 LIST_REMOVE(boot_list
, l
, i
);
1146 static int discover_next_boot(sd_journal
*j
,
1147 sd_id128_t previous_boot_id
,
1151 _cleanup_free_ BootId
*next_boot
= NULL
;
1152 char match
[9+32+1] = "_BOOT_ID=";
1159 /* We expect the journal to be on the last position of a boot
1160 * (in relation to the direction we are going), so that the next
1161 * invocation of sd_journal_next/previous will be from a different
1162 * boot. We then collect any information we desire and then jump
1163 * to the last location of the new boot by using a _BOOT_ID match
1164 * coming from the other journal direction. */
1166 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1167 * we can actually advance to a *different* boot. */
1168 sd_journal_flush_matches(j
);
1172 r
= sd_journal_previous(j
);
1174 r
= sd_journal_next(j
);
1178 return 0; /* End of journal, yay. */
1180 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1184 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1185 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1186 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1187 * complete than the main entry array, and hence might reference an entry that's not actually the last
1188 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1189 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1192 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1194 next_boot
= new0(BootId
, 1);
1198 next_boot
->id
= boot_id
;
1200 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1204 /* Now seek to the last occurrence of this boot ID. */
1205 sd_id128_to_string(next_boot
->id
, match
+ 9);
1206 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1211 r
= sd_journal_seek_head(j
);
1213 r
= sd_journal_seek_tail(j
);
1218 r
= sd_journal_next(j
);
1220 r
= sd_journal_previous(j
);
1224 log_debug("Whoopsie! We found a boot ID but can't read its last entry.");
1225 return -ENODATA
; /* This shouldn't happen. We just came from this very boot ID. */
1228 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1238 static int get_boots(
1241 sd_id128_t
*boot_id
,
1246 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1247 const bool advance_older
= boot_id
&& offset
<= 0;
1248 sd_id128_t previous_boot_id
;
1252 /* Adjust for the asymmetry that offset 0 is
1253 * the last (and current) boot, while 1 is considered the
1254 * (chronological) first boot in the journal. */
1255 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1257 /* Advance to the earliest/latest occurrence of our reference
1258 * boot ID (taking our lookup direction into account), so that
1259 * discover_next_boot() can do its job.
1260 * If no reference is given, the journal head/tail will do,
1261 * they're "virtual" boots after all. */
1262 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1263 char match
[9+32+1] = "_BOOT_ID=";
1265 sd_journal_flush_matches(j
);
1267 sd_id128_to_string(*boot_id
, match
+ 9);
1268 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1273 r
= sd_journal_seek_head(j
); /* seek to oldest */
1275 r
= sd_journal_seek_tail(j
); /* seek to newest */
1280 r
= sd_journal_next(j
); /* read the oldest entry */
1282 r
= sd_journal_previous(j
); /* read the most recently added entry */
1287 else if (offset
== 0) {
1292 /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
1293 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1294 * the following entry, which must then have an older/newer boot ID */
1298 r
= sd_journal_seek_tail(j
); /* seek to newest */
1300 r
= sd_journal_seek_head(j
); /* seek to oldest */
1304 /* No sd_journal_next()/_previous() here.
1306 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1307 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1311 previous_boot_id
= SD_ID128_NULL
;
1313 _cleanup_free_ BootId
*current
= NULL
;
1315 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1317 boot_id_free_all(head
);
1324 previous_boot_id
= current
->id
;
1328 offset
+= advance_older
? 1 : -1;
1333 *boot_id
= current
->id
;
1337 LIST_FOREACH(boot_list
, id
, head
) {
1338 if (sd_id128_equal(id
->id
, current
->id
)) {
1339 /* boot id already stored, something wrong with the journal files */
1340 /* exiting as otherwise this problem would cause forever loop */
1344 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1355 sd_journal_flush_matches(j
);
1360 static int list_boots(sd_journal
*j
) {
1362 BootId
*id
, *all_ids
;
1366 count
= get_boots(j
, &all_ids
, NULL
, 0);
1368 return log_error_errno(count
, "Failed to determine boots: %m");
1372 pager_open(arg_no_pager
, arg_pager_end
);
1374 /* numbers are one less, but we need an extra char for the sign */
1375 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1378 LIST_FOREACH(boot_list
, id
, all_ids
) {
1379 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1381 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1383 SD_ID128_FORMAT_VAL(id
->id
),
1384 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1385 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1389 boot_id_free_all(all_ids
);
1394 static int add_boot(sd_journal
*j
) {
1395 char match
[9+32+1] = "_BOOT_ID=";
1404 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1405 * We can do this only when we logs are coming from the current machine,
1406 * so take the slow path if log location is specified. */
1407 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1408 !arg_directory
&& !arg_file
&& !arg_root
)
1410 return add_match_this_boot(j
, arg_machine
);
1412 boot_id
= arg_boot_id
;
1413 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1416 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror(-r
);
1418 if (sd_id128_is_null(arg_boot_id
))
1419 log_error("Data from the specified boot (%+i) is not available: %s",
1420 arg_boot_offset
, reason
);
1422 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1423 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1425 return r
== 0 ? -ENODATA
: r
;
1428 sd_id128_to_string(boot_id
, match
+ 9);
1430 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1432 return log_error_errno(r
, "Failed to add match: %m");
1434 r
= sd_journal_add_conjunction(j
);
1436 return log_error_errno(r
, "Failed to add conjunction: %m");
1441 static int add_dmesg(sd_journal
*j
) {
1448 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1449 STRLEN("_TRANSPORT=kernel"));
1451 return log_error_errno(r
, "Failed to add match: %m");
1453 r
= sd_journal_add_conjunction(j
);
1455 return log_error_errno(r
, "Failed to add conjunction: %m");
1460 static int get_possible_units(
1466 _cleanup_set_free_free_ Set
*found
;
1470 found
= set_new(&string_hash_ops
);
1474 NULSTR_FOREACH(field
, fields
) {
1478 r
= sd_journal_query_unique(j
, field
);
1482 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1483 char **pattern
, *eq
;
1485 _cleanup_free_
char *u
= NULL
;
1487 eq
= memchr(data
, '=', size
);
1489 prefix
= eq
- (char*) data
+ 1;
1493 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1497 STRV_FOREACH(pattern
, patterns
)
1498 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1499 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1501 r
= set_consume(found
, u
);
1503 if (r
< 0 && r
!= -EEXIST
)
1516 /* This list is supposed to return the superset of unit names
1517 * possibly matched by rules added with add_matches_for_unit... */
1518 #define SYSTEM_UNITS \
1522 "OBJECT_SYSTEMD_UNIT\0" \
1525 /* ... and add_matches_for_user_unit */
1526 #define USER_UNITS \
1527 "_SYSTEMD_USER_UNIT\0" \
1529 "COREDUMP_USER_UNIT\0" \
1530 "OBJECT_SYSTEMD_USER_UNIT\0"
1532 static int add_units(sd_journal
*j
) {
1533 _cleanup_strv_free_
char **patterns
= NULL
;
1539 STRV_FOREACH(i
, arg_system_units
) {
1540 _cleanup_free_
char *u
= NULL
;
1542 r
= unit_name_mangle(*i
, UNIT_NAME_GLOB
, &u
);
1546 if (string_is_glob(u
)) {
1547 r
= strv_push(&patterns
, u
);
1552 r
= add_matches_for_unit(j
, u
);
1555 r
= sd_journal_add_disjunction(j
);
1562 if (!strv_isempty(patterns
)) {
1563 _cleanup_set_free_free_ Set
*units
= NULL
;
1567 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1571 SET_FOREACH(u
, units
, it
) {
1572 r
= add_matches_for_unit(j
, u
);
1575 r
= sd_journal_add_disjunction(j
);
1582 patterns
= strv_free(patterns
);
1584 STRV_FOREACH(i
, arg_user_units
) {
1585 _cleanup_free_
char *u
= NULL
;
1587 r
= unit_name_mangle(*i
, UNIT_NAME_GLOB
, &u
);
1591 if (string_is_glob(u
)) {
1592 r
= strv_push(&patterns
, u
);
1597 r
= add_matches_for_user_unit(j
, u
, getuid());
1600 r
= sd_journal_add_disjunction(j
);
1607 if (!strv_isempty(patterns
)) {
1608 _cleanup_set_free_free_ Set
*units
= NULL
;
1612 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1616 SET_FOREACH(u
, units
, it
) {
1617 r
= add_matches_for_user_unit(j
, u
, getuid());
1620 r
= sd_journal_add_disjunction(j
);
1627 /* Complain if the user request matches but nothing whatsoever was
1628 * found, since otherwise everything would be matched. */
1629 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1632 r
= sd_journal_add_conjunction(j
);
1639 static int add_priorities(sd_journal
*j
) {
1640 char match
[] = "PRIORITY=0";
1644 if (arg_priorities
== 0xFF)
1647 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1648 if (arg_priorities
& (1 << i
)) {
1649 match
[sizeof(match
)-2] = '0' + i
;
1651 r
= sd_journal_add_match(j
, match
, strlen(match
));
1653 return log_error_errno(r
, "Failed to add match: %m");
1656 r
= sd_journal_add_conjunction(j
);
1658 return log_error_errno(r
, "Failed to add conjunction: %m");
1664 static int add_syslog_identifier(sd_journal
*j
) {
1670 STRV_FOREACH(i
, arg_syslog_identifier
) {
1673 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1674 r
= sd_journal_add_match(j
, u
, 0);
1677 r
= sd_journal_add_disjunction(j
);
1682 r
= sd_journal_add_conjunction(j
);
1689 static int setup_keys(void) {
1691 size_t mpk_size
, seed_size
, state_size
, i
;
1692 uint8_t *mpk
, *seed
, *state
;
1694 sd_id128_t machine
, boot
;
1695 char *p
= NULL
, *k
= NULL
;
1700 r
= stat("/var/log/journal", &st
);
1701 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1702 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1704 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1705 log_error("%s is not a directory, must be using persistent logging for FSS.",
1706 "/var/log/journal");
1707 return r
< 0 ? -errno
: -ENOTDIR
;
1710 r
= sd_id128_get_machine(&machine
);
1712 return log_error_errno(r
, "Failed to get machine ID: %m");
1714 r
= sd_id128_get_boot(&boot
);
1716 return log_error_errno(r
, "Failed to get boot ID: %m");
1718 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1719 SD_ID128_FORMAT_VAL(machine
)) < 0)
1724 if (r
< 0 && errno
!= ENOENT
) {
1725 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1728 } else if (access(p
, F_OK
) >= 0) {
1729 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1734 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1735 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1740 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1741 mpk
= alloca(mpk_size
);
1743 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1744 seed
= alloca(seed_size
);
1746 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1747 state
= alloca(state_size
);
1749 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1751 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1755 log_info("Generating seed...");
1756 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1758 log_error_errno(r
, "Failed to read random seed: %m");
1762 log_info("Generating key pair...");
1763 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1765 log_info("Generating sealing key...");
1766 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1768 assert(arg_interval
> 0);
1770 n
= now(CLOCK_REALTIME
);
1774 fd
= mkostemp_safe(k
);
1776 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1780 /* Enable secure remove, exclusion from dump, synchronous
1781 * writing and in-place updating */
1782 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
);
1784 log_warning_errno(r
, "Failed to set file attributes: %m");
1787 memcpy(h
.signature
, "KSHHRHLP", 8);
1788 h
.machine_id
= machine
;
1790 h
.header_size
= htole64(sizeof(h
));
1791 h
.start_usec
= htole64(n
* arg_interval
);
1792 h
.interval_usec
= htole64(arg_interval
);
1793 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1794 h
.fsprg_state_size
= htole64(state_size
);
1796 r
= loop_write(fd
, &h
, sizeof(h
), false);
1798 log_error_errno(r
, "Failed to write header: %m");
1802 r
= loop_write(fd
, state
, state_size
, false);
1804 log_error_errno(r
, "Failed to write state: %m");
1808 if (link(k
, p
) < 0) {
1809 r
= log_error_errno(errno
, "Failed to link file: %m");
1816 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1817 "the following local file. This key file is automatically updated when the\n"
1818 "sealing key is advanced. It should not be used on multiple hosts.\n"
1822 "Please write down the following %ssecret verification key%s. It should be stored\n"
1823 "at a safe location and should not be saved locally on disk.\n"
1825 ansi_highlight(), ansi_normal(),
1827 ansi_highlight(), ansi_normal(),
1828 ansi_highlight_red());
1831 for (i
= 0; i
< seed_size
; i
++) {
1832 if (i
> 0 && i
% 3 == 0)
1834 printf("%02x", ((uint8_t*) seed
)[i
]);
1837 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1840 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1844 "The sealing key is automatically changed every %s.\n",
1846 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1848 hn
= gethostname_malloc();
1851 hostname_cleanup(hn
);
1852 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1854 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1857 /* If this is not an UTF-8 system don't print any QR codes */
1858 if (is_locale_utf8()) {
1859 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1860 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1880 log_error("Forward-secure sealing not available.");
1885 static int verify(sd_journal
*j
) {
1892 log_show_color(true);
1894 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1896 usec_t first
= 0, validated
= 0, last
= 0;
1899 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1900 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1903 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1905 /* If the key was invalid give up right-away. */
1908 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1911 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1912 log_info("PASS: %s", f
->path
);
1914 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1915 if (validated
> 0) {
1916 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1917 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1918 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1919 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1920 } else if (last
> 0)
1921 log_info("=> No sealing yet, %s of entries not sealed.",
1922 format_timespan(c
, sizeof(c
), last
- first
, 0));
1924 log_info("=> No sealing yet, no entries in file.");
1932 static int flush_to_var(void) {
1933 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1934 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1935 _cleanup_close_
int watch_fd
= -1;
1939 log_error("--flush is not supported in conjunction with --machine=.");
1944 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1947 /* OK, let's actually do the full logic, send SIGUSR1 to the
1948 * daemon and set up inotify to wait for the flushed file to appear */
1949 r
= bus_connect_system_systemd(&bus
);
1951 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1953 r
= sd_bus_call_method(
1955 "org.freedesktop.systemd1",
1956 "/org/freedesktop/systemd1",
1957 "org.freedesktop.systemd1.Manager",
1961 "ssi", "systemd-journald.service", "main", SIGUSR1
);
1963 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
1965 mkdir_p("/run/systemd/journal", 0755);
1967 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1969 return log_error_errno(errno
, "Failed to create inotify watch: %m");
1971 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_CREATE
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
1973 return log_error_errno(errno
, "Failed to watch journal directory: %m");
1976 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1979 if (errno
!= ENOENT
)
1980 return log_error_errno(errno
, "Failed to check for existence of /run/systemd/journal/flushed: %m");
1982 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
1984 return log_error_errno(r
, "Failed to wait for event: %m");
1986 r
= flush_fd(watch_fd
);
1988 return log_error_errno(r
, "Failed to flush inotify events: %m");
1994 static int send_signal_and_wait(int sig
, const char *watch_path
) {
1995 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1996 _cleanup_close_
int watch_fd
= -1;
2001 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
2005 start
= now(CLOCK_MONOTONIC
);
2007 /* This call sends the specified signal to journald, and waits
2008 * for acknowledgment by watching the mtime of the specified
2009 * flag file. This is used to trigger syncing or rotation and
2010 * then wait for the operation to complete. */
2015 /* See if a sync happened by now. */
2016 r
= read_timestamp_file(watch_path
, &tstamp
);
2017 if (r
< 0 && r
!= -ENOENT
)
2018 return log_error_errno(errno
, "Failed to read %s: %m", watch_path
);
2019 if (r
>= 0 && tstamp
>= start
)
2022 /* Let's ask for a sync, but only once. */
2024 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2026 r
= bus_connect_system_systemd(&bus
);
2028 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
2030 r
= sd_bus_call_method(
2032 "org.freedesktop.systemd1",
2033 "/org/freedesktop/systemd1",
2034 "org.freedesktop.systemd1.Manager",
2038 "ssi", "systemd-journald.service", "main", sig
);
2040 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
2045 /* Let's install the inotify watch, if we didn't do that yet. */
2048 mkdir_p("/run/systemd/journal", 0755);
2050 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
2052 return log_error_errno(errno
, "Failed to create inotify watch: %m");
2054 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_MOVED_TO
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
2056 return log_error_errno(errno
, "Failed to watch journal directory: %m");
2058 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
2062 /* OK, all preparatory steps done, let's wait until
2063 * inotify reports an event. */
2065 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
2067 return log_error_errno(r
, "Failed to wait for event: %m");
2069 r
= flush_fd(watch_fd
);
2071 return log_error_errno(r
, "Failed to flush inotify events: %m");
2077 static int rotate(void) {
2078 return send_signal_and_wait(SIGUSR2
, "/run/systemd/journal/rotated");
2081 static int sync_journal(void) {
2082 return send_signal_and_wait(SIGRTMIN
+1, "/run/systemd/journal/synced");
2085 int main(int argc
, char *argv
[]) {
2087 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2088 bool need_seek
= false;
2089 sd_id128_t previous_boot_id
;
2090 bool previous_boot_id_valid
= false, first_line
= true;
2092 bool ellipsized
= false;
2094 setlocale(LC_ALL
, "");
2095 log_parse_environment();
2098 r
= parse_argv(argc
, argv
);
2102 signal(SIGWINCH
, columns_lines_cache_reset
);
2105 /* Increase max number of open files to 16K if we can, we
2106 * might needs this when browsing journal files, which might
2107 * be split up into many files. */
2108 setrlimit_closest(RLIMIT_NOFILE
, &RLIMIT_MAKE_CONST(16384));
2110 switch (arg_action
) {
2112 case ACTION_NEW_ID128
:
2113 r
= generate_new_id128();
2116 case ACTION_SETUP_KEYS
:
2120 case ACTION_LIST_CATALOG
:
2121 case ACTION_DUMP_CATALOG
:
2122 case ACTION_UPDATE_CATALOG
: {
2123 _cleanup_free_
char *database
;
2125 database
= path_join(arg_root
, CATALOG_DATABASE
, NULL
);
2131 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2132 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2134 log_error_errno(r
, "Failed to list catalog: %m");
2136 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2138 pager_open(arg_no_pager
, arg_pager_end
);
2141 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2143 r
= catalog_list(stdout
, database
, oneline
);
2145 log_error_errno(r
, "Failed to list catalog: %m");
2164 case ACTION_PRINT_HEADER
:
2166 case ACTION_DISK_USAGE
:
2167 case ACTION_LIST_BOOTS
:
2169 case ACTION_LIST_FIELDS
:
2170 case ACTION_LIST_FIELD_NAMES
:
2171 /* These ones require access to the journal files, continue below. */
2175 assert_not_reached("Unknown action");
2179 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2181 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2182 else if (arg_file_stdin
) {
2183 int ifd
= STDIN_FILENO
;
2184 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2185 } else if (arg_file
)
2186 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2187 else if (arg_machine
) {
2188 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2189 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2190 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2193 if (geteuid() != 0) {
2194 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2195 * the container, thus we need root privileges to override them. */
2196 log_error("Using the --machine= switch requires root privileges.");
2201 r
= sd_bus_open_system(&bus
);
2203 log_error_errno(r
, "Failed to open system bus: %m");
2207 r
= sd_bus_call_method(
2209 "org.freedesktop.machine1",
2210 "/org/freedesktop/machine1",
2211 "org.freedesktop.machine1.Manager",
2212 "OpenMachineRootDirectory",
2217 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2221 r
= sd_bus_message_read(reply
, "h", &fd
);
2223 bus_log_parse_error(r
);
2227 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2229 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2233 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2237 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2239 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2243 r
= journal_access_check_and_warn(j
, arg_quiet
,
2244 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2248 switch (arg_action
) {
2250 case ACTION_NEW_ID128
:
2251 case ACTION_SETUP_KEYS
:
2252 case ACTION_LIST_CATALOG
:
2253 case ACTION_DUMP_CATALOG
:
2254 case ACTION_UPDATE_CATALOG
:
2258 assert_not_reached("Unexpected action.");
2260 case ACTION_PRINT_HEADER
:
2261 journal_print_header(j
);
2269 case ACTION_DISK_USAGE
: {
2271 char sbytes
[FORMAT_BYTES_MAX
];
2273 r
= sd_journal_get_usage(j
, &bytes
);
2277 printf("Archived and active journals take up %s in the file system.\n",
2278 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2282 case ACTION_LIST_BOOTS
:
2286 case ACTION_VACUUM
: {
2290 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2296 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2298 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2306 case ACTION_LIST_FIELD_NAMES
: {
2309 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2310 printf("%s\n", field
);
2319 case ACTION_LIST_FIELDS
:
2323 assert_not_reached("Unknown action");
2326 if (arg_boot_offset
!= 0 &&
2327 sd_journal_has_runtime_files(j
) > 0 &&
2328 sd_journal_has_persistent_files(j
) == 0) {
2329 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2333 /* add_boot() must be called first!
2334 * It may need to seek the journal to find parent boot IDs. */
2345 log_error_errno(r
, "Failed to add filter for units: %m");
2349 r
= add_syslog_identifier(j
);
2351 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2355 r
= add_priorities(j
);
2359 r
= add_matches(j
, argv
+ optind
);
2363 if (DEBUG_LOGGING
) {
2364 _cleanup_free_
char *filter
;
2366 filter
= journal_make_match_string(j
);
2370 log_debug("Journal filter: %s", filter
);
2373 if (arg_action
== ACTION_LIST_FIELDS
) {
2379 r
= sd_journal_set_data_threshold(j
, 0);
2381 log_error_errno(r
, "Failed to unset data size threshold: %m");
2385 r
= sd_journal_query_unique(j
, arg_field
);
2387 log_error_errno(r
, "Failed to query unique data objects: %m");
2391 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2394 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2397 eq
= memchr(data
, '=', size
);
2399 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2401 printf("%.*s\n", (int) size
, (const char*) data
);
2410 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2412 r
= sd_journal_get_fd(j
);
2413 if (r
== -EMEDIUMTYPE
) {
2414 log_error_errno(r
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2418 log_error_errno(r
, "Failed to get journal fd: %m");
2423 if (arg_cursor
|| arg_after_cursor
) {
2424 r
= sd_journal_seek_cursor(j
, arg_cursor
?: arg_after_cursor
);
2426 log_error_errno(r
, "Failed to seek to cursor: %m");
2431 r
= sd_journal_next_skip(j
, 1 + !!arg_after_cursor
);
2433 r
= sd_journal_previous_skip(j
, 1 + !!arg_after_cursor
);
2435 if (arg_after_cursor
&& r
< 2) {
2436 /* We couldn't find the next entry after the cursor. */
2443 } else if (arg_since_set
&& !arg_reverse
) {
2444 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2446 log_error_errno(r
, "Failed to seek to date: %m");
2449 r
= sd_journal_next(j
);
2451 } else if (arg_until_set
&& arg_reverse
) {
2452 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2454 log_error_errno(r
, "Failed to seek to date: %m");
2457 r
= sd_journal_previous(j
);
2459 } else if (arg_lines
>= 0) {
2460 r
= sd_journal_seek_tail(j
);
2462 log_error_errno(r
, "Failed to seek to tail: %m");
2466 r
= sd_journal_previous_skip(j
, arg_lines
);
2468 } else if (arg_reverse
) {
2469 r
= sd_journal_seek_tail(j
);
2471 log_error_errno(r
, "Failed to seek to tail: %m");
2475 r
= sd_journal_previous(j
);
2478 r
= sd_journal_seek_head(j
);
2480 log_error_errno(r
, "Failed to seek to head: %m");
2484 r
= sd_journal_next(j
);
2488 log_error_errno(r
, "Failed to iterate through journal: %m");
2495 pager_open(arg_no_pager
, arg_pager_end
);
2497 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2499 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2501 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2503 log_error_errno(r
, "Failed to get cutoff: %m");
2509 printf("-- Logs begin at %s. --\n",
2510 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2512 printf("-- Logs begin at %s, end at %s. --\n",
2513 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2514 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2519 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2521 size_t highlight
[2] = {};
2525 r
= sd_journal_next(j
);
2527 r
= sd_journal_previous(j
);
2529 log_error_errno(r
, "Failed to iterate through journal: %m");
2536 if (arg_until_set
&& !arg_reverse
) {
2539 r
= sd_journal_get_realtime_usec(j
, &usec
);
2541 log_error_errno(r
, "Failed to determine timestamp: %m");
2544 if (usec
> arg_until
)
2548 if (arg_since_set
&& arg_reverse
) {
2551 r
= sd_journal_get_realtime_usec(j
, &usec
);
2553 log_error_errno(r
, "Failed to determine timestamp: %m");
2556 if (usec
< arg_since
)
2560 if (!arg_merge
&& !arg_quiet
) {
2563 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2565 if (previous_boot_id_valid
&&
2566 !sd_id128_equal(boot_id
, previous_boot_id
))
2567 printf("%s-- Reboot --%s\n",
2568 ansi_highlight(), ansi_normal());
2570 previous_boot_id
= boot_id
;
2571 previous_boot_id_valid
= true;
2576 if (arg_compiled_pattern
) {
2577 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2578 const void *message
;
2582 md
= pcre2_match_data_create(1, NULL
);
2586 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2593 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2597 assert_se(message
= startswith(message
, "MESSAGE="));
2599 r
= pcre2_match(arg_compiled_pattern
,
2601 len
- strlen("MESSAGE="),
2602 0, /* start at offset 0 in the subject */
2603 0, /* default options */
2606 if (r
== PCRE2_ERROR_NOMATCH
) {
2611 unsigned char buf
[LINE_MAX
];
2614 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2615 log_error("Pattern matching failed: %s",
2616 r2
< 0 ? "unknown error" : (char*) buf
);
2621 ovec
= pcre2_get_ovector_pointer(md
);
2622 highlight
[0] = ovec
[0];
2623 highlight
[1] = ovec
[1];
2628 arg_all
* OUTPUT_SHOW_ALL
|
2629 arg_full
* OUTPUT_FULL_WIDTH
|
2630 colors_enabled() * OUTPUT_COLOR
|
2631 arg_catalog
* OUTPUT_CATALOG
|
2632 arg_utc
* OUTPUT_UTC
|
2633 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2635 r
= output_journal(stdout
, j
, arg_output
, 0, flags
,
2636 arg_output_fields
, highlight
, &ellipsized
);
2638 if (r
== -EADDRNOTAVAIL
)
2640 else if (r
< 0 || ferror(stdout
))
2645 /* If journalctl take a long time to process messages, and during that time journal file
2646 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2647 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2648 * in the "following" case. By periodically calling sd_journal_process() during the processing
2649 * loop we shrink the window of time a client instance has open file descriptors for rotated
2650 * (deleted) journal files. */
2651 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2652 r
= sd_journal_process(j
);
2654 log_error_errno(r
, "Failed to process inotify events: %m");
2661 if (n_shown
== 0 && !arg_quiet
)
2662 printf("-- No entries --\n");
2664 if (arg_show_cursor
) {
2665 _cleanup_free_
char *cursor
= NULL
;
2667 r
= sd_journal_get_cursor(j
, &cursor
);
2668 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2669 log_error_errno(r
, "Failed to get cursor: %m");
2671 printf("-- cursor: %s\n", cursor
);
2678 r
= sd_journal_wait(j
, (uint64_t) -1);
2680 log_error_errno(r
, "Couldn't wait for journal event: %m");
2691 strv_free(arg_file
);
2693 strv_free(arg_syslog_identifier
);
2694 strv_free(arg_system_units
);
2695 strv_free(arg_user_units
);
2696 strv_free(arg_output_fields
);
2699 free(arg_verify_key
);
2702 if (arg_compiled_pattern
)
2703 pcre2_code_free(arg_compiled_pattern
);
2706 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;