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)
85 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data
*, pcre2_match_data_free
);
87 static int pattern_compile(const char *pattern
, unsigned flags
, pcre2_code
**out
) {
89 PCRE2_SIZE erroroffset
;
92 p
= pcre2_compile((PCRE2_SPTR8
) pattern
,
93 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
95 unsigned char buf
[LINE_MAX
];
97 r
= pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
99 log_error("Bad pattern \"%s\": %s",
101 r
< 0 ? "unknown error" : (char*) buf
);
112 /* Special values for arg_lines */
113 ARG_LINES_DEFAULT
= -2,
117 static OutputMode arg_output
= OUTPUT_SHORT
;
118 static bool arg_utc
= false;
119 static bool arg_pager_end
= false;
120 static bool arg_follow
= false;
121 static bool arg_full
= true;
122 static bool arg_all
= false;
123 static bool arg_no_pager
= false;
124 static int arg_lines
= ARG_LINES_DEFAULT
;
125 static bool arg_no_tail
= false;
126 static bool arg_quiet
= false;
127 static bool arg_merge
= false;
128 static bool arg_boot
= false;
129 static sd_id128_t arg_boot_id
= {};
130 static int arg_boot_offset
= 0;
131 static bool arg_dmesg
= false;
132 static bool arg_no_hostname
= false;
133 static const char *arg_cursor
= NULL
;
134 static const char *arg_after_cursor
= NULL
;
135 static bool arg_show_cursor
= false;
136 static const char *arg_directory
= NULL
;
137 static char **arg_file
= NULL
;
138 static bool arg_file_stdin
= false;
139 static int arg_priorities
= 0xFF;
140 static char *arg_verify_key
= NULL
;
142 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
143 static bool arg_force
= false;
145 static usec_t arg_since
, arg_until
;
146 static bool arg_since_set
= false, arg_until_set
= false;
147 static char **arg_syslog_identifier
= NULL
;
148 static char **arg_system_units
= NULL
;
149 static char **arg_user_units
= NULL
;
150 static const char *arg_field
= NULL
;
151 static bool arg_catalog
= false;
152 static bool arg_reverse
= false;
153 static int arg_journal_type
= 0;
154 static char *arg_root
= NULL
;
155 static const char *arg_machine
= NULL
;
156 static uint64_t arg_vacuum_size
= 0;
157 static uint64_t arg_vacuum_n_files
= 0;
158 static usec_t arg_vacuum_time
= 0;
159 static char **arg_output_fields
= NULL
;
162 static pcre2_code
*arg_pattern
= NULL
;
174 ACTION_UPDATE_CATALOG
,
181 ACTION_LIST_FIELD_NAMES
,
182 } arg_action
= ACTION_SHOW
;
184 typedef struct BootId
{
188 LIST_FIELDS(struct BootId
, boot_list
);
191 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
193 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
194 _cleanup_udev_device_unref_
struct udev_device
*device
= NULL
;
195 struct udev_device
*d
= NULL
;
201 if (!path_startswith(devpath
, "/dev/")) {
202 log_error("Devpath does not start with /dev/");
210 r
= stat(devpath
, &st
);
212 log_error_errno(errno
, "Couldn't stat file: %m");
214 d
= device
= udev_device_new_from_devnum(udev
, S_ISBLK(st
.st_mode
) ? 'b' : 'c', st
.st_rdev
);
216 return log_error_errno(errno
, "Failed to get udev device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
219 _cleanup_free_
char *match
= NULL
;
220 const char *subsys
, *sysname
, *devnode
;
222 subsys
= udev_device_get_subsystem(d
);
224 d
= udev_device_get_parent(d
);
228 sysname
= udev_device_get_sysname(d
);
230 d
= udev_device_get_parent(d
);
234 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
238 r
= sd_journal_add_match(j
, match
, 0);
240 return log_error_errno(r
, "Failed to add match: %m");
242 devnode
= udev_device_get_devnode(d
);
244 _cleanup_free_
char *match1
= NULL
;
246 r
= stat(devnode
, &st
);
248 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
250 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
254 r
= sd_journal_add_match(j
, match1
, 0);
256 return log_error_errno(r
, "Failed to add match: %m");
259 d
= udev_device_get_parent(d
);
262 r
= add_match_this_boot(j
, arg_machine
);
264 return log_error_errno(r
, "Failed to add match for the current boot: %m");
269 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
272 return format_timestamp_utc(buf
, l
, t
);
274 return format_timestamp(buf
, l
, t
);
277 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
278 sd_id128_t id
= SD_ID128_NULL
;
281 if (strlen(x
) >= 32) {
285 r
= sd_id128_from_string(t
, &id
);
289 if (!IN_SET(*x
, 0, '-', '+'))
293 r
= safe_atoi(x
, &off
);
298 r
= safe_atoi(x
, &off
);
312 static void help(void) {
314 pager_open(arg_no_pager
, arg_pager_end
);
316 printf("%s [OPTIONS...] [MATCHES...]\n\n"
317 "Query the journal.\n\n"
319 " --system Show the system journal\n"
320 " --user Show the user journal for the current user\n"
321 " -M --machine=CONTAINER Operate on local container\n"
322 " -S --since=DATE Show entries not older than the specified date\n"
323 " -U --until=DATE Show entries not newer than the specified date\n"
324 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
325 " --after-cursor=CURSOR Show entries after the specified cursor\n"
326 " --show-cursor Print the cursor after all the entries\n"
327 " -b --boot[=ID] Show current boot or the specified boot\n"
328 " --list-boots Show terse information about recorded boots\n"
329 " -k --dmesg Show kernel message log from the current boot\n"
330 " -u --unit=UNIT Show logs from the specified unit\n"
331 " --user-unit=UNIT Show logs from the specified user unit\n"
332 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
333 " -p --priority=RANGE Show entries with the specified priority\n"
334 " -g --grep=PATTERN Show entries with MESSSAGE matching PATTERN\n"
335 " -e --pager-end Immediately jump to the end in the pager\n"
336 " -f --follow Follow the journal\n"
337 " -n --lines[=INTEGER] Number of journal entries to show\n"
338 " --no-tail Show all lines, even in follow mode\n"
339 " -r --reverse Show the newest entries first\n"
340 " -o --output=STRING Change journal output mode (short, short-precise,\n"
341 " short-iso, short-iso-precise, short-full,\n"
342 " short-monotonic, short-unix, verbose, export,\n"
343 " json, json-pretty, json-sse, cat)\n"
344 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
345 " --utc Express time in Coordinated Universal Time (UTC)\n"
346 " -x --catalog Add message explanations where available\n"
347 " --no-full Ellipsize fields\n"
348 " -a --all Show all fields, including long and unprintable\n"
349 " -q --quiet Do not show info messages and privilege warning\n"
350 " --no-pager Do not pipe output into a pager\n"
351 " --no-hostname Suppress output of hostname field\n"
352 " -m --merge Show entries from all available journals\n"
353 " -D --directory=PATH Show journal files from directory\n"
354 " --file=PATH Show journal file\n"
355 " --root=ROOT Operate on files below a root directory\n"
357 " --interval=TIME Time interval for changing the FSS sealing key\n"
358 " --verify-key=KEY Specify FSS verification key\n"
359 " --force Override of the FSS key pair with --setup-keys\n"
362 " -h --help Show this help text\n"
363 " --version Show package version\n"
364 " -N --fields List all field names currently used\n"
365 " -F --field=FIELD List all values that a specified field takes\n"
366 " --disk-usage Show total disk usage of all journal files\n"
367 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
368 " --vacuum-files=INT Leave only the specified number of journal files\n"
369 " --vacuum-time=TIME Remove journal files older than specified time\n"
370 " --verify Verify journal file consistency\n"
371 " --sync Synchronize unwritten journal messages to disk\n"
372 " --flush Flush all journal data from /run into /var\n"
373 " --rotate Request immediate rotation of the journal files\n"
374 " --header Show journal header information\n"
375 " --list-catalog Show all message IDs in the catalog\n"
376 " --dump-catalog Show entries in the message catalog\n"
377 " --update-catalog Update the message catalog database\n"
378 " --new-id128 Generate a new 128-bit ID\n"
380 " --setup-keys Generate a new FSS key pair\n"
382 , program_invocation_short_name
);
385 static int parse_argv(int argc
, char *argv
[]) {
423 static const struct option options
[] = {
424 { "help", no_argument
, NULL
, 'h' },
425 { "version" , no_argument
, NULL
, ARG_VERSION
},
426 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
427 { "pager-end", no_argument
, NULL
, 'e' },
428 { "follow", no_argument
, NULL
, 'f' },
429 { "force", no_argument
, NULL
, ARG_FORCE
},
430 { "output", required_argument
, NULL
, 'o' },
431 { "all", no_argument
, NULL
, 'a' },
432 { "full", no_argument
, NULL
, 'l' },
433 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
434 { "lines", optional_argument
, NULL
, 'n' },
435 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
436 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
437 { "quiet", no_argument
, NULL
, 'q' },
438 { "merge", no_argument
, NULL
, 'm' },
439 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
440 { "boot", optional_argument
, NULL
, 'b' },
441 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
442 { "dmesg", no_argument
, NULL
, 'k' },
443 { "system", no_argument
, NULL
, ARG_SYSTEM
},
444 { "user", no_argument
, NULL
, ARG_USER
},
445 { "directory", required_argument
, NULL
, 'D' },
446 { "file", required_argument
, NULL
, ARG_FILE
},
447 { "root", required_argument
, NULL
, ARG_ROOT
},
448 { "header", no_argument
, NULL
, ARG_HEADER
},
449 { "identifier", required_argument
, NULL
, 't' },
450 { "priority", required_argument
, NULL
, 'p' },
451 { "grep", required_argument
, NULL
, 'g' },
452 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
453 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
454 { "verify", no_argument
, NULL
, ARG_VERIFY
},
455 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
456 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
457 { "cursor", required_argument
, NULL
, 'c' },
458 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
459 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
460 { "since", required_argument
, NULL
, 'S' },
461 { "until", required_argument
, NULL
, 'U' },
462 { "unit", required_argument
, NULL
, 'u' },
463 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
464 { "field", required_argument
, NULL
, 'F' },
465 { "fields", no_argument
, NULL
, 'N' },
466 { "catalog", no_argument
, NULL
, 'x' },
467 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
468 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
469 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
470 { "reverse", no_argument
, NULL
, 'r' },
471 { "machine", required_argument
, NULL
, 'M' },
472 { "utc", no_argument
, NULL
, ARG_UTC
},
473 { "flush", no_argument
, NULL
, ARG_FLUSH
},
474 { "sync", no_argument
, NULL
, ARG_SYNC
},
475 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
476 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
477 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
478 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
479 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
480 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
489 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
505 arg_pager_end
= true;
507 if (arg_lines
== ARG_LINES_DEFAULT
)
517 arg_output
= output_mode_from_string(optarg
);
518 if (arg_output
< 0) {
519 log_error("Unknown output format '%s'.", optarg
);
523 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_CAT
))
542 if (streq(optarg
, "all"))
543 arg_lines
= ARG_LINES_ALL
;
545 r
= safe_atoi(optarg
, &arg_lines
);
546 if (r
< 0 || arg_lines
< 0) {
547 log_error("Failed to parse lines '%s'", optarg
);
554 /* Hmm, no argument? Maybe the next
555 * word on the command line is
556 * supposed to be the argument? Let's
557 * see if there is one, and is
561 if (streq(argv
[optind
], "all")) {
562 arg_lines
= ARG_LINES_ALL
;
564 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
578 arg_action
= ACTION_NEW_ID128
;
597 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
599 log_error("Failed to parse boot descriptor '%s'", optarg
);
604 /* Hmm, no argument? Maybe the next
605 * word on the command line is
606 * supposed to be the argument? Let's
607 * see if there is one and is parsable
608 * as a boot descriptor... */
611 parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
) >= 0)
618 arg_action
= ACTION_LIST_BOOTS
;
622 arg_boot
= arg_dmesg
= true;
626 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
630 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
634 arg_machine
= optarg
;
638 arg_directory
= optarg
;
642 if (streq(optarg
, "-"))
643 /* An undocumented feature: we can read journal files from STDIN. We don't document
644 * this though, since after all we only support this for mmap-able, seekable files, and
645 * not for example pipes which are probably the primary usecase for reading things from
646 * STDIN. To avoid confusion we hence don't document this feature. */
647 arg_file_stdin
= true;
649 r
= glob_extend(&arg_file
, optarg
);
651 return log_error_errno(r
, "Failed to add paths: %m");
656 r
= parse_path_argument_and_warn(optarg
, true, &arg_root
);
665 case ARG_AFTER_CURSOR
:
666 arg_after_cursor
= optarg
;
669 case ARG_SHOW_CURSOR
:
670 arg_show_cursor
= true;
674 arg_action
= ACTION_PRINT_HEADER
;
678 arg_action
= ACTION_VERIFY
;
682 arg_action
= ACTION_DISK_USAGE
;
685 case ARG_VACUUM_SIZE
:
686 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
688 log_error("Failed to parse vacuum size: %s", optarg
);
692 arg_action
= ACTION_VACUUM
;
695 case ARG_VACUUM_FILES
:
696 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
698 log_error("Failed to parse vacuum files: %s", optarg
);
702 arg_action
= ACTION_VACUUM
;
705 case ARG_VACUUM_TIME
:
706 r
= parse_sec(optarg
, &arg_vacuum_time
);
708 log_error("Failed to parse vacuum time: %s", optarg
);
712 arg_action
= ACTION_VACUUM
;
721 arg_action
= ACTION_SETUP_KEYS
;
726 arg_action
= ACTION_VERIFY
;
727 r
= free_and_strdup(&arg_verify_key
, optarg
);
730 /* Use memset not string_erase so this doesn't look confusing
731 * in ps or htop output. */
732 memset(optarg
, 'x', strlen(optarg
));
738 r
= parse_sec(optarg
, &arg_interval
);
739 if (r
< 0 || arg_interval
<= 0) {
740 log_error("Failed to parse sealing key change interval: %s", optarg
);
749 log_error("Forward-secure sealing not available.");
756 dots
= strstr(optarg
, "..");
762 a
= strndup(optarg
, dots
- optarg
);
766 from
= log_level_from_string(a
);
767 to
= log_level_from_string(dots
+ 2);
770 if (from
< 0 || to
< 0) {
771 log_error("Failed to parse log level range %s", optarg
);
778 for (i
= from
; i
<= to
; i
++)
779 arg_priorities
|= 1 << i
;
781 for (i
= to
; i
<= from
; i
++)
782 arg_priorities
|= 1 << i
;
788 p
= log_level_from_string(optarg
);
790 log_error("Unknown log level %s", optarg
);
796 for (i
= 0; i
<= p
; i
++)
797 arg_priorities
|= 1 << i
;
806 pcre2_code_free(arg_pattern
);
809 r
= pattern_compile(optarg
, 0, &arg_pattern
);
818 return log_error("Compiled without pattern matching support");
822 r
= parse_timestamp(optarg
, &arg_since
);
824 log_error("Failed to parse timestamp: %s", optarg
);
827 arg_since_set
= true;
831 r
= parse_timestamp(optarg
, &arg_until
);
833 log_error("Failed to parse timestamp: %s", optarg
);
836 arg_until_set
= true;
840 r
= strv_extend(&arg_syslog_identifier
, optarg
);
846 r
= strv_extend(&arg_system_units
, optarg
);
852 r
= strv_extend(&arg_user_units
, optarg
);
858 arg_action
= ACTION_LIST_FIELDS
;
863 arg_action
= ACTION_LIST_FIELD_NAMES
;
866 case ARG_NO_HOSTNAME
:
867 arg_no_hostname
= true;
874 case ARG_LIST_CATALOG
:
875 arg_action
= ACTION_LIST_CATALOG
;
878 case ARG_DUMP_CATALOG
:
879 arg_action
= ACTION_DUMP_CATALOG
;
882 case ARG_UPDATE_CATALOG
:
883 arg_action
= ACTION_UPDATE_CATALOG
;
895 arg_action
= ACTION_FLUSH
;
899 arg_action
= ACTION_ROTATE
;
903 arg_action
= ACTION_SYNC
;
906 case ARG_OUTPUT_FIELDS
: {
907 _cleanup_strv_free_
char **v
= NULL
;
909 v
= strv_split(optarg
, ",");
913 if (!arg_output_fields
) {
914 arg_output_fields
= v
;
917 r
= strv_extend_strv(&arg_output_fields
, v
, true);
928 assert_not_reached("Unhandled option");
931 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
934 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
> 1) {
935 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
939 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
940 log_error("--since= must be before --until=.");
944 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
945 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
949 if (arg_follow
&& arg_reverse
) {
950 log_error("Please specify either --reverse= or --follow=, not both.");
954 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
955 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
959 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
960 log_error("Using --boot or --list-boots with --merge is not supported.");
964 if (!strv_isempty(arg_system_units
) && (arg_journal_type
== SD_JOURNAL_CURRENT_USER
)) {
966 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
967 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
968 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
969 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
973 arg_system_units
= strv_free(arg_system_units
);
979 static int generate_new_id128(void) {
984 r
= sd_id128_randomize(&id
);
986 return log_error_errno(r
, "Failed to generate ID: %m");
988 printf("As string:\n"
989 SD_ID128_FORMAT_STR
"\n\n"
991 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
992 "As man:sd-id128(3) macro:\n"
993 "#define MESSAGE_XYZ SD_ID128_MAKE(",
994 SD_ID128_FORMAT_VAL(id
),
995 SD_ID128_FORMAT_VAL(id
));
996 for (i
= 0; i
< 16; i
++)
997 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
998 fputs(")\n\n", stdout
);
1000 printf("As Python constant:\n"
1002 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
1003 SD_ID128_FORMAT_VAL(id
));
1008 static int add_matches(sd_journal
*j
, char **args
) {
1010 bool have_term
= false;
1014 STRV_FOREACH(i
, args
) {
1017 if (streq(*i
, "+")) {
1020 r
= sd_journal_add_disjunction(j
);
1023 } else if (path_is_absolute(*i
)) {
1024 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1027 r
= chase_symlinks(*i
, NULL
, 0, &p
);
1029 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1031 if (lstat(p
, &st
) < 0)
1032 return log_error_errno(errno
, "Couldn't stat file: %m");
1034 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1035 if (executable_is_script(p
, &interpreter
) > 0) {
1036 _cleanup_free_
char *comm
;
1038 comm
= strndup(basename(p
), 15);
1042 t
= strappend("_COMM=", comm
);
1046 /* Append _EXE only if the interpreter is not a link.
1047 Otherwise, it might be outdated often. */
1048 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1049 t2
= strappend("_EXE=", interpreter
);
1054 t
= strappend("_EXE=", p
);
1059 r
= sd_journal_add_match(j
, t
, 0);
1062 r
= sd_journal_add_match(j
, t2
, 0);
1064 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1065 r
= add_matches_for_device(j
, p
);
1069 log_error("File is neither a device node, nor regular file, nor executable: %s", *i
);
1075 r
= sd_journal_add_match(j
, *i
, 0);
1080 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1083 if (!strv_isempty(args
) && !have_term
) {
1084 log_error("\"+\" can only be used between terms");
1091 static void boot_id_free_all(BootId
*l
) {
1095 LIST_REMOVE(boot_list
, l
, i
);
1100 static int discover_next_boot(sd_journal
*j
,
1101 sd_id128_t previous_boot_id
,
1105 _cleanup_free_ BootId
*next_boot
= NULL
;
1106 char match
[9+32+1] = "_BOOT_ID=";
1113 /* We expect the journal to be on the last position of a boot
1114 * (in relation to the direction we are going), so that the next
1115 * invocation of sd_journal_next/previous will be from a different
1116 * boot. We then collect any information we desire and then jump
1117 * to the last location of the new boot by using a _BOOT_ID match
1118 * coming from the other journal direction. */
1120 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1121 * we can actually advance to a *different* boot. */
1122 sd_journal_flush_matches(j
);
1126 r
= sd_journal_previous(j
);
1128 r
= sd_journal_next(j
);
1132 return 0; /* End of journal, yay. */
1134 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1138 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1139 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1140 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1141 * complete than the main entry array, and hence might reference an entry that's not actually the last
1142 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1143 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1146 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1148 next_boot
= new0(BootId
, 1);
1152 next_boot
->id
= boot_id
;
1154 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1158 /* Now seek to the last occurrence of this boot ID. */
1159 sd_id128_to_string(next_boot
->id
, match
+ 9);
1160 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1165 r
= sd_journal_seek_head(j
);
1167 r
= sd_journal_seek_tail(j
);
1172 r
= sd_journal_next(j
);
1174 r
= sd_journal_previous(j
);
1178 log_debug("Whoopsie! We found a boot ID but can't read its last entry.");
1179 return -ENODATA
; /* This shouldn't happen. We just came from this very boot ID. */
1182 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1192 static int get_boots(
1195 sd_id128_t
*boot_id
,
1200 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1201 const bool advance_older
= boot_id
&& offset
<= 0;
1202 sd_id128_t previous_boot_id
;
1206 /* Adjust for the asymmetry that offset 0 is
1207 * the last (and current) boot, while 1 is considered the
1208 * (chronological) first boot in the journal. */
1209 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1211 /* Advance to the earliest/latest occurrence of our reference
1212 * boot ID (taking our lookup direction into account), so that
1213 * discover_next_boot() can do its job.
1214 * If no reference is given, the journal head/tail will do,
1215 * they're "virtual" boots after all. */
1216 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1217 char match
[9+32+1] = "_BOOT_ID=";
1219 sd_journal_flush_matches(j
);
1221 sd_id128_to_string(*boot_id
, match
+ 9);
1222 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1227 r
= sd_journal_seek_head(j
); /* seek to oldest */
1229 r
= sd_journal_seek_tail(j
); /* seek to newest */
1234 r
= sd_journal_next(j
); /* read the oldest entry */
1236 r
= sd_journal_previous(j
); /* read the most recently added entry */
1241 else if (offset
== 0) {
1246 /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
1247 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1248 * the following entry, which must then have an older/newer boot ID */
1252 r
= sd_journal_seek_tail(j
); /* seek to newest */
1254 r
= sd_journal_seek_head(j
); /* seek to oldest */
1258 /* No sd_journal_next()/_previous() here.
1260 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1261 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1265 previous_boot_id
= SD_ID128_NULL
;
1267 _cleanup_free_ BootId
*current
= NULL
;
1269 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1271 boot_id_free_all(head
);
1278 previous_boot_id
= current
->id
;
1282 offset
+= advance_older
? 1 : -1;
1287 *boot_id
= current
->id
;
1291 LIST_FOREACH(boot_list
, id
, head
) {
1292 if (sd_id128_equal(id
->id
, current
->id
)) {
1293 /* boot id already stored, something wrong with the journal files */
1294 /* exiting as otherwise this problem would cause forever loop */
1298 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1309 sd_journal_flush_matches(j
);
1314 static int list_boots(sd_journal
*j
) {
1316 BootId
*id
, *all_ids
;
1320 count
= get_boots(j
, &all_ids
, NULL
, 0);
1322 return log_error_errno(count
, "Failed to determine boots: %m");
1326 pager_open(arg_no_pager
, arg_pager_end
);
1328 /* numbers are one less, but we need an extra char for the sign */
1329 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1332 LIST_FOREACH(boot_list
, id
, all_ids
) {
1333 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1335 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1337 SD_ID128_FORMAT_VAL(id
->id
),
1338 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1339 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1343 boot_id_free_all(all_ids
);
1348 static int add_boot(sd_journal
*j
) {
1349 char match
[9+32+1] = "_BOOT_ID=";
1358 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1359 * We can do this only when we logs are coming from the current machine,
1360 * so take the slow path if log location is specified. */
1361 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1362 !arg_directory
&& !arg_file
&& !arg_root
)
1364 return add_match_this_boot(j
, arg_machine
);
1366 boot_id
= arg_boot_id
;
1367 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1370 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror(-r
);
1372 if (sd_id128_is_null(arg_boot_id
))
1373 log_error("Data from the specified boot (%+i) is not available: %s",
1374 arg_boot_offset
, reason
);
1376 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1377 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1379 return r
== 0 ? -ENODATA
: r
;
1382 sd_id128_to_string(boot_id
, match
+ 9);
1384 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1386 return log_error_errno(r
, "Failed to add match: %m");
1388 r
= sd_journal_add_conjunction(j
);
1390 return log_error_errno(r
, "Failed to add conjunction: %m");
1395 static int add_dmesg(sd_journal
*j
) {
1402 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1403 STRLEN("_TRANSPORT=kernel"));
1405 return log_error_errno(r
, "Failed to add match: %m");
1407 r
= sd_journal_add_conjunction(j
);
1409 return log_error_errno(r
, "Failed to add conjunction: %m");
1414 static int get_possible_units(
1420 _cleanup_set_free_free_ Set
*found
;
1424 found
= set_new(&string_hash_ops
);
1428 NULSTR_FOREACH(field
, fields
) {
1432 r
= sd_journal_query_unique(j
, field
);
1436 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1437 char **pattern
, *eq
;
1439 _cleanup_free_
char *u
= NULL
;
1441 eq
= memchr(data
, '=', size
);
1443 prefix
= eq
- (char*) data
+ 1;
1447 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1451 STRV_FOREACH(pattern
, patterns
)
1452 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1453 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1455 r
= set_consume(found
, u
);
1457 if (r
< 0 && r
!= -EEXIST
)
1470 /* This list is supposed to return the superset of unit names
1471 * possibly matched by rules added with add_matches_for_unit... */
1472 #define SYSTEM_UNITS \
1476 "OBJECT_SYSTEMD_UNIT\0" \
1479 /* ... and add_matches_for_user_unit */
1480 #define USER_UNITS \
1481 "_SYSTEMD_USER_UNIT\0" \
1483 "COREDUMP_USER_UNIT\0" \
1484 "OBJECT_SYSTEMD_USER_UNIT\0"
1486 static int add_units(sd_journal
*j
) {
1487 _cleanup_strv_free_
char **patterns
= NULL
;
1493 STRV_FOREACH(i
, arg_system_units
) {
1494 _cleanup_free_
char *u
= NULL
;
1496 r
= unit_name_mangle(*i
, UNIT_NAME_GLOB
, &u
);
1500 if (string_is_glob(u
)) {
1501 r
= strv_push(&patterns
, u
);
1506 r
= add_matches_for_unit(j
, u
);
1509 r
= sd_journal_add_disjunction(j
);
1516 if (!strv_isempty(patterns
)) {
1517 _cleanup_set_free_free_ Set
*units
= NULL
;
1521 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1525 SET_FOREACH(u
, units
, it
) {
1526 r
= add_matches_for_unit(j
, u
);
1529 r
= sd_journal_add_disjunction(j
);
1536 patterns
= strv_free(patterns
);
1538 STRV_FOREACH(i
, arg_user_units
) {
1539 _cleanup_free_
char *u
= NULL
;
1541 r
= unit_name_mangle(*i
, UNIT_NAME_GLOB
, &u
);
1545 if (string_is_glob(u
)) {
1546 r
= strv_push(&patterns
, u
);
1551 r
= add_matches_for_user_unit(j
, u
, getuid());
1554 r
= sd_journal_add_disjunction(j
);
1561 if (!strv_isempty(patterns
)) {
1562 _cleanup_set_free_free_ Set
*units
= NULL
;
1566 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1570 SET_FOREACH(u
, units
, it
) {
1571 r
= add_matches_for_user_unit(j
, u
, getuid());
1574 r
= sd_journal_add_disjunction(j
);
1581 /* Complain if the user request matches but nothing whatsoever was
1582 * found, since otherwise everything would be matched. */
1583 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1586 r
= sd_journal_add_conjunction(j
);
1593 static int add_priorities(sd_journal
*j
) {
1594 char match
[] = "PRIORITY=0";
1598 if (arg_priorities
== 0xFF)
1601 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1602 if (arg_priorities
& (1 << i
)) {
1603 match
[sizeof(match
)-2] = '0' + i
;
1605 r
= sd_journal_add_match(j
, match
, strlen(match
));
1607 return log_error_errno(r
, "Failed to add match: %m");
1610 r
= sd_journal_add_conjunction(j
);
1612 return log_error_errno(r
, "Failed to add conjunction: %m");
1618 static int add_syslog_identifier(sd_journal
*j
) {
1624 STRV_FOREACH(i
, arg_syslog_identifier
) {
1627 u
= strjoina("SYSLOG_IDENTIFIER=", *i
);
1628 r
= sd_journal_add_match(j
, u
, 0);
1631 r
= sd_journal_add_disjunction(j
);
1636 r
= sd_journal_add_conjunction(j
);
1643 static int setup_keys(void) {
1645 size_t mpk_size
, seed_size
, state_size
, i
;
1646 uint8_t *mpk
, *seed
, *state
;
1648 sd_id128_t machine
, boot
;
1649 char *p
= NULL
, *k
= NULL
;
1654 r
= stat("/var/log/journal", &st
);
1655 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1656 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1658 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1659 log_error("%s is not a directory, must be using persistent logging for FSS.",
1660 "/var/log/journal");
1661 return r
< 0 ? -errno
: -ENOTDIR
;
1664 r
= sd_id128_get_machine(&machine
);
1666 return log_error_errno(r
, "Failed to get machine ID: %m");
1668 r
= sd_id128_get_boot(&boot
);
1670 return log_error_errno(r
, "Failed to get boot ID: %m");
1672 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1673 SD_ID128_FORMAT_VAL(machine
)) < 0)
1678 if (r
< 0 && errno
!= ENOENT
) {
1679 r
= log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1682 } else if (access(p
, F_OK
) >= 0) {
1683 log_error("Sealing key file %s exists already. Use --force to recreate.", p
);
1688 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1689 SD_ID128_FORMAT_VAL(machine
)) < 0) {
1694 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1695 mpk
= alloca(mpk_size
);
1697 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1698 seed
= alloca(seed_size
);
1700 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1701 state
= alloca(state_size
);
1703 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1705 r
= log_error_errno(errno
, "Failed to open /dev/random: %m");
1709 log_info("Generating seed...");
1710 r
= loop_read_exact(fd
, seed
, seed_size
, true);
1712 log_error_errno(r
, "Failed to read random seed: %m");
1716 log_info("Generating key pair...");
1717 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1719 log_info("Generating sealing key...");
1720 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1722 assert(arg_interval
> 0);
1724 n
= now(CLOCK_REALTIME
);
1728 fd
= mkostemp_safe(k
);
1730 r
= log_error_errno(fd
, "Failed to open %s: %m", k
);
1734 /* Enable secure remove, exclusion from dump, synchronous
1735 * writing and in-place updating */
1736 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
);
1738 log_warning_errno(r
, "Failed to set file attributes: %m");
1741 memcpy(h
.signature
, "KSHHRHLP", 8);
1742 h
.machine_id
= machine
;
1744 h
.header_size
= htole64(sizeof(h
));
1745 h
.start_usec
= htole64(n
* arg_interval
);
1746 h
.interval_usec
= htole64(arg_interval
);
1747 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1748 h
.fsprg_state_size
= htole64(state_size
);
1750 r
= loop_write(fd
, &h
, sizeof(h
), false);
1752 log_error_errno(r
, "Failed to write header: %m");
1756 r
= loop_write(fd
, state
, state_size
, false);
1758 log_error_errno(r
, "Failed to write state: %m");
1762 if (link(k
, p
) < 0) {
1763 r
= log_error_errno(errno
, "Failed to link file: %m");
1770 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
1771 "the following local file. This key file is automatically updated when the\n"
1772 "sealing key is advanced. It should not be used on multiple hosts.\n"
1776 "Please write down the following %ssecret verification key%s. It should be stored\n"
1777 "at a safe location and should not be saved locally on disk.\n"
1779 ansi_highlight(), ansi_normal(),
1781 ansi_highlight(), ansi_normal(),
1782 ansi_highlight_red());
1785 for (i
= 0; i
< seed_size
; i
++) {
1786 if (i
> 0 && i
% 3 == 0)
1788 printf("%02x", ((uint8_t*) seed
)[i
]);
1791 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1794 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1798 "The sealing key is automatically changed every %s.\n",
1800 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1802 hn
= gethostname_malloc();
1805 hostname_cleanup(hn
);
1806 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1808 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1811 /* If this is not an UTF-8 system don't print any QR codes */
1812 if (is_locale_utf8()) {
1813 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1814 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1834 log_error("Forward-secure sealing not available.");
1839 static int verify(sd_journal
*j
) {
1846 log_show_color(true);
1848 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1850 usec_t first
= 0, validated
= 0, last
= 0;
1853 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1854 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1857 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1859 /* If the key was invalid give up right-away. */
1862 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1865 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1866 log_info("PASS: %s", f
->path
);
1868 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1869 if (validated
> 0) {
1870 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1871 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1872 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1873 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1874 } else if (last
> 0)
1875 log_info("=> No sealing yet, %s of entries not sealed.",
1876 format_timespan(c
, sizeof(c
), last
- first
, 0));
1878 log_info("=> No sealing yet, no entries in file.");
1886 static int flush_to_var(void) {
1887 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1888 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1889 _cleanup_close_
int watch_fd
= -1;
1893 log_error("--flush is not supported in conjunction with --machine=.");
1898 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1901 /* OK, let's actually do the full logic, send SIGUSR1 to the
1902 * daemon and set up inotify to wait for the flushed file to appear */
1903 r
= bus_connect_system_systemd(&bus
);
1905 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1907 r
= sd_bus_call_method(
1909 "org.freedesktop.systemd1",
1910 "/org/freedesktop/systemd1",
1911 "org.freedesktop.systemd1.Manager",
1915 "ssi", "systemd-journald.service", "main", SIGUSR1
);
1917 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
1919 mkdir_p("/run/systemd/journal", 0755);
1921 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1923 return log_error_errno(errno
, "Failed to create inotify watch: %m");
1925 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_CREATE
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
1927 return log_error_errno(errno
, "Failed to watch journal directory: %m");
1930 if (access("/run/systemd/journal/flushed", F_OK
) >= 0)
1933 if (errno
!= ENOENT
)
1934 return log_error_errno(errno
, "Failed to check for existence of /run/systemd/journal/flushed: %m");
1936 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
1938 return log_error_errno(r
, "Failed to wait for event: %m");
1940 r
= flush_fd(watch_fd
);
1942 return log_error_errno(r
, "Failed to flush inotify events: %m");
1948 static int send_signal_and_wait(int sig
, const char *watch_path
) {
1949 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1950 _cleanup_close_
int watch_fd
= -1;
1955 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
1959 start
= now(CLOCK_MONOTONIC
);
1961 /* This call sends the specified signal to journald, and waits
1962 * for acknowledgment by watching the mtime of the specified
1963 * flag file. This is used to trigger syncing or rotation and
1964 * then wait for the operation to complete. */
1969 /* See if a sync happened by now. */
1970 r
= read_timestamp_file(watch_path
, &tstamp
);
1971 if (r
< 0 && r
!= -ENOENT
)
1972 return log_error_errno(errno
, "Failed to read %s: %m", watch_path
);
1973 if (r
>= 0 && tstamp
>= start
)
1976 /* Let's ask for a sync, but only once. */
1978 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1980 r
= bus_connect_system_systemd(&bus
);
1982 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
1984 r
= sd_bus_call_method(
1986 "org.freedesktop.systemd1",
1987 "/org/freedesktop/systemd1",
1988 "org.freedesktop.systemd1.Manager",
1992 "ssi", "systemd-journald.service", "main", sig
);
1994 return log_error_errno(r
, "Failed to kill journal service: %s", bus_error_message(&error
, r
));
1999 /* Let's install the inotify watch, if we didn't do that yet. */
2002 mkdir_p("/run/systemd/journal", 0755);
2004 watch_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
2006 return log_error_errno(errno
, "Failed to create inotify watch: %m");
2008 r
= inotify_add_watch(watch_fd
, "/run/systemd/journal", IN_MOVED_TO
|IN_DONT_FOLLOW
|IN_ONLYDIR
);
2010 return log_error_errno(errno
, "Failed to watch journal directory: %m");
2012 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
2016 /* OK, all preparatory steps done, let's wait until
2017 * inotify reports an event. */
2019 r
= fd_wait_for_event(watch_fd
, POLLIN
, USEC_INFINITY
);
2021 return log_error_errno(r
, "Failed to wait for event: %m");
2023 r
= flush_fd(watch_fd
);
2025 return log_error_errno(r
, "Failed to flush inotify events: %m");
2031 static int rotate(void) {
2032 return send_signal_and_wait(SIGUSR2
, "/run/systemd/journal/rotated");
2035 static int sync_journal(void) {
2036 return send_signal_and_wait(SIGRTMIN
+1, "/run/systemd/journal/synced");
2039 int main(int argc
, char *argv
[]) {
2041 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2042 bool need_seek
= false;
2043 sd_id128_t previous_boot_id
;
2044 bool previous_boot_id_valid
= false, first_line
= true;
2046 bool ellipsized
= false;
2048 setlocale(LC_ALL
, "");
2049 log_parse_environment();
2052 r
= parse_argv(argc
, argv
);
2056 signal(SIGWINCH
, columns_lines_cache_reset
);
2059 /* Increase max number of open files to 16K if we can, we
2060 * might needs this when browsing journal files, which might
2061 * be split up into many files. */
2062 setrlimit_closest(RLIMIT_NOFILE
, &RLIMIT_MAKE_CONST(16384));
2064 switch (arg_action
) {
2066 case ACTION_NEW_ID128
:
2067 r
= generate_new_id128();
2070 case ACTION_SETUP_KEYS
:
2074 case ACTION_LIST_CATALOG
:
2075 case ACTION_DUMP_CATALOG
:
2076 case ACTION_UPDATE_CATALOG
: {
2077 _cleanup_free_
char *database
;
2079 database
= path_join(arg_root
, CATALOG_DATABASE
, NULL
);
2085 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2086 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2088 log_error_errno(r
, "Failed to list catalog: %m");
2090 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2092 pager_open(arg_no_pager
, arg_pager_end
);
2095 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2097 r
= catalog_list(stdout
, database
, oneline
);
2099 log_error_errno(r
, "Failed to list catalog: %m");
2118 case ACTION_PRINT_HEADER
:
2120 case ACTION_DISK_USAGE
:
2121 case ACTION_LIST_BOOTS
:
2123 case ACTION_LIST_FIELDS
:
2124 case ACTION_LIST_FIELD_NAMES
:
2125 /* These ones require access to the journal files, continue below. */
2129 assert_not_reached("Unknown action");
2133 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2135 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2136 else if (arg_file_stdin
) {
2137 int ifd
= STDIN_FILENO
;
2138 r
= sd_journal_open_files_fd(&j
, &ifd
, 1, 0);
2139 } else if (arg_file
)
2140 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2141 else if (arg_machine
) {
2142 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2143 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2144 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2147 if (geteuid() != 0) {
2148 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2149 * the container, thus we need root privileges to override them. */
2150 log_error("Using the --machine= switch requires root privileges.");
2155 r
= sd_bus_open_system(&bus
);
2157 log_error_errno(r
, "Failed to open system bus: %m");
2161 r
= sd_bus_call_method(
2163 "org.freedesktop.machine1",
2164 "/org/freedesktop/machine1",
2165 "org.freedesktop.machine1.Manager",
2166 "OpenMachineRootDirectory",
2171 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2175 r
= sd_bus_message_read(reply
, "h", &fd
);
2177 bus_log_parse_error(r
);
2181 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2183 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2187 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2191 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
2193 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2197 r
= journal_access_check_and_warn(j
, arg_quiet
);
2201 switch (arg_action
) {
2203 case ACTION_NEW_ID128
:
2204 case ACTION_SETUP_KEYS
:
2205 case ACTION_LIST_CATALOG
:
2206 case ACTION_DUMP_CATALOG
:
2207 case ACTION_UPDATE_CATALOG
:
2211 assert_not_reached("Unexpected action.");
2213 case ACTION_PRINT_HEADER
:
2214 journal_print_header(j
);
2222 case ACTION_DISK_USAGE
: {
2224 char sbytes
[FORMAT_BYTES_MAX
];
2226 r
= sd_journal_get_usage(j
, &bytes
);
2230 printf("Archived and active journals take up %s in the file system.\n",
2231 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2235 case ACTION_LIST_BOOTS
:
2239 case ACTION_VACUUM
: {
2243 HASHMAP_FOREACH(d
, j
->directories_by_path
, i
) {
2249 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2251 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2259 case ACTION_LIST_FIELD_NAMES
: {
2262 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2263 printf("%s\n", field
);
2272 case ACTION_LIST_FIELDS
:
2276 assert_not_reached("Unknown action");
2279 if (arg_boot_offset
!= 0 &&
2280 sd_journal_has_runtime_files(j
) > 0 &&
2281 sd_journal_has_persistent_files(j
) == 0) {
2282 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2286 /* add_boot() must be called first!
2287 * It may need to seek the journal to find parent boot IDs. */
2298 log_error_errno(r
, "Failed to add filter for units: %m");
2302 r
= add_syslog_identifier(j
);
2304 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2308 r
= add_priorities(j
);
2312 r
= add_matches(j
, argv
+ optind
);
2316 if (DEBUG_LOGGING
) {
2317 _cleanup_free_
char *filter
;
2319 filter
= journal_make_match_string(j
);
2323 log_debug("Journal filter: %s", filter
);
2326 if (arg_action
== ACTION_LIST_FIELDS
) {
2332 r
= sd_journal_set_data_threshold(j
, 0);
2334 log_error_errno(r
, "Failed to unset data size threshold: %m");
2338 r
= sd_journal_query_unique(j
, arg_field
);
2340 log_error_errno(r
, "Failed to query unique data objects: %m");
2344 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2347 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2350 eq
= memchr(data
, '=', size
);
2352 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2354 printf("%.*s\n", (int) size
, (const char*) data
);
2363 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2365 r
= sd_journal_get_fd(j
);
2366 if (r
== -EMEDIUMTYPE
) {
2367 log_error_errno(r
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2371 log_error_errno(r
, "Failed to get journal fd: %m");
2376 if (arg_cursor
|| arg_after_cursor
) {
2377 r
= sd_journal_seek_cursor(j
, arg_cursor
?: arg_after_cursor
);
2379 log_error_errno(r
, "Failed to seek to cursor: %m");
2384 r
= sd_journal_next_skip(j
, 1 + !!arg_after_cursor
);
2386 r
= sd_journal_previous_skip(j
, 1 + !!arg_after_cursor
);
2388 if (arg_after_cursor
&& r
< 2) {
2389 /* We couldn't find the next entry after the cursor. */
2396 } else if (arg_since_set
&& !arg_reverse
) {
2397 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2399 log_error_errno(r
, "Failed to seek to date: %m");
2402 r
= sd_journal_next(j
);
2404 } else if (arg_until_set
&& arg_reverse
) {
2405 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2407 log_error_errno(r
, "Failed to seek to date: %m");
2410 r
= sd_journal_previous(j
);
2412 } else if (arg_lines
>= 0) {
2413 r
= sd_journal_seek_tail(j
);
2415 log_error_errno(r
, "Failed to seek to tail: %m");
2419 r
= sd_journal_previous_skip(j
, arg_lines
);
2421 } else if (arg_reverse
) {
2422 r
= sd_journal_seek_tail(j
);
2424 log_error_errno(r
, "Failed to seek to tail: %m");
2428 r
= sd_journal_previous(j
);
2431 r
= sd_journal_seek_head(j
);
2433 log_error_errno(r
, "Failed to seek to head: %m");
2437 r
= sd_journal_next(j
);
2441 log_error_errno(r
, "Failed to iterate through journal: %m");
2448 pager_open(arg_no_pager
, arg_pager_end
);
2450 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2452 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2454 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2456 log_error_errno(r
, "Failed to get cutoff: %m");
2462 printf("-- Logs begin at %s. --\n",
2463 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2465 printf("-- Logs begin at %s, end at %s. --\n",
2466 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2467 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2472 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2477 r
= sd_journal_next(j
);
2479 r
= sd_journal_previous(j
);
2481 log_error_errno(r
, "Failed to iterate through journal: %m");
2488 if (arg_until_set
&& !arg_reverse
) {
2491 r
= sd_journal_get_realtime_usec(j
, &usec
);
2493 log_error_errno(r
, "Failed to determine timestamp: %m");
2496 if (usec
> arg_until
)
2500 if (arg_since_set
&& arg_reverse
) {
2503 r
= sd_journal_get_realtime_usec(j
, &usec
);
2505 log_error_errno(r
, "Failed to determine timestamp: %m");
2508 if (usec
< arg_since
)
2512 if (!arg_merge
&& !arg_quiet
) {
2515 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2517 if (previous_boot_id_valid
&&
2518 !sd_id128_equal(boot_id
, previous_boot_id
))
2519 printf("%s-- Reboot --%s\n",
2520 ansi_highlight(), ansi_normal());
2522 previous_boot_id
= boot_id
;
2523 previous_boot_id_valid
= true;
2529 _cleanup_(pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2530 const void *message
;
2533 md
= pcre2_match_data_create(1, NULL
);
2537 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2544 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2548 assert_se(message
= startswith(message
, "MESSAGE="));
2550 r
= pcre2_match(arg_pattern
,
2552 len
- strlen("MESSAGE="),
2553 0, /* start at offset 0 in the subject */
2554 0, /* default options */
2557 if (r
== PCRE2_ERROR_NOMATCH
) {
2562 unsigned char buf
[LINE_MAX
];
2565 r2
= pcre2_get_error_message(r
, buf
, sizeof buf
);
2566 log_error("Pattern matching failed: %s",
2567 r2
< 0 ? "unknown error" : (char*) buf
);
2575 arg_all
* OUTPUT_SHOW_ALL
|
2576 arg_full
* OUTPUT_FULL_WIDTH
|
2577 colors_enabled() * OUTPUT_COLOR
|
2578 arg_catalog
* OUTPUT_CATALOG
|
2579 arg_utc
* OUTPUT_UTC
|
2580 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2582 r
= output_journal(stdout
, j
, arg_output
, 0, flags
, arg_output_fields
, &ellipsized
);
2584 if (r
== -EADDRNOTAVAIL
)
2586 else if (r
< 0 || ferror(stdout
))
2593 if (n_shown
== 0 && !arg_quiet
)
2594 printf("-- No entries --\n");
2596 if (arg_show_cursor
) {
2597 _cleanup_free_
char *cursor
= NULL
;
2599 r
= sd_journal_get_cursor(j
, &cursor
);
2600 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2601 log_error_errno(r
, "Failed to get cursor: %m");
2603 printf("-- cursor: %s\n", cursor
);
2610 r
= sd_journal_wait(j
, (uint64_t) -1);
2612 log_error_errno(r
, "Couldn't wait for journal event: %m");
2623 strv_free(arg_file
);
2625 strv_free(arg_syslog_identifier
);
2626 strv_free(arg_system_units
);
2627 strv_free(arg_user_units
);
2628 strv_free(arg_output_fields
);
2631 free(arg_verify_key
);
2635 pcre2_code_free(arg_pattern
);
2638 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;