1 /* SPDX-License-Identifier: LGPL-2.1+ */
13 #include <sys/inotify.h>
18 # define PCRE2_CODE_UNIT_WIDTH 8
23 #include "sd-device.h"
24 #include "sd-journal.h"
27 #include "alloc-util.h"
28 #include "bus-error.h"
31 #include "chattr-util.h"
33 #include "device-private.h"
34 #include "dissect-image.h"
37 #include "format-util.h"
40 #include "glob-util.h"
41 #include "hostname-util.h"
42 #include "id128-print.h"
44 #include "journal-def.h"
45 #include "journal-internal.h"
46 #include "journal-qrcode.h"
47 #include "journal-util.h"
48 #include "journal-vacuum.h"
49 #include "journal-verify.h"
50 #include "locale-util.h"
52 #include "logs-show.h"
53 #include "memory-util.h"
55 #include "mount-util.h"
56 #include "mountpoint-util.h"
57 #include "nulstr-util.h"
59 #include "parse-util.h"
60 #include "path-util.h"
61 #include "pcre2-dlopen.h"
62 #include "pretty-print.h"
63 #include "random-util.h"
64 #include "rlimit-util.h"
67 #include "stdio-util.h"
68 #include "string-table.h"
70 #include "syslog-util.h"
71 #include "terminal-util.h"
72 #include "tmpfile-util.h"
73 #include "unit-name.h"
74 #include "user-util.h"
77 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
78 #define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
81 /* Special values for arg_lines */
82 ARG_LINES_DEFAULT
= -2,
86 static OutputMode arg_output
= OUTPUT_SHORT
;
87 static bool arg_utc
= false;
88 static bool arg_follow
= false;
89 static bool arg_full
= true;
90 static bool arg_all
= false;
91 static PagerFlags arg_pager_flags
= 0;
92 static int arg_lines
= ARG_LINES_DEFAULT
;
93 static bool arg_no_tail
= false;
94 static bool arg_quiet
= false;
95 static bool arg_merge
= false;
96 static bool arg_boot
= false;
97 static sd_id128_t arg_boot_id
= {};
98 static int arg_boot_offset
= 0;
99 static bool arg_dmesg
= false;
100 static bool arg_no_hostname
= false;
101 static const char *arg_cursor
= NULL
;
102 static const char *arg_cursor_file
= NULL
;
103 static const char *arg_after_cursor
= NULL
;
104 static bool arg_show_cursor
= false;
105 static const char *arg_directory
= NULL
;
106 static char **arg_file
= NULL
;
107 static bool arg_file_stdin
= false;
108 static int arg_priorities
= 0xFF;
109 static Set
*arg_facilities
= NULL
;
110 static char *arg_verify_key
= NULL
;
112 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
113 static bool arg_force
= false;
115 static usec_t arg_since
, arg_until
;
116 static bool arg_since_set
= false, arg_until_set
= false;
117 static char **arg_syslog_identifier
= NULL
;
118 static char **arg_system_units
= NULL
;
119 static char **arg_user_units
= NULL
;
120 static const char *arg_field
= NULL
;
121 static bool arg_catalog
= false;
122 static bool arg_reverse
= false;
123 static int arg_journal_type
= 0;
124 static int arg_namespace_flags
= 0;
125 static char *arg_root
= NULL
;
126 static char *arg_image
= NULL
;
127 static const char *arg_machine
= NULL
;
128 static const char *arg_namespace
= NULL
;
129 static uint64_t arg_vacuum_size
= 0;
130 static uint64_t arg_vacuum_n_files
= 0;
131 static usec_t arg_vacuum_time
= 0;
132 static char **arg_output_fields
= NULL
;
134 static const char *arg_pattern
= NULL
;
135 static pcre2_code
*arg_compiled_pattern
= NULL
;
136 static int arg_case_sensitive
= -1; /* -1 means be smart */
148 ACTION_UPDATE_CATALOG
,
151 ACTION_RELINQUISH_VAR
,
155 ACTION_ROTATE_AND_VACUUM
,
157 ACTION_LIST_FIELD_NAMES
,
158 } arg_action
= ACTION_SHOW
;
160 typedef struct BootId
{
164 LIST_FIELDS(struct BootId
, boot_list
);
168 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data
*, sym_pcre2_match_data_free
);
169 DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code
*, sym_pcre2_code_free
);
171 static int pattern_compile(const char *pattern
, unsigned flags
, pcre2_code
**out
) {
173 PCRE2_SIZE erroroffset
;
176 p
= sym_pcre2_compile((PCRE2_SPTR8
) pattern
,
177 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
179 unsigned char buf
[LINE_MAX
];
181 r
= sym_pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
183 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
184 "Bad pattern \"%s\": %s", pattern
,
185 r
< 0 ? "unknown error" : (char *)buf
);
193 static int add_matches_for_device(sd_journal
*j
, const char *devpath
) {
194 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
202 if (!path_startswith(devpath
, "/dev/")) {
203 log_error("Devpath does not start with /dev/");
207 if (stat(devpath
, &st
) < 0)
208 return log_error_errno(errno
, "Couldn't stat file: %m");
210 r
= device_new_from_stat_rdev(&device
, &st
);
212 return log_error_errno(r
, "Failed to get device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
214 for (d
= device
; d
; ) {
215 _cleanup_free_
char *match
= NULL
;
216 const char *subsys
, *sysname
, *devnode
;
219 r
= sd_device_get_subsystem(d
, &subsys
);
223 r
= sd_device_get_sysname(d
, &sysname
);
227 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
231 r
= sd_journal_add_match(j
, match
, 0);
233 return log_error_errno(r
, "Failed to add match: %m");
235 if (sd_device_get_devname(d
, &devnode
) >= 0) {
236 _cleanup_free_
char *match1
= NULL
;
238 r
= stat(devnode
, &st
);
240 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
242 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
246 r
= sd_journal_add_match(j
, match1
, 0);
248 return log_error_errno(r
, "Failed to add match: %m");
252 if (sd_device_get_parent(d
, &parent
) < 0)
258 r
= add_match_this_boot(j
, arg_machine
);
260 return log_error_errno(r
, "Failed to add match for the current boot: %m");
265 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
268 return format_timestamp_style(buf
, l
, t
, TIMESTAMP_UTC
);
270 return format_timestamp(buf
, l
, t
);
273 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
274 sd_id128_t id
= SD_ID128_NULL
;
277 if (streq(x
, "all")) {
278 *boot_id
= SD_ID128_NULL
;
281 } else 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 int help_facilities(void) {
314 puts("Available facilities:");
316 for (int i
= 0; i
< LOG_NFACILITIES
; i
++) {
317 _cleanup_free_
char *t
= NULL
;
319 if (log_facility_unshifted_to_string_alloc(i
, &t
))
327 static int help(void) {
328 _cleanup_free_
char *link
= NULL
;
331 (void) pager_open(arg_pager_flags
);
333 r
= terminal_urlify_man("journalctl", "1", &link
);
337 printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
338 "%5$sQuery the journal.%6$s\n\n"
340 " --system Show the system journal\n"
341 " --user Show the user journal for the current user\n"
342 " -M --machine=CONTAINER Operate on local container\n"
343 " -S --since=DATE Show entries not older than the specified date\n"
344 " -U --until=DATE Show entries not newer than the specified date\n"
345 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
346 " --after-cursor=CURSOR Show entries after the specified cursor\n"
347 " --show-cursor Print the cursor after all the entries\n"
348 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
349 " -b --boot[=ID] Show current boot or the specified boot\n"
350 " --list-boots Show terse information about recorded boots\n"
351 " -k --dmesg Show kernel message log from the current boot\n"
352 " -u --unit=UNIT Show logs from the specified unit\n"
353 " --user-unit=UNIT Show logs from the specified user unit\n"
354 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
355 " -p --priority=RANGE Show entries with the specified priority\n"
356 " --facility=FACILITY... Show entries with the specified facilities\n"
357 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
358 " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
359 " -e --pager-end Immediately jump to the end in the pager\n"
360 " -f --follow Follow the journal\n"
361 " -n --lines[=INTEGER] Number of journal entries to show\n"
362 " --no-tail Show all lines, even in follow mode\n"
363 " -r --reverse Show the newest entries first\n"
364 " -o --output=STRING Change journal output mode (short, short-precise,\n"
365 " short-iso, short-iso-precise, short-full,\n"
366 " short-monotonic, short-unix, verbose, export,\n"
367 " json, json-pretty, json-sse, json-seq, cat,\n"
369 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
370 " --utc Express time in Coordinated Universal Time (UTC)\n"
371 " -x --catalog Add message explanations where available\n"
372 " --no-full Ellipsize fields\n"
373 " -a --all Show all fields, including long and unprintable\n"
374 " -q --quiet Do not show info messages and privilege warning\n"
375 " --no-pager Do not pipe output into a pager\n"
376 " --no-hostname Suppress output of hostname field\n"
377 " -m --merge Show entries from all available journals\n"
378 " -D --directory=PATH Show journal files from directory\n"
379 " --file=PATH Show journal file\n"
380 " --root=ROOT Operate on files below a root directory\n"
381 " --image=IMAGE Operate on files in filesystem image\n"
382 " --namespace=NAMESPACE Show journal data from specified namespace\n"
383 " --interval=TIME Time interval for changing the FSS sealing key\n"
384 " --verify-key=KEY Specify FSS verification key\n"
385 " --force Override of the FSS key pair with --setup-keys\n"
386 "\n%3$sCommands:%4$s\n"
387 " -h --help Show this help text\n"
388 " --version Show package version\n"
389 " -N --fields List all field names currently used\n"
390 " -F --field=FIELD List all values that a specified field takes\n"
391 " --disk-usage Show total disk usage of all journal files\n"
392 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
393 " --vacuum-files=INT Leave only the specified number of journal files\n"
394 " --vacuum-time=TIME Remove journal files older than specified time\n"
395 " --verify Verify journal file consistency\n"
396 " --sync Synchronize unwritten journal messages to disk\n"
397 " --relinquish-var Stop logging to disk, log to temporary file system\n"
398 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
399 " --flush Flush all journal data from /run into /var\n"
400 " --rotate Request immediate rotation of the journal files\n"
401 " --header Show journal header information\n"
402 " --list-catalog Show all message IDs in the catalog\n"
403 " --dump-catalog Show entries in the message catalog\n"
404 " --update-catalog Update the message catalog database\n"
405 " --setup-keys Generate a new FSS key pair\n"
406 "\nSee the %2$s for details.\n"
407 , program_invocation_short_name
409 , ansi_underline(), ansi_normal()
410 , ansi_highlight(), ansi_normal()
416 static int parse_argv(int argc
, char *argv
[]) {
451 ARG_SMART_RELINQUISH_VAR
,
461 static const struct option options
[] = {
462 { "help", no_argument
, NULL
, 'h' },
463 { "version" , no_argument
, NULL
, ARG_VERSION
},
464 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
465 { "pager-end", no_argument
, NULL
, 'e' },
466 { "follow", no_argument
, NULL
, 'f' },
467 { "force", no_argument
, NULL
, ARG_FORCE
},
468 { "output", required_argument
, NULL
, 'o' },
469 { "all", no_argument
, NULL
, 'a' },
470 { "full", no_argument
, NULL
, 'l' },
471 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
472 { "lines", optional_argument
, NULL
, 'n' },
473 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
474 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
475 { "quiet", no_argument
, NULL
, 'q' },
476 { "merge", no_argument
, NULL
, 'm' },
477 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
478 { "boot", optional_argument
, NULL
, 'b' },
479 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
480 { "dmesg", no_argument
, NULL
, 'k' },
481 { "system", no_argument
, NULL
, ARG_SYSTEM
},
482 { "user", no_argument
, NULL
, ARG_USER
},
483 { "directory", required_argument
, NULL
, 'D' },
484 { "file", required_argument
, NULL
, ARG_FILE
},
485 { "root", required_argument
, NULL
, ARG_ROOT
},
486 { "image", required_argument
, NULL
, ARG_IMAGE
},
487 { "header", no_argument
, NULL
, ARG_HEADER
},
488 { "identifier", required_argument
, NULL
, 't' },
489 { "priority", required_argument
, NULL
, 'p' },
490 { "facility", required_argument
, NULL
, ARG_FACILITY
},
491 { "grep", required_argument
, NULL
, 'g' },
492 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
493 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
494 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
495 { "verify", no_argument
, NULL
, ARG_VERIFY
},
496 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
497 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
498 { "cursor", required_argument
, NULL
, 'c' },
499 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
500 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
501 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
502 { "since", required_argument
, NULL
, 'S' },
503 { "until", required_argument
, NULL
, 'U' },
504 { "unit", required_argument
, NULL
, 'u' },
505 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
506 { "field", required_argument
, NULL
, 'F' },
507 { "fields", no_argument
, NULL
, 'N' },
508 { "catalog", no_argument
, NULL
, 'x' },
509 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
510 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
511 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
512 { "reverse", no_argument
, NULL
, 'r' },
513 { "machine", required_argument
, NULL
, 'M' },
514 { "utc", no_argument
, NULL
, ARG_UTC
},
515 { "flush", no_argument
, NULL
, ARG_FLUSH
},
516 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
517 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
518 { "sync", no_argument
, NULL
, ARG_SYNC
},
519 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
520 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
521 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
522 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
523 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
524 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
525 { "namespace", required_argument
, NULL
, ARG_NAMESPACE
},
534 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
545 arg_pager_flags
|= PAGER_DISABLE
;
549 arg_pager_flags
|= PAGER_JUMP_TO_END
;
551 if (arg_lines
== ARG_LINES_DEFAULT
)
561 if (streq(optarg
, "help")) {
562 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
566 arg_output
= output_mode_from_string(optarg
);
568 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unknown output format '%s'.", optarg
);
570 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
589 if (streq(optarg
, "all"))
590 arg_lines
= ARG_LINES_ALL
;
592 r
= safe_atoi(optarg
, &arg_lines
);
593 if (r
< 0 || arg_lines
< 0)
594 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse lines '%s'", optarg
);
599 /* Hmm, no argument? Maybe the next
600 * word on the command line is
601 * supposed to be the argument? Let's
602 * see if there is one, and is
606 if (streq(argv
[optind
], "all")) {
607 arg_lines
= ARG_LINES_ALL
;
609 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
623 arg_action
= ACTION_NEW_ID128
;
636 arg_boot_id
= SD_ID128_NULL
;
642 arg_boot_id
= SD_ID128_NULL
;
646 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
648 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
652 /* Hmm, no argument? Maybe the next
653 * word on the command line is
654 * supposed to be the argument? Let's
655 * see if there is one and is parsable
656 * as a boot descriptor... */
657 } else if (optind
< argc
) {
658 r
= parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
667 arg_action
= ACTION_LIST_BOOTS
;
671 arg_boot
= arg_dmesg
= true;
675 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
679 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
683 arg_machine
= optarg
;
687 if (streq(optarg
, "*")) {
688 arg_namespace_flags
= SD_JOURNAL_ALL_NAMESPACES
;
689 arg_namespace
= NULL
;
690 } else if (startswith(optarg
, "+")) {
691 arg_namespace_flags
= SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
;
692 arg_namespace
= optarg
+ 1;
693 } else if (isempty(optarg
)) {
694 arg_namespace_flags
= 0;
695 arg_namespace
= NULL
;
697 arg_namespace_flags
= 0;
698 arg_namespace
= optarg
;
704 arg_directory
= optarg
;
708 if (streq(optarg
, "-"))
709 /* An undocumented feature: we can read journal files from STDIN. We don't document
710 * this though, since after all we only support this for mmap-able, seekable files, and
711 * not for example pipes which are probably the primary usecase for reading things from
712 * STDIN. To avoid confusion we hence don't document this feature. */
713 arg_file_stdin
= true;
715 r
= glob_extend(&arg_file
, optarg
, GLOB_NOCHECK
);
717 return log_error_errno(r
, "Failed to add paths: %m");
722 r
= parse_path_argument_and_warn(optarg
, /* suppress_root= */ true, &arg_root
);
728 r
= parse_path_argument_and_warn(optarg
, /* suppress_root= */ false, &arg_image
);
737 case ARG_CURSOR_FILE
:
738 arg_cursor_file
= optarg
;
741 case ARG_AFTER_CURSOR
:
742 arg_after_cursor
= optarg
;
745 case ARG_SHOW_CURSOR
:
746 arg_show_cursor
= true;
750 arg_action
= ACTION_PRINT_HEADER
;
754 arg_action
= ACTION_VERIFY
;
758 arg_action
= ACTION_DISK_USAGE
;
761 case ARG_VACUUM_SIZE
:
762 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
764 return log_error_errno(r
, "Failed to parse vacuum size: %s", optarg
);
766 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
769 case ARG_VACUUM_FILES
:
770 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
772 return log_error_errno(r
, "Failed to parse vacuum files: %s", optarg
);
774 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
777 case ARG_VACUUM_TIME
:
778 r
= parse_sec(optarg
, &arg_vacuum_time
);
780 return log_error_errno(r
, "Failed to parse vacuum time: %s", optarg
);
782 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
791 arg_action
= ACTION_SETUP_KEYS
;
795 r
= free_and_strdup(&arg_verify_key
, optarg
);
798 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
799 * in ps or htop output. */
800 memset(optarg
, 'x', strlen(optarg
));
802 arg_action
= ACTION_VERIFY
;
807 r
= parse_sec(optarg
, &arg_interval
);
808 if (r
< 0 || arg_interval
<= 0)
809 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
810 "Failed to parse sealing key change interval: %s", optarg
);
817 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
818 "Compiled without forward-secure sealing support.");
824 dots
= strstr(optarg
, "..");
826 _cleanup_free_
char *a
= NULL
;
830 a
= strndup(optarg
, dots
- optarg
);
834 from
= log_level_from_string(a
);
835 to
= log_level_from_string(dots
+ 2);
837 if (from
< 0 || to
< 0)
838 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
839 "Failed to parse log level range %s", optarg
);
844 for (i
= from
; i
<= to
; i
++)
845 arg_priorities
|= 1 << i
;
847 for (i
= to
; i
<= from
; i
++)
848 arg_priorities
|= 1 << i
;
854 p
= log_level_from_string(optarg
);
856 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
857 "Unknown log level %s", optarg
);
861 for (i
= 0; i
<= p
; i
++)
862 arg_priorities
|= 1 << i
;
872 _cleanup_free_
char *fac
= NULL
;
875 r
= extract_first_word(&p
, &fac
, ",", 0);
877 return log_error_errno(r
, "Failed to parse facilities: %s", optarg
);
881 if (streq(fac
, "help")) {
886 num
= log_facility_unshifted_from_string(fac
);
888 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
889 "Bad --facility= argument \"%s\".", fac
);
891 if (set_ensure_put(&arg_facilities
, NULL
, INT_TO_PTR(num
)) < 0)
900 arg_pattern
= optarg
;
903 case ARG_CASE_SENSITIVE
:
905 r
= parse_boolean(optarg
);
907 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
908 arg_case_sensitive
= r
;
910 arg_case_sensitive
= true;
915 case ARG_CASE_SENSITIVE
:
916 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Compiled without pattern matching support");
920 r
= parse_timestamp(optarg
, &arg_since
);
922 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
923 "Failed to parse timestamp: %s", optarg
);
924 arg_since_set
= true;
928 r
= parse_timestamp(optarg
, &arg_until
);
930 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
931 "Failed to parse timestamp: %s", optarg
);
932 arg_until_set
= true;
936 r
= strv_extend(&arg_syslog_identifier
, optarg
);
942 r
= strv_extend(&arg_system_units
, optarg
);
948 r
= strv_extend(&arg_user_units
, optarg
);
954 arg_action
= ACTION_LIST_FIELDS
;
959 arg_action
= ACTION_LIST_FIELD_NAMES
;
962 case ARG_NO_HOSTNAME
:
963 arg_no_hostname
= true;
970 case ARG_LIST_CATALOG
:
971 arg_action
= ACTION_LIST_CATALOG
;
974 case ARG_DUMP_CATALOG
:
975 arg_action
= ACTION_DUMP_CATALOG
;
978 case ARG_UPDATE_CATALOG
:
979 arg_action
= ACTION_UPDATE_CATALOG
;
991 arg_action
= ACTION_FLUSH
;
994 case ARG_SMART_RELINQUISH_VAR
: {
995 int root_mnt_id
, log_mnt_id
;
997 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
998 * if it's on the same mount as the root file system there's no point in
999 * relinquishing access and we can leave journald write to it until the very last
1002 r
= path_get_mnt_id("/", &root_mnt_id
);
1004 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
1006 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
1008 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
1009 else if (root_mnt_id
== log_mnt_id
) {
1010 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
1013 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
1019 case ARG_RELINQUISH_VAR
:
1020 arg_action
= ACTION_RELINQUISH_VAR
;
1024 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
1028 arg_action
= ACTION_SYNC
;
1031 case ARG_OUTPUT_FIELDS
: {
1032 _cleanup_strv_free_
char **v
= NULL
;
1034 v
= strv_split(optarg
, ",");
1038 if (!arg_output_fields
)
1039 arg_output_fields
= TAKE_PTR(v
);
1041 r
= strv_extend_strv(&arg_output_fields
, v
, true);
1052 assert_not_reached("Unhandled option");
1055 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
1058 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
+ !!arg_image
> 1) {
1059 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
1063 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
1064 log_error("--since= must be before --until=.");
1068 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
1069 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
1073 if (arg_follow
&& arg_reverse
) {
1074 log_error("Please specify either --reverse= or --follow=, not both.");
1078 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
) {
1079 log_error("Extraneous arguments starting with '%s'", argv
[optind
]);
1083 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
) {
1084 log_error("Using --boot or --list-boots with --merge is not supported.");
1088 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
1089 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1090 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1091 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1092 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
1096 arg_system_units
= strv_free(arg_system_units
);
1107 if (arg_case_sensitive
>= 0)
1108 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
1110 _cleanup_(sym_pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
1112 _cleanup_(sym_pcre2_code_freep
) pcre2_code
*cs
= NULL
;
1114 md
= sym_pcre2_match_data_create(1, NULL
);
1118 r
= pattern_compile("[[:upper:]]", 0, &cs
);
1122 r
= sym_pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
1125 flags
= !has_case
* PCRE2_CASELESS
;
1128 log_debug("Doing case %s matching based on %s",
1129 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
1130 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
1132 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1141 static int add_matches(sd_journal
*j
, char **args
) {
1143 bool have_term
= false;
1147 STRV_FOREACH(i
, args
) {
1150 if (streq(*i
, "+")) {
1153 r
= sd_journal_add_disjunction(j
);
1156 } else if (path_is_absolute(*i
)) {
1157 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1160 r
= chase_symlinks(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
, NULL
);
1162 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1164 if (lstat(p
, &st
) < 0)
1165 return log_error_errno(errno
, "Couldn't stat file: %m");
1167 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1168 if (executable_is_script(p
, &interpreter
) > 0) {
1169 _cleanup_free_
char *comm
;
1171 comm
= strndup(basename(p
), 15);
1175 t
= strjoin("_COMM=", comm
);
1179 /* Append _EXE only if the interpreter is not a link.
1180 Otherwise, it might be outdated often. */
1181 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1182 t2
= strjoin("_EXE=", interpreter
);
1187 t
= strjoin("_EXE=", p
);
1192 r
= sd_journal_add_match(j
, t
, 0);
1195 r
= sd_journal_add_match(j
, t2
, 0);
1197 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1198 r
= add_matches_for_device(j
, p
);
1202 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1203 "File is neither a device node, nor regular file, nor executable: %s",
1208 r
= sd_journal_add_match(j
, *i
, 0);
1213 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1216 if (!strv_isempty(args
) && !have_term
)
1217 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1218 "\"+\" can only be used between terms");
1223 static void boot_id_free_all(BootId
*l
) {
1227 LIST_REMOVE(boot_list
, l
, i
);
1232 static int discover_next_boot(sd_journal
*j
,
1233 sd_id128_t previous_boot_id
,
1237 _cleanup_free_ BootId
*next_boot
= NULL
;
1238 char match
[9+32+1] = "_BOOT_ID=";
1245 /* We expect the journal to be on the last position of a boot
1246 * (in relation to the direction we are going), so that the next
1247 * invocation of sd_journal_next/previous will be from a different
1248 * boot. We then collect any information we desire and then jump
1249 * to the last location of the new boot by using a _BOOT_ID match
1250 * coming from the other journal direction. */
1252 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1253 * we can actually advance to a *different* boot. */
1254 sd_journal_flush_matches(j
);
1258 r
= sd_journal_previous(j
);
1260 r
= sd_journal_next(j
);
1264 return 0; /* End of journal, yay. */
1266 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1270 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1271 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1272 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1273 * complete than the main entry array, and hence might reference an entry that's not actually the last
1274 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1275 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1278 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1280 next_boot
= new0(BootId
, 1);
1284 next_boot
->id
= boot_id
;
1286 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1290 /* Now seek to the last occurrence of this boot ID. */
1291 sd_id128_to_string(next_boot
->id
, match
+ 9);
1292 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1297 r
= sd_journal_seek_head(j
);
1299 r
= sd_journal_seek_tail(j
);
1304 r
= sd_journal_next(j
);
1306 r
= sd_journal_previous(j
);
1310 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA
),
1311 "Whoopsie! We found a boot ID but can't read its last entry."); /* This shouldn't happen. We just came from this very boot ID. */
1313 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1317 *ret
= TAKE_PTR(next_boot
);
1322 static int get_boots(
1325 sd_id128_t
*boot_id
,
1330 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1331 const bool advance_older
= boot_id
&& offset
<= 0;
1332 sd_id128_t previous_boot_id
;
1336 /* Adjust for the asymmetry that offset 0 is
1337 * the last (and current) boot, while 1 is considered the
1338 * (chronological) first boot in the journal. */
1339 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1341 /* Advance to the earliest/latest occurrence of our reference
1342 * boot ID (taking our lookup direction into account), so that
1343 * discover_next_boot() can do its job.
1344 * If no reference is given, the journal head/tail will do,
1345 * they're "virtual" boots after all. */
1346 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1347 char match
[9+32+1] = "_BOOT_ID=";
1349 sd_journal_flush_matches(j
);
1351 sd_id128_to_string(*boot_id
, match
+ 9);
1352 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1357 r
= sd_journal_seek_head(j
); /* seek to oldest */
1359 r
= sd_journal_seek_tail(j
); /* seek to newest */
1364 r
= sd_journal_next(j
); /* read the oldest entry */
1366 r
= sd_journal_previous(j
); /* read the most recently added entry */
1371 else if (offset
== 0) {
1376 /* At this point the read pointer is positioned at the oldest/newest occurrence of the reference boot
1377 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1378 * the following entry, which must then have an older/newer boot ID */
1382 r
= sd_journal_seek_tail(j
); /* seek to newest */
1384 r
= sd_journal_seek_head(j
); /* seek to oldest */
1388 /* No sd_journal_next()/_previous() here.
1390 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1391 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1395 previous_boot_id
= SD_ID128_NULL
;
1397 _cleanup_free_ BootId
*current
= NULL
;
1399 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1401 boot_id_free_all(head
);
1408 previous_boot_id
= current
->id
;
1412 offset
+= advance_older
? 1 : -1;
1417 *boot_id
= current
->id
;
1421 LIST_FOREACH(boot_list
, id
, head
) {
1422 if (sd_id128_equal(id
->id
, current
->id
)) {
1423 /* boot id already stored, something wrong with the journal files */
1424 /* exiting as otherwise this problem would cause forever loop */
1428 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1429 tail
= TAKE_PTR(current
);
1438 sd_journal_flush_matches(j
);
1443 static int list_boots(sd_journal
*j
) {
1445 BootId
*id
, *all_ids
;
1449 count
= get_boots(j
, &all_ids
, NULL
, 0);
1451 return log_error_errno(count
, "Failed to determine boots: %m");
1455 (void) pager_open(arg_pager_flags
);
1457 /* numbers are one less, but we need an extra char for the sign */
1458 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1461 LIST_FOREACH(boot_list
, id
, all_ids
) {
1462 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1464 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1466 SD_ID128_FORMAT_VAL(id
->id
),
1467 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1468 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1472 boot_id_free_all(all_ids
);
1477 static int add_boot(sd_journal
*j
) {
1478 char match
[9+32+1] = "_BOOT_ID=";
1487 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1488 * We can do this only when we logs are coming from the current machine,
1489 * so take the slow path if log location is specified. */
1490 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1491 !arg_directory
&& !arg_file
&& !arg_root
)
1492 return add_match_this_boot(j
, arg_machine
);
1494 boot_id
= arg_boot_id
;
1495 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1498 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror_safe(r
);
1500 if (sd_id128_is_null(arg_boot_id
))
1501 log_error("Data from the specified boot (%+i) is not available: %s",
1502 arg_boot_offset
, reason
);
1504 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1505 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1507 return r
== 0 ? -ENODATA
: r
;
1510 sd_id128_to_string(boot_id
, match
+ 9);
1512 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1514 return log_error_errno(r
, "Failed to add match: %m");
1516 r
= sd_journal_add_conjunction(j
);
1518 return log_error_errno(r
, "Failed to add conjunction: %m");
1523 static int add_dmesg(sd_journal
*j
) {
1530 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1531 STRLEN("_TRANSPORT=kernel"));
1533 return log_error_errno(r
, "Failed to add match: %m");
1535 r
= sd_journal_add_conjunction(j
);
1537 return log_error_errno(r
, "Failed to add conjunction: %m");
1542 static int get_possible_units(
1548 _cleanup_set_free_free_ Set
*found
;
1552 found
= set_new(&string_hash_ops
);
1556 NULSTR_FOREACH(field
, fields
) {
1560 r
= sd_journal_query_unique(j
, field
);
1564 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1565 char **pattern
, *eq
;
1567 _cleanup_free_
char *u
= NULL
;
1569 eq
= memchr(data
, '=', size
);
1571 prefix
= eq
- (char*) data
+ 1;
1575 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1579 STRV_FOREACH(pattern
, patterns
)
1580 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1581 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1583 r
= set_consume(found
, u
);
1585 if (r
< 0 && r
!= -EEXIST
)
1593 *units
= TAKE_PTR(found
);
1598 /* This list is supposed to return the superset of unit names
1599 * possibly matched by rules added with add_matches_for_unit... */
1600 #define SYSTEM_UNITS \
1604 "OBJECT_SYSTEMD_UNIT\0" \
1607 /* ... and add_matches_for_user_unit */
1608 #define USER_UNITS \
1609 "_SYSTEMD_USER_UNIT\0" \
1611 "COREDUMP_USER_UNIT\0" \
1612 "OBJECT_SYSTEMD_USER_UNIT\0" \
1613 "_SYSTEMD_USER_SLICE\0"
1615 static int add_units(sd_journal
*j
) {
1616 _cleanup_strv_free_
char **patterns
= NULL
;
1622 STRV_FOREACH(i
, arg_system_units
) {
1623 _cleanup_free_
char *u
= NULL
;
1625 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1629 if (string_is_glob(u
)) {
1630 r
= strv_push(&patterns
, u
);
1635 r
= add_matches_for_unit(j
, u
);
1638 r
= sd_journal_add_disjunction(j
);
1645 if (!strv_isempty(patterns
)) {
1646 _cleanup_set_free_free_ Set
*units
= NULL
;
1649 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1653 SET_FOREACH(u
, units
) {
1654 r
= add_matches_for_unit(j
, u
);
1657 r
= sd_journal_add_disjunction(j
);
1664 patterns
= strv_free(patterns
);
1666 STRV_FOREACH(i
, arg_user_units
) {
1667 _cleanup_free_
char *u
= NULL
;
1669 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1673 if (string_is_glob(u
)) {
1674 r
= strv_push(&patterns
, u
);
1679 r
= add_matches_for_user_unit(j
, u
, getuid());
1682 r
= sd_journal_add_disjunction(j
);
1689 if (!strv_isempty(patterns
)) {
1690 _cleanup_set_free_free_ Set
*units
= NULL
;
1693 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1697 SET_FOREACH(u
, units
) {
1698 r
= add_matches_for_user_unit(j
, u
, getuid());
1701 r
= sd_journal_add_disjunction(j
);
1708 /* Complain if the user request matches but nothing whatsoever was
1709 * found, since otherwise everything would be matched. */
1710 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1713 r
= sd_journal_add_conjunction(j
);
1720 static int add_priorities(sd_journal
*j
) {
1721 char match
[] = "PRIORITY=0";
1725 if (arg_priorities
== 0xFF)
1728 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1729 if (arg_priorities
& (1 << i
)) {
1730 match
[sizeof(match
)-2] = '0' + i
;
1732 r
= sd_journal_add_match(j
, match
, strlen(match
));
1734 return log_error_errno(r
, "Failed to add match: %m");
1737 r
= sd_journal_add_conjunction(j
);
1739 return log_error_errno(r
, "Failed to add conjunction: %m");
1744 static int add_facilities(sd_journal
*j
) {
1748 SET_FOREACH(p
, arg_facilities
) {
1749 char match
[STRLEN("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
1751 xsprintf(match
, "SYSLOG_FACILITY=%d", PTR_TO_INT(p
));
1753 r
= sd_journal_add_match(j
, match
, strlen(match
));
1755 return log_error_errno(r
, "Failed to add match: %m");
1761 static int add_syslog_identifier(sd_journal
*j
) {
1767 STRV_FOREACH(i
, arg_syslog_identifier
) {
1768 _cleanup_free_
char *u
= NULL
;
1770 u
= strjoin("SYSLOG_IDENTIFIER=", *i
);
1773 r
= sd_journal_add_match(j
, u
, 0);
1776 r
= sd_journal_add_disjunction(j
);
1781 r
= sd_journal_add_conjunction(j
);
1788 static int setup_keys(void) {
1790 size_t mpk_size
, seed_size
, state_size
;
1791 _cleanup_(unlink_and_freep
) char *k
= NULL
;
1792 _cleanup_free_
char *p
= NULL
;
1793 uint8_t *mpk
, *seed
, *state
;
1794 _cleanup_close_
int fd
= -1;
1795 sd_id128_t machine
, boot
;
1800 r
= stat("/var/log/journal", &st
);
1801 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1802 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1804 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1805 log_error("%s is not a directory, must be using persistent logging for FSS.",
1806 "/var/log/journal");
1807 return r
< 0 ? -errno
: -ENOTDIR
;
1810 r
= sd_id128_get_machine(&machine
);
1812 return log_error_errno(r
, "Failed to get machine ID: %m");
1814 r
= sd_id128_get_boot(&boot
);
1816 return log_error_errno(r
, "Failed to get boot ID: %m");
1818 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1819 SD_ID128_FORMAT_VAL(machine
)) < 0)
1824 if (r
< 0 && errno
!= ENOENT
)
1825 return log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1826 } else if (access(p
, F_OK
) >= 0)
1827 return log_error_errno(SYNTHETIC_ERRNO(EEXIST
),
1828 "Sealing key file %s exists already. Use --force to recreate.", p
);
1830 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1831 SD_ID128_FORMAT_VAL(machine
)) < 0)
1834 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1835 mpk
= alloca(mpk_size
);
1837 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1838 seed
= alloca(seed_size
);
1840 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1841 state
= alloca(state_size
);
1843 log_info("Generating seed...");
1844 r
= genuine_random_bytes(seed
, seed_size
, RANDOM_BLOCK
);
1846 return log_error_errno(r
, "Failed to acquire random seed: %m");
1848 log_info("Generating key pair...");
1849 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1851 log_info("Generating sealing key...");
1852 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1854 assert(arg_interval
> 0);
1856 n
= now(CLOCK_REALTIME
);
1860 fd
= mkostemp_safe(k
);
1862 return log_error_errno(fd
, "Failed to open %s: %m", k
);
1864 /* Enable secure remove, exclusion from dump, synchronous writing and in-place updating */
1865 static const unsigned chattr_flags
[] = {
1871 for (size_t j
= 0; j
< ELEMENTSOF(chattr_flags
); j
++) {
1872 r
= chattr_fd(fd
, chattr_flags
[j
], chattr_flags
[j
], NULL
);
1874 log_full_errno(ERRNO_IS_NOT_SUPPORTED(r
) ? LOG_DEBUG
: LOG_WARNING
, r
,
1875 "Failed to set file attribute 0x%x: %m", chattr_flags
[j
]);
1878 struct FSSHeader h
= {
1879 .signature
= { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' },
1880 .machine_id
= machine
,
1882 .header_size
= htole64(sizeof(h
)),
1883 .start_usec
= htole64(n
* arg_interval
),
1884 .interval_usec
= htole64(arg_interval
),
1885 .fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
),
1886 .fsprg_state_size
= htole64(state_size
),
1889 r
= loop_write(fd
, &h
, sizeof(h
), false);
1891 return log_error_errno(r
, "Failed to write header: %m");
1893 r
= loop_write(fd
, state
, state_size
, false);
1895 return log_error_errno(r
, "Failed to write state: %m");
1897 if (rename(k
, p
) < 0)
1898 return log_error_errno(errno
, "Failed to link file: %m");
1902 _cleanup_free_
char *hn
= NULL
;
1905 hn
= gethostname_malloc();
1907 hostname_cleanup(hn
);
1909 char tsb
[FORMAT_TIMESPAN_MAX
];
1911 "\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR
".\n"
1913 "The %ssecret sealing key%s has been written to the following local file.\n"
1914 "This key file is automatically updated when the sealing key is advanced.\n"
1915 "It should not be used on multiple hosts.\n"
1919 "The sealing key is automatically changed every %s.\n"
1921 "Please write down the following %ssecret verification key%s. It should be stored\n"
1922 "in a safe location and should not be saved locally on disk.\n"
1924 hn
?: "", hn
? "/" : "", SD_ID128_FORMAT_VAL(machine
),
1925 ansi_highlight(), ansi_normal(),
1927 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0),
1928 ansi_highlight(), ansi_normal(),
1929 ansi_highlight_red());
1933 for (size_t i
= 0; i
< seed_size
; i
++) {
1934 if (i
> 0 && i
% 3 == 0)
1936 printf("%02x", ((uint8_t*) seed
)[i
]);
1938 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1941 fprintf(stderr
, "%s", ansi_normal());
1943 (void) print_qr_code(stderr
,
1944 "\nTo transfer the verification key to your phone scan the QR code below:\n",
1953 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1954 "Forward-secure sealing not available.");
1958 static int verify(sd_journal
*j
) {
1964 log_show_color(true);
1966 ORDERED_HASHMAP_FOREACH(f
, j
->files
) {
1968 usec_t first
= 0, validated
= 0, last
= 0;
1971 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1972 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1975 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1977 /* If the key was invalid give up right-away. */
1980 log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
1983 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1984 log_info("PASS: %s", f
->path
);
1986 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1987 if (validated
> 0) {
1988 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1989 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
1990 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
1991 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1992 } else if (last
> 0)
1993 log_info("=> No sealing yet, %s of entries not sealed.",
1994 format_timespan(c
, sizeof(c
), last
- first
, 0));
1996 log_info("=> No sealing yet, no entries in file.");
2004 static int simple_varlink_call(const char *option
, const char *method
) {
2005 _cleanup_(varlink_flush_close_unrefp
) Varlink
*link
= NULL
;
2006 const char *error
, *fn
;
2010 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "%s is not supported in conjunction with --machine=.", option
);
2012 fn
= arg_namespace
?
2013 strjoina("/run/systemd/journal.", arg_namespace
, "/io.systemd.journal") :
2014 "/run/systemd/journal/io.systemd.journal";
2016 r
= varlink_connect_address(&link
, fn
);
2018 return log_error_errno(r
, "Failed to connect to %s: %m", fn
);
2020 (void) varlink_set_description(link
, "journal");
2021 (void) varlink_set_relative_timeout(link
, USEC_INFINITY
);
2023 r
= varlink_call(link
, method
, NULL
, NULL
, &error
, NULL
);
2025 return log_error_errno(r
, "Failed to execute varlink call: %m");
2027 return log_error_errno(SYNTHETIC_ERRNO(ENOANO
),
2028 "Failed to execute varlink call: %s", error
);
2033 static int flush_to_var(void) {
2034 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
2037 static int relinquish_var(void) {
2038 return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
2041 static int rotate(void) {
2042 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
2045 static int sync_journal(void) {
2046 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
2049 static int wait_for_change(sd_journal
*j
, int poll_fd
) {
2050 struct pollfd pollfds
[] = {
2051 { .fd
= poll_fd
, .events
= POLLIN
},
2052 { .fd
= STDOUT_FILENO
},
2060 assert(poll_fd
>= 0);
2062 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
2063 * i.e. when it is closed. */
2065 r
= sd_journal_get_timeout(j
, &timeout
);
2067 return log_error_errno(r
, "Failed to determine journal waiting time: %m");
2069 if (ppoll(pollfds
, ELEMENTSOF(pollfds
),
2070 timeout
== USEC_INFINITY
? NULL
: timespec_store(&ts
, timeout
), NULL
) < 0) {
2074 return log_error_errno(errno
, "Couldn't wait for journal event: %m");
2077 if (pollfds
[1].revents
& (POLLHUP
|POLLERR
|POLLNVAL
)) /* STDOUT has been closed? */
2078 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED
),
2079 "Standard output has been closed.");
2081 if (pollfds
[0].revents
& POLLNVAL
)
2082 return log_debug_errno(SYNTHETIC_ERRNO(EBADF
), "Change fd closed?");
2084 r
= sd_journal_process(j
);
2086 return log_error_errno(r
, "Failed to process journal events: %m");
2091 int main(int argc
, char *argv
[]) {
2092 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
2093 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*decrypted_image
= NULL
;
2094 _cleanup_(umount_and_rmdir_and_freep
) char *unlink_dir
= NULL
;
2095 bool previous_boot_id_valid
= false, first_line
= true, ellipsized
= false, need_seek
= false;
2096 bool use_cursor
= false, after_cursor
= false;
2097 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2098 sd_id128_t previous_boot_id
;
2099 int n_shown
= 0, r
, poll_fd
= -1;
2101 setlocale(LC_ALL
, "");
2104 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2105 * split up into many files. */
2106 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
2108 r
= parse_argv(argc
, argv
);
2115 r
= mount_image_privately_interactively(
2117 DISSECT_IMAGE_REQUIRE_ROOT
|DISSECT_IMAGE_VALIDATE_OS
|DISSECT_IMAGE_RELAX_VAR_CHECK
|
2118 (arg_action
== ACTION_UPDATE_CATALOG
? DISSECT_IMAGE_FSCK
: DISSECT_IMAGE_READ_ONLY
),
2125 arg_root
= strdup(unlink_dir
);
2130 signal(SIGWINCH
, columns_lines_cache_reset
);
2133 switch (arg_action
) {
2135 case ACTION_NEW_ID128
:
2136 r
= id128_print_new(ID128_PRINT_PRETTY
);
2139 case ACTION_SETUP_KEYS
:
2143 case ACTION_LIST_CATALOG
:
2144 case ACTION_DUMP_CATALOG
:
2145 case ACTION_UPDATE_CATALOG
: {
2146 _cleanup_free_
char *database
;
2148 database
= path_join(arg_root
, CATALOG_DATABASE
);
2154 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2155 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2157 log_error_errno(r
, "Failed to list catalog: %m");
2159 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2161 (void) pager_open(arg_pager_flags
);
2164 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2166 r
= catalog_list(stdout
, database
, oneline
);
2168 log_error_errno(r
, "Failed to list catalog: %m");
2178 case ACTION_RELINQUISH_VAR
:
2179 r
= relinquish_var();
2191 case ACTION_PRINT_HEADER
:
2193 case ACTION_DISK_USAGE
:
2194 case ACTION_LIST_BOOTS
:
2196 case ACTION_ROTATE_AND_VACUUM
:
2197 case ACTION_LIST_FIELDS
:
2198 case ACTION_LIST_FIELD_NAMES
:
2199 /* These ones require access to the journal files, continue below. */
2203 assert_not_reached("Unknown action");
2207 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2209 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2210 else if (arg_file_stdin
)
2211 r
= sd_journal_open_files_fd(&j
, (int[]) { STDIN_FILENO
}, 1, 0);
2213 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2214 else if (arg_machine
) {
2215 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2216 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2217 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2220 if (geteuid() != 0) {
2221 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2222 * the container, thus we need root privileges to override them. */
2223 r
= log_error_errno(SYNTHETIC_ERRNO(EPERM
), "Using the --machine= switch requires root privileges.");
2227 r
= sd_bus_open_system(&bus
);
2229 log_error_errno(r
, "Failed to open system bus: %m");
2233 r
= sd_bus_call_method(
2235 "org.freedesktop.machine1",
2236 "/org/freedesktop/machine1",
2237 "org.freedesktop.machine1.Manager",
2238 "OpenMachineRootDirectory",
2243 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2247 r
= sd_bus_message_read(reply
, "h", &fd
);
2249 bus_log_parse_error(r
);
2253 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2255 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2259 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2263 r
= sd_journal_open_namespace(
2266 (arg_merge
? 0 : SD_JOURNAL_LOCAL_ONLY
) |
2267 arg_namespace_flags
| arg_journal_type
);
2269 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2273 r
= journal_access_check_and_warn(j
, arg_quiet
,
2274 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2278 switch (arg_action
) {
2280 case ACTION_NEW_ID128
:
2281 case ACTION_SETUP_KEYS
:
2282 case ACTION_LIST_CATALOG
:
2283 case ACTION_DUMP_CATALOG
:
2284 case ACTION_UPDATE_CATALOG
:
2288 assert_not_reached("Unexpected action.");
2290 case ACTION_PRINT_HEADER
:
2291 journal_print_header(j
);
2299 case ACTION_DISK_USAGE
: {
2301 char sbytes
[FORMAT_BYTES_MAX
];
2303 r
= sd_journal_get_usage(j
, &bytes
);
2307 printf("Archived and active journals take up %s in the file system.\n",
2308 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2312 case ACTION_LIST_BOOTS
:
2316 case ACTION_ROTATE_AND_VACUUM
:
2324 case ACTION_VACUUM
: {
2327 HASHMAP_FOREACH(d
, j
->directories_by_path
) {
2330 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2332 log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2340 case ACTION_LIST_FIELD_NAMES
: {
2343 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2344 printf("%s\n", field
);
2353 case ACTION_LIST_FIELDS
:
2357 assert_not_reached("Unknown action");
2360 if (arg_boot_offset
!= 0 &&
2361 sd_journal_has_runtime_files(j
) > 0 &&
2362 sd_journal_has_persistent_files(j
) == 0) {
2363 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2367 /* add_boot() must be called first!
2368 * It may need to seek the journal to find parent boot IDs. */
2379 log_error_errno(r
, "Failed to add filter for units: %m");
2383 r
= add_syslog_identifier(j
);
2385 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2389 r
= add_priorities(j
);
2393 r
= add_facilities(j
);
2397 r
= add_matches(j
, argv
+ optind
);
2401 if (DEBUG_LOGGING
) {
2402 _cleanup_free_
char *filter
;
2404 filter
= journal_make_match_string(j
);
2408 log_debug("Journal filter: %s", filter
);
2411 if (arg_action
== ACTION_LIST_FIELDS
) {
2417 r
= sd_journal_set_data_threshold(j
, 0);
2419 log_error_errno(r
, "Failed to unset data size threshold: %m");
2423 r
= sd_journal_query_unique(j
, arg_field
);
2425 log_error_errno(r
, "Failed to query unique data objects: %m");
2429 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2432 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2435 eq
= memchr(data
, '=', size
);
2437 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2439 printf("%.*s\n", (int) size
, (const char*) data
);
2448 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2450 poll_fd
= sd_journal_get_fd(j
);
2451 if (poll_fd
== -EMFILE
) {
2452 log_warning_errno(poll_fd
, "Insufficient watch descriptors available. Reverting to -n.");
2454 } else if (poll_fd
== -EMEDIUMTYPE
) {
2455 log_error_errno(poll_fd
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2457 } else if (poll_fd
< 0) {
2458 log_error_errno(poll_fd
, "Failed to get journal fd: %m");
2463 if (arg_cursor
|| arg_after_cursor
|| arg_cursor_file
) {
2464 _cleanup_free_
char *cursor_from_file
= NULL
;
2465 const char *cursor
= arg_cursor
?: arg_after_cursor
;
2467 if (arg_cursor_file
) {
2468 r
= read_one_line_file(arg_cursor_file
, &cursor_from_file
);
2469 if (r
< 0 && r
!= -ENOENT
) {
2470 log_error_errno(r
, "Failed to read cursor file %s: %m", arg_cursor_file
);
2475 cursor
= cursor_from_file
;
2476 after_cursor
= true;
2479 after_cursor
= !!arg_after_cursor
;
2482 r
= sd_journal_seek_cursor(j
, cursor
);
2484 log_error_errno(r
, "Failed to seek to cursor: %m");
2493 r
= sd_journal_next_skip(j
, 1 + after_cursor
);
2495 r
= sd_journal_previous_skip(j
, 1 + after_cursor
);
2497 if (after_cursor
&& r
< 2) {
2498 /* We couldn't find the next entry after the cursor. */
2505 } else if (arg_since_set
&& !arg_reverse
) {
2506 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2508 log_error_errno(r
, "Failed to seek to date: %m");
2511 r
= sd_journal_next(j
);
2513 } else if (arg_until_set
&& arg_reverse
) {
2514 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2516 log_error_errno(r
, "Failed to seek to date: %m");
2519 r
= sd_journal_previous(j
);
2521 } else if (arg_reverse
) {
2522 r
= sd_journal_seek_tail(j
);
2524 log_error_errno(r
, "Failed to seek to tail: %m");
2528 r
= sd_journal_previous(j
);
2530 } else if (arg_lines
>= 0) {
2531 r
= sd_journal_seek_tail(j
);
2533 log_error_errno(r
, "Failed to seek to tail: %m");
2537 r
= sd_journal_previous_skip(j
, arg_lines
);
2540 r
= sd_journal_seek_head(j
);
2542 log_error_errno(r
, "Failed to seek to head: %m");
2546 r
= sd_journal_next(j
);
2550 log_error_errno(r
, "Failed to iterate through journal: %m");
2557 (void) pager_open(arg_pager_flags
);
2559 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2561 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2563 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2565 log_error_errno(r
, "Failed to get cutoff: %m");
2571 printf("-- Journal begins at %s. --\n",
2572 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2574 printf("-- Journal begins at %s, ends at %s. --\n",
2575 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2576 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2581 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2583 size_t highlight
[2] = {};
2587 r
= sd_journal_next(j
);
2589 r
= sd_journal_previous(j
);
2591 log_error_errno(r
, "Failed to iterate through journal: %m");
2598 if (arg_until_set
&& !arg_reverse
) {
2601 r
= sd_journal_get_realtime_usec(j
, &usec
);
2603 log_error_errno(r
, "Failed to determine timestamp: %m");
2606 if (usec
> arg_until
)
2610 if (arg_since_set
&& arg_reverse
) {
2613 r
= sd_journal_get_realtime_usec(j
, &usec
);
2615 log_error_errno(r
, "Failed to determine timestamp: %m");
2618 if (usec
< arg_since
)
2622 if (!arg_merge
&& !arg_quiet
) {
2625 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2627 if (previous_boot_id_valid
&&
2628 !sd_id128_equal(boot_id
, previous_boot_id
))
2629 printf("%s-- Reboot --%s\n",
2630 ansi_highlight(), ansi_normal());
2632 previous_boot_id
= boot_id
;
2633 previous_boot_id_valid
= true;
2638 if (arg_compiled_pattern
) {
2639 _cleanup_(sym_pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2640 const void *message
;
2644 md
= sym_pcre2_match_data_create(1, NULL
);
2648 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2655 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2659 assert_se(message
= startswith(message
, "MESSAGE="));
2661 r
= sym_pcre2_match(arg_compiled_pattern
,
2663 len
- strlen("MESSAGE="),
2664 0, /* start at offset 0 in the subject */
2665 0, /* default options */
2668 if (r
== PCRE2_ERROR_NOMATCH
) {
2673 unsigned char buf
[LINE_MAX
];
2676 r2
= sym_pcre2_get_error_message(r
, buf
, sizeof buf
);
2677 log_error("Pattern matching failed: %s",
2678 r2
< 0 ? "unknown error" : (char*) buf
);
2683 ovec
= sym_pcre2_get_ovector_pointer(md
);
2684 highlight
[0] = ovec
[0];
2685 highlight
[1] = ovec
[1];
2690 arg_all
* OUTPUT_SHOW_ALL
|
2691 arg_full
* OUTPUT_FULL_WIDTH
|
2692 colors_enabled() * OUTPUT_COLOR
|
2693 arg_catalog
* OUTPUT_CATALOG
|
2694 arg_utc
* OUTPUT_UTC
|
2695 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2697 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2698 arg_output_fields
, highlight
, &ellipsized
);
2700 if (r
== -EADDRNOTAVAIL
)
2707 /* If journalctl take a long time to process messages, and during that time journal file
2708 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2709 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2710 * in the "following" case. By periodically calling sd_journal_process() during the processing
2711 * loop we shrink the window of time a client instance has open file descriptors for rotated
2712 * (deleted) journal files. */
2713 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2714 r
= sd_journal_process(j
);
2716 log_error_errno(r
, "Failed to process inotify events: %m");
2723 if (n_shown
== 0 && !arg_quiet
)
2724 printf("-- No entries --\n");
2730 r
= wait_for_change(j
, poll_fd
);
2737 if (arg_show_cursor
|| arg_cursor_file
) {
2738 _cleanup_free_
char *cursor
= NULL
;
2740 r
= sd_journal_get_cursor(j
, &cursor
);
2741 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2742 log_error_errno(r
, "Failed to get cursor: %m");
2744 if (arg_show_cursor
)
2745 printf("-- cursor: %s\n", cursor
);
2747 if (arg_cursor_file
) {
2748 r
= write_string_file(arg_cursor_file
, cursor
,
2749 WRITE_STRING_FILE_CREATE
|
2750 WRITE_STRING_FILE_ATOMIC
);
2753 "Failed to write new cursor to %s: %m",
2762 strv_free(arg_file
);
2764 set_free(arg_facilities
);
2765 strv_free(arg_syslog_identifier
);
2766 strv_free(arg_system_units
);
2767 strv_free(arg_user_units
);
2768 strv_free(arg_output_fields
);
2771 free(arg_verify_key
);
2774 if (arg_compiled_pattern
) {
2775 sym_pcre2_code_free(arg_compiled_pattern
);
2777 /* --grep was used, no error was thrown, but the pattern didn't
2778 * match anything. Let's mimic grep's behavior here and return
2779 * a non-zero exit code, so journalctl --grep can be used
2780 * in scripts and such */
2781 if (r
== 0 && n_shown
== 0)
2786 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;