1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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-util.h"
47 #include "journal-vacuum.h"
48 #include "journal-verify.h"
49 #include "locale-util.h"
51 #include "logs-show.h"
52 #include "memory-util.h"
54 #include "mount-util.h"
55 #include "mountpoint-util.h"
56 #include "nulstr-util.h"
58 #include "parse-util.h"
59 #include "path-util.h"
60 #include "pcre2-dlopen.h"
61 #include "pretty-print.h"
62 #include "qrcode-util.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 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
204 "Devpath does not start with /dev/");
206 if (stat(devpath
, &st
) < 0)
207 return log_error_errno(errno
, "Couldn't stat file: %m");
209 r
= device_new_from_stat_rdev(&device
, &st
);
211 return log_error_errno(r
, "Failed to get device from devnum %u:%u: %m", major(st
.st_rdev
), minor(st
.st_rdev
));
213 for (d
= device
; d
; ) {
214 _cleanup_free_
char *match
= NULL
;
215 const char *subsys
, *sysname
, *devnode
;
218 r
= sd_device_get_subsystem(d
, &subsys
);
222 r
= sd_device_get_sysname(d
, &sysname
);
226 match
= strjoin("_KERNEL_DEVICE=+", subsys
, ":", sysname
);
230 r
= sd_journal_add_match(j
, match
, 0);
232 return log_error_errno(r
, "Failed to add match: %m");
234 if (sd_device_get_devname(d
, &devnode
) >= 0) {
235 _cleanup_free_
char *match1
= NULL
;
237 r
= stat(devnode
, &st
);
239 return log_error_errno(r
, "Failed to stat() device node \"%s\": %m", devnode
);
241 r
= asprintf(&match1
, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st
.st_mode
) ? 'b' : 'c', major(st
.st_rdev
), minor(st
.st_rdev
));
245 r
= sd_journal_add_match(j
, match1
, 0);
247 return log_error_errno(r
, "Failed to add match: %m");
251 if (sd_device_get_parent(d
, &parent
) < 0)
257 r
= add_match_this_boot(j
, arg_machine
);
259 return log_error_errno(r
, "Failed to add match for the current boot: %m");
264 static char *format_timestamp_maybe_utc(char *buf
, size_t l
, usec_t t
) {
267 return format_timestamp_style(buf
, l
, t
, TIMESTAMP_UTC
);
269 return format_timestamp(buf
, l
, t
);
272 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
273 sd_id128_t id
= SD_ID128_NULL
;
276 if (streq(x
, "all")) {
277 *boot_id
= SD_ID128_NULL
;
280 } else if (strlen(x
) >= 32) {
284 r
= sd_id128_from_string(t
, &id
);
288 if (!IN_SET(*x
, 0, '-', '+'))
292 r
= safe_atoi(x
, &off
);
297 r
= safe_atoi(x
, &off
);
311 static int help_facilities(void) {
313 puts("Available facilities:");
315 for (int i
= 0; i
< LOG_NFACILITIES
; i
++) {
316 _cleanup_free_
char *t
= NULL
;
318 if (log_facility_unshifted_to_string_alloc(i
, &t
))
326 static int help(void) {
327 _cleanup_free_
char *link
= NULL
;
330 (void) pager_open(arg_pager_flags
);
332 r
= terminal_urlify_man("journalctl", "1", &link
);
336 printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
337 "%5$sQuery the journal.%6$s\n\n"
339 " --system Show the system journal\n"
340 " --user Show the user journal for the current user\n"
341 " -M --machine=CONTAINER Operate on local container\n"
342 " -S --since=DATE Show entries not older than the specified date\n"
343 " -U --until=DATE Show entries not newer than the specified date\n"
344 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
345 " --after-cursor=CURSOR Show entries after the specified cursor\n"
346 " --show-cursor Print the cursor after all the entries\n"
347 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
348 " -b --boot[=ID] Show current boot or the specified boot\n"
349 " --list-boots Show terse information about recorded boots\n"
350 " -k --dmesg Show kernel message log from the current boot\n"
351 " -u --unit=UNIT Show logs from the specified unit\n"
352 " --user-unit=UNIT Show logs from the specified user unit\n"
353 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
354 " -p --priority=RANGE Show entries with the specified priority\n"
355 " --facility=FACILITY... Show entries with the specified facilities\n"
356 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
357 " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
358 " -e --pager-end Immediately jump to the end in the pager\n"
359 " -f --follow Follow the journal\n"
360 " -n --lines[=INTEGER] Number of journal entries to show\n"
361 " --no-tail Show all lines, even in follow mode\n"
362 " -r --reverse Show the newest entries first\n"
363 " -o --output=STRING Change journal output mode (short, short-precise,\n"
364 " short-iso, short-iso-precise, short-full,\n"
365 " short-monotonic, short-unix, verbose, export,\n"
366 " json, json-pretty, json-sse, json-seq, cat,\n"
368 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
369 " --utc Express time in Coordinated Universal Time (UTC)\n"
370 " -x --catalog Add message explanations where available\n"
371 " --no-full Ellipsize fields\n"
372 " -a --all Show all fields, including long and unprintable\n"
373 " -q --quiet Do not show info messages and privilege warning\n"
374 " --no-pager Do not pipe output into a pager\n"
375 " --no-hostname Suppress output of hostname field\n"
376 " -m --merge Show entries from all available journals\n"
377 " -D --directory=PATH Show journal files from directory\n"
378 " --file=PATH Show journal file\n"
379 " --root=ROOT Operate on files below a root directory\n"
380 " --image=IMAGE Operate on files in filesystem image\n"
381 " --namespace=NAMESPACE Show journal data from specified namespace\n"
382 " --interval=TIME Time interval for changing the FSS sealing key\n"
383 " --verify-key=KEY Specify FSS verification key\n"
384 " --force Override of the FSS key pair with --setup-keys\n"
385 "\n%3$sCommands:%4$s\n"
386 " -h --help Show this help text\n"
387 " --version Show package version\n"
388 " -N --fields List all field names currently used\n"
389 " -F --field=FIELD List all values that a specified field takes\n"
390 " --disk-usage Show total disk usage of all journal files\n"
391 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
392 " --vacuum-files=INT Leave only the specified number of journal files\n"
393 " --vacuum-time=TIME Remove journal files older than specified time\n"
394 " --verify Verify journal file consistency\n"
395 " --sync Synchronize unwritten journal messages to disk\n"
396 " --relinquish-var Stop logging to disk, log to temporary file system\n"
397 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
398 " --flush Flush all journal data from /run into /var\n"
399 " --rotate Request immediate rotation of the journal files\n"
400 " --header Show journal header information\n"
401 " --list-catalog Show all message IDs in the catalog\n"
402 " --dump-catalog Show entries in the message catalog\n"
403 " --update-catalog Update the message catalog database\n"
404 " --setup-keys Generate a new FSS key pair\n"
405 "\nSee the %2$s for details.\n"
406 , program_invocation_short_name
408 , ansi_underline(), ansi_normal()
409 , ansi_highlight(), ansi_normal()
415 static int parse_argv(int argc
, char *argv
[]) {
450 ARG_SMART_RELINQUISH_VAR
,
460 static const struct option options
[] = {
461 { "help", no_argument
, NULL
, 'h' },
462 { "version" , no_argument
, NULL
, ARG_VERSION
},
463 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
464 { "pager-end", no_argument
, NULL
, 'e' },
465 { "follow", no_argument
, NULL
, 'f' },
466 { "force", no_argument
, NULL
, ARG_FORCE
},
467 { "output", required_argument
, NULL
, 'o' },
468 { "all", no_argument
, NULL
, 'a' },
469 { "full", no_argument
, NULL
, 'l' },
470 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
471 { "lines", optional_argument
, NULL
, 'n' },
472 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
473 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
474 { "quiet", no_argument
, NULL
, 'q' },
475 { "merge", no_argument
, NULL
, 'm' },
476 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
477 { "boot", optional_argument
, NULL
, 'b' },
478 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
479 { "dmesg", no_argument
, NULL
, 'k' },
480 { "system", no_argument
, NULL
, ARG_SYSTEM
},
481 { "user", no_argument
, NULL
, ARG_USER
},
482 { "directory", required_argument
, NULL
, 'D' },
483 { "file", required_argument
, NULL
, ARG_FILE
},
484 { "root", required_argument
, NULL
, ARG_ROOT
},
485 { "image", required_argument
, NULL
, ARG_IMAGE
},
486 { "header", no_argument
, NULL
, ARG_HEADER
},
487 { "identifier", required_argument
, NULL
, 't' },
488 { "priority", required_argument
, NULL
, 'p' },
489 { "facility", required_argument
, NULL
, ARG_FACILITY
},
490 { "grep", required_argument
, NULL
, 'g' },
491 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
492 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
493 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
494 { "verify", no_argument
, NULL
, ARG_VERIFY
},
495 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
496 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
497 { "cursor", required_argument
, NULL
, 'c' },
498 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
499 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
500 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
501 { "since", required_argument
, NULL
, 'S' },
502 { "until", required_argument
, NULL
, 'U' },
503 { "unit", required_argument
, NULL
, 'u' },
504 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
505 { "field", required_argument
, NULL
, 'F' },
506 { "fields", no_argument
, NULL
, 'N' },
507 { "catalog", no_argument
, NULL
, 'x' },
508 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
509 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
510 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
511 { "reverse", no_argument
, NULL
, 'r' },
512 { "machine", required_argument
, NULL
, 'M' },
513 { "utc", no_argument
, NULL
, ARG_UTC
},
514 { "flush", no_argument
, NULL
, ARG_FLUSH
},
515 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
516 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
517 { "sync", no_argument
, NULL
, ARG_SYNC
},
518 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
519 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
520 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
521 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
522 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
523 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
524 { "namespace", required_argument
, NULL
, ARG_NAMESPACE
},
533 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:", options
, NULL
)) >= 0)
544 arg_pager_flags
|= PAGER_DISABLE
;
548 arg_pager_flags
|= PAGER_JUMP_TO_END
;
550 if (arg_lines
== ARG_LINES_DEFAULT
)
560 if (streq(optarg
, "help")) {
561 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
565 arg_output
= output_mode_from_string(optarg
);
567 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unknown output format '%s'.", optarg
);
569 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
588 if (streq(optarg
, "all"))
589 arg_lines
= ARG_LINES_ALL
;
591 r
= safe_atoi(optarg
, &arg_lines
);
592 if (r
< 0 || arg_lines
< 0)
593 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse lines '%s'", optarg
);
598 /* Hmm, no argument? Maybe the next
599 * word on the command line is
600 * supposed to be the argument? Let's
601 * see if there is one, and is
605 if (streq(argv
[optind
], "all")) {
606 arg_lines
= ARG_LINES_ALL
;
608 } else if (safe_atoi(argv
[optind
], &n
) >= 0 && n
>= 0) {
622 arg_action
= ACTION_NEW_ID128
;
635 arg_boot_id
= SD_ID128_NULL
;
641 arg_boot_id
= SD_ID128_NULL
;
645 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
647 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
651 /* Hmm, no argument? Maybe the next
652 * word on the command line is
653 * supposed to be the argument? Let's
654 * see if there is one and is parsable
655 * as a boot descriptor... */
656 } else if (optind
< argc
) {
657 r
= parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
666 arg_action
= ACTION_LIST_BOOTS
;
670 arg_boot
= arg_dmesg
= true;
674 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
678 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
682 arg_machine
= optarg
;
686 if (streq(optarg
, "*")) {
687 arg_namespace_flags
= SD_JOURNAL_ALL_NAMESPACES
;
688 arg_namespace
= NULL
;
689 } else if (startswith(optarg
, "+")) {
690 arg_namespace_flags
= SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
;
691 arg_namespace
= optarg
+ 1;
692 } else if (isempty(optarg
)) {
693 arg_namespace_flags
= 0;
694 arg_namespace
= NULL
;
696 arg_namespace_flags
= 0;
697 arg_namespace
= optarg
;
703 arg_directory
= optarg
;
707 if (streq(optarg
, "-"))
708 /* An undocumented feature: we can read journal files from STDIN. We don't document
709 * this though, since after all we only support this for mmap-able, seekable files, and
710 * not for example pipes which are probably the primary usecase for reading things from
711 * STDIN. To avoid confusion we hence don't document this feature. */
712 arg_file_stdin
= true;
714 r
= glob_extend(&arg_file
, optarg
, GLOB_NOCHECK
);
716 return log_error_errno(r
, "Failed to add paths: %m");
721 r
= parse_path_argument_and_warn(optarg
, /* suppress_root= */ true, &arg_root
);
727 r
= parse_path_argument_and_warn(optarg
, /* suppress_root= */ false, &arg_image
);
736 case ARG_CURSOR_FILE
:
737 arg_cursor_file
= optarg
;
740 case ARG_AFTER_CURSOR
:
741 arg_after_cursor
= optarg
;
744 case ARG_SHOW_CURSOR
:
745 arg_show_cursor
= true;
749 arg_action
= ACTION_PRINT_HEADER
;
753 arg_action
= ACTION_VERIFY
;
757 arg_action
= ACTION_DISK_USAGE
;
760 case ARG_VACUUM_SIZE
:
761 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
763 return log_error_errno(r
, "Failed to parse vacuum size: %s", optarg
);
765 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
768 case ARG_VACUUM_FILES
:
769 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
771 return log_error_errno(r
, "Failed to parse vacuum files: %s", optarg
);
773 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
776 case ARG_VACUUM_TIME
:
777 r
= parse_sec(optarg
, &arg_vacuum_time
);
779 return log_error_errno(r
, "Failed to parse vacuum time: %s", optarg
);
781 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
790 arg_action
= ACTION_SETUP_KEYS
;
794 r
= free_and_strdup(&arg_verify_key
, optarg
);
797 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
798 * in ps or htop output. */
799 memset(optarg
, 'x', strlen(optarg
));
801 arg_action
= ACTION_VERIFY
;
806 r
= parse_sec(optarg
, &arg_interval
);
807 if (r
< 0 || arg_interval
<= 0)
808 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
809 "Failed to parse sealing key change interval: %s", optarg
);
816 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
817 "Compiled without forward-secure sealing support.");
823 dots
= strstr(optarg
, "..");
825 _cleanup_free_
char *a
= NULL
;
829 a
= strndup(optarg
, dots
- optarg
);
833 from
= log_level_from_string(a
);
834 to
= log_level_from_string(dots
+ 2);
836 if (from
< 0 || to
< 0)
837 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
838 "Failed to parse log level range %s", optarg
);
843 for (i
= from
; i
<= to
; i
++)
844 arg_priorities
|= 1 << i
;
846 for (i
= to
; i
<= from
; i
++)
847 arg_priorities
|= 1 << i
;
853 p
= log_level_from_string(optarg
);
855 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
856 "Unknown log level %s", optarg
);
860 for (i
= 0; i
<= p
; i
++)
861 arg_priorities
|= 1 << i
;
871 _cleanup_free_
char *fac
= NULL
;
874 r
= extract_first_word(&p
, &fac
, ",", 0);
876 return log_error_errno(r
, "Failed to parse facilities: %s", optarg
);
880 if (streq(fac
, "help")) {
885 num
= log_facility_unshifted_from_string(fac
);
887 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
888 "Bad --facility= argument \"%s\".", fac
);
890 if (set_ensure_put(&arg_facilities
, NULL
, INT_TO_PTR(num
)) < 0)
899 arg_pattern
= optarg
;
902 case ARG_CASE_SENSITIVE
:
904 r
= parse_boolean(optarg
);
906 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
907 arg_case_sensitive
= r
;
909 arg_case_sensitive
= true;
914 case ARG_CASE_SENSITIVE
:
915 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Compiled without pattern matching support");
919 r
= parse_timestamp(optarg
, &arg_since
);
921 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
922 "Failed to parse timestamp: %s", optarg
);
923 arg_since_set
= true;
927 r
= parse_timestamp(optarg
, &arg_until
);
929 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
930 "Failed to parse timestamp: %s", optarg
);
931 arg_until_set
= true;
935 r
= strv_extend(&arg_syslog_identifier
, optarg
);
941 r
= strv_extend(&arg_system_units
, optarg
);
947 r
= strv_extend(&arg_user_units
, optarg
);
953 arg_action
= ACTION_LIST_FIELDS
;
958 arg_action
= ACTION_LIST_FIELD_NAMES
;
961 case ARG_NO_HOSTNAME
:
962 arg_no_hostname
= true;
969 case ARG_LIST_CATALOG
:
970 arg_action
= ACTION_LIST_CATALOG
;
973 case ARG_DUMP_CATALOG
:
974 arg_action
= ACTION_DUMP_CATALOG
;
977 case ARG_UPDATE_CATALOG
:
978 arg_action
= ACTION_UPDATE_CATALOG
;
990 arg_action
= ACTION_FLUSH
;
993 case ARG_SMART_RELINQUISH_VAR
: {
994 int root_mnt_id
, log_mnt_id
;
996 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
997 * if it's on the same mount as the root file system there's no point in
998 * relinquishing access and we can leave journald write to it until the very last
1001 r
= path_get_mnt_id("/", &root_mnt_id
);
1003 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
1005 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
1007 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
1008 else if (root_mnt_id
== log_mnt_id
) {
1009 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
1012 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
1018 case ARG_RELINQUISH_VAR
:
1019 arg_action
= ACTION_RELINQUISH_VAR
;
1023 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
1027 arg_action
= ACTION_SYNC
;
1030 case ARG_OUTPUT_FIELDS
: {
1031 _cleanup_strv_free_
char **v
= NULL
;
1033 v
= strv_split(optarg
, ",");
1037 if (!arg_output_fields
)
1038 arg_output_fields
= TAKE_PTR(v
);
1040 r
= strv_extend_strv(&arg_output_fields
, v
, true);
1051 assert_not_reached("Unhandled option");
1054 if (arg_follow
&& !arg_no_tail
&& !arg_since
&& arg_lines
== ARG_LINES_DEFAULT
)
1057 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
+ !!arg_image
> 1)
1058 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1059 "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
1061 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
)
1062 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1063 "--since= must be before --until=.");
1065 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1)
1066 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1067 "Please specify only one of --since=, --cursor=, and --after-cursor.");
1069 if (arg_follow
&& arg_reverse
)
1070 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1071 "Please specify either --reverse= or --follow=, not both.");
1073 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
)
1074 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1075 "Extraneous arguments starting with '%s'",
1078 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
)
1079 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1080 "Using --boot or --list-boots with --merge is not supported.");
1082 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
1083 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1084 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1085 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1086 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
1090 arg_system_units
= strv_free(arg_system_units
);
1101 if (arg_case_sensitive
>= 0)
1102 flags
= !arg_case_sensitive
* PCRE2_CASELESS
;
1104 _cleanup_(sym_pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
1106 _cleanup_(sym_pcre2_code_freep
) pcre2_code
*cs
= NULL
;
1108 md
= sym_pcre2_match_data_create(1, NULL
);
1112 r
= pattern_compile("[[:upper:]]", 0, &cs
);
1116 r
= sym_pcre2_match(cs
, (PCRE2_SPTR8
) arg_pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
1119 flags
= !has_case
* PCRE2_CASELESS
;
1122 log_debug("Doing case %s matching based on %s",
1123 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
1124 arg_case_sensitive
>= 0 ? "request" : "pattern casing");
1126 r
= pattern_compile(arg_pattern
, flags
, &arg_compiled_pattern
);
1135 static int add_matches(sd_journal
*j
, char **args
) {
1137 bool have_term
= false;
1141 STRV_FOREACH(i
, args
) {
1144 if (streq(*i
, "+")) {
1147 r
= sd_journal_add_disjunction(j
);
1150 } else if (path_is_absolute(*i
)) {
1151 _cleanup_free_
char *p
= NULL
, *t
= NULL
, *t2
= NULL
, *interpreter
= NULL
;
1154 r
= chase_symlinks(*i
, NULL
, CHASE_TRAIL_SLASH
, &p
, NULL
);
1156 return log_error_errno(r
, "Couldn't canonicalize path: %m");
1158 if (lstat(p
, &st
) < 0)
1159 return log_error_errno(errno
, "Couldn't stat file: %m");
1161 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
1162 if (executable_is_script(p
, &interpreter
) > 0) {
1163 _cleanup_free_
char *comm
;
1165 comm
= strndup(basename(p
), 15);
1169 t
= strjoin("_COMM=", comm
);
1173 /* Append _EXE only if the interpreter is not a link.
1174 Otherwise, it might be outdated often. */
1175 if (lstat(interpreter
, &st
) == 0 && !S_ISLNK(st
.st_mode
)) {
1176 t2
= strjoin("_EXE=", interpreter
);
1181 t
= strjoin("_EXE=", p
);
1186 r
= sd_journal_add_match(j
, t
, 0);
1189 r
= sd_journal_add_match(j
, t2
, 0);
1191 } else if (S_ISCHR(st
.st_mode
) || S_ISBLK(st
.st_mode
)) {
1192 r
= add_matches_for_device(j
, p
);
1196 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1197 "File is neither a device node, nor regular file, nor executable: %s",
1202 r
= sd_journal_add_match(j
, *i
, 0);
1207 return log_error_errno(r
, "Failed to add match '%s': %m", *i
);
1210 if (!strv_isempty(args
) && !have_term
)
1211 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1212 "\"+\" can only be used between terms");
1217 static void boot_id_free_all(BootId
*l
) {
1221 LIST_REMOVE(boot_list
, l
, i
);
1226 static int discover_next_boot(sd_journal
*j
,
1227 sd_id128_t previous_boot_id
,
1231 _cleanup_free_ BootId
*next_boot
= NULL
;
1232 char match
[9+32+1] = "_BOOT_ID=";
1239 /* We expect the journal to be on the last position of a boot
1240 * (in relation to the direction we are going), so that the next
1241 * invocation of sd_journal_next/previous will be from a different
1242 * boot. We then collect any information we desire and then jump
1243 * to the last location of the new boot by using a _BOOT_ID match
1244 * coming from the other journal direction. */
1246 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1247 * we can actually advance to a *different* boot. */
1248 sd_journal_flush_matches(j
);
1252 r
= sd_journal_previous(j
);
1254 r
= sd_journal_next(j
);
1258 return 0; /* End of journal, yay. */
1260 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1264 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1265 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1266 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1267 * complete than the main entry array, and hence might reference an entry that's not actually the last
1268 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1269 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1272 } while (sd_id128_equal(boot_id
, previous_boot_id
));
1274 next_boot
= new0(BootId
, 1);
1278 next_boot
->id
= boot_id
;
1280 r
= sd_journal_get_realtime_usec(j
, &next_boot
->first
);
1284 /* Now seek to the last occurrence of this boot ID. */
1285 sd_id128_to_string(next_boot
->id
, match
+ 9);
1286 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1291 r
= sd_journal_seek_head(j
);
1293 r
= sd_journal_seek_tail(j
);
1298 r
= sd_journal_next(j
);
1300 r
= sd_journal_previous(j
);
1304 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA
),
1305 "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. */
1307 r
= sd_journal_get_realtime_usec(j
, &next_boot
->last
);
1311 *ret
= TAKE_PTR(next_boot
);
1316 static int get_boots(
1319 sd_id128_t
*boot_id
,
1324 BootId
*head
= NULL
, *tail
= NULL
, *id
;
1325 const bool advance_older
= boot_id
&& offset
<= 0;
1326 sd_id128_t previous_boot_id
;
1330 /* Adjust for the asymmetry that offset 0 is
1331 * the last (and current) boot, while 1 is considered the
1332 * (chronological) first boot in the journal. */
1333 skip_once
= boot_id
&& sd_id128_is_null(*boot_id
) && offset
<= 0;
1335 /* Advance to the earliest/latest occurrence of our reference
1336 * boot ID (taking our lookup direction into account), so that
1337 * discover_next_boot() can do its job.
1338 * If no reference is given, the journal head/tail will do,
1339 * they're "virtual" boots after all. */
1340 if (boot_id
&& !sd_id128_is_null(*boot_id
)) {
1341 char match
[9+32+1] = "_BOOT_ID=";
1343 sd_journal_flush_matches(j
);
1345 sd_id128_to_string(*boot_id
, match
+ 9);
1346 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1351 r
= sd_journal_seek_head(j
); /* seek to oldest */
1353 r
= sd_journal_seek_tail(j
); /* seek to newest */
1358 r
= sd_journal_next(j
); /* read the oldest entry */
1360 r
= sd_journal_previous(j
); /* read the most recently added entry */
1365 else if (offset
== 0) {
1370 /* At this point the read pointer is positioned at the oldest/newest occurrence of the reference boot
1371 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1372 * the following entry, which must then have an older/newer boot ID */
1376 r
= sd_journal_seek_tail(j
); /* seek to newest */
1378 r
= sd_journal_seek_head(j
); /* seek to oldest */
1382 /* No sd_journal_next()/_previous() here.
1384 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1385 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1389 previous_boot_id
= SD_ID128_NULL
;
1391 _cleanup_free_ BootId
*current
= NULL
;
1393 r
= discover_next_boot(j
, previous_boot_id
, advance_older
, ¤t
);
1395 boot_id_free_all(head
);
1402 previous_boot_id
= current
->id
;
1406 offset
+= advance_older
? 1 : -1;
1411 *boot_id
= current
->id
;
1415 LIST_FOREACH(boot_list
, id
, head
) {
1416 if (sd_id128_equal(id
->id
, current
->id
)) {
1417 /* boot id already stored, something wrong with the journal files */
1418 /* exiting as otherwise this problem would cause forever loop */
1422 LIST_INSERT_AFTER(boot_list
, head
, tail
, current
);
1423 tail
= TAKE_PTR(current
);
1432 sd_journal_flush_matches(j
);
1437 static int list_boots(sd_journal
*j
) {
1439 BootId
*id
, *all_ids
;
1443 count
= get_boots(j
, &all_ids
, NULL
, 0);
1445 return log_error_errno(count
, "Failed to determine boots: %m");
1449 (void) pager_open(arg_pager_flags
);
1451 /* numbers are one less, but we need an extra char for the sign */
1452 w
= DECIMAL_STR_WIDTH(count
- 1) + 1;
1455 LIST_FOREACH(boot_list
, id
, all_ids
) {
1456 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
];
1458 printf("% *i " SD_ID128_FORMAT_STR
" %s—%s\n",
1460 SD_ID128_FORMAT_VAL(id
->id
),
1461 format_timestamp_maybe_utc(a
, sizeof(a
), id
->first
),
1462 format_timestamp_maybe_utc(b
, sizeof(b
), id
->last
));
1466 boot_id_free_all(all_ids
);
1471 static int add_boot(sd_journal
*j
) {
1472 char match
[9+32+1] = "_BOOT_ID=";
1481 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1482 * We can do this only when we logs are coming from the current machine,
1483 * so take the slow path if log location is specified. */
1484 if (arg_boot_offset
== 0 && sd_id128_is_null(arg_boot_id
) &&
1485 !arg_directory
&& !arg_file
&& !arg_root
)
1486 return add_match_this_boot(j
, arg_machine
);
1488 boot_id
= arg_boot_id
;
1489 r
= get_boots(j
, NULL
, &boot_id
, arg_boot_offset
);
1492 const char *reason
= (r
== 0) ? "No such boot ID in journal" : strerror_safe(r
);
1494 if (sd_id128_is_null(arg_boot_id
))
1495 log_error("Data from the specified boot (%+i) is not available: %s",
1496 arg_boot_offset
, reason
);
1498 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR
") is not available: %s",
1499 SD_ID128_FORMAT_VAL(arg_boot_id
), reason
);
1501 return r
== 0 ? -ENODATA
: r
;
1504 sd_id128_to_string(boot_id
, match
+ 9);
1506 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
1508 return log_error_errno(r
, "Failed to add match: %m");
1510 r
= sd_journal_add_conjunction(j
);
1512 return log_error_errno(r
, "Failed to add conjunction: %m");
1517 static int add_dmesg(sd_journal
*j
) {
1524 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel",
1525 STRLEN("_TRANSPORT=kernel"));
1527 return log_error_errno(r
, "Failed to add match: %m");
1529 r
= sd_journal_add_conjunction(j
);
1531 return log_error_errno(r
, "Failed to add conjunction: %m");
1536 static int get_possible_units(
1542 _cleanup_set_free_free_ Set
*found
;
1546 found
= set_new(&string_hash_ops
);
1550 NULSTR_FOREACH(field
, fields
) {
1554 r
= sd_journal_query_unique(j
, field
);
1558 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1559 char **pattern
, *eq
;
1561 _cleanup_free_
char *u
= NULL
;
1563 eq
= memchr(data
, '=', size
);
1565 prefix
= eq
- (char*) data
+ 1;
1569 u
= strndup((char*) data
+ prefix
, size
- prefix
);
1573 STRV_FOREACH(pattern
, patterns
)
1574 if (fnmatch(*pattern
, u
, FNM_NOESCAPE
) == 0) {
1575 log_debug("Matched %s with pattern %s=%s", u
, field
, *pattern
);
1577 r
= set_consume(found
, u
);
1579 if (r
< 0 && r
!= -EEXIST
)
1587 *units
= TAKE_PTR(found
);
1592 /* This list is supposed to return the superset of unit names
1593 * possibly matched by rules added with add_matches_for_unit... */
1594 #define SYSTEM_UNITS \
1598 "OBJECT_SYSTEMD_UNIT\0" \
1601 /* ... and add_matches_for_user_unit */
1602 #define USER_UNITS \
1603 "_SYSTEMD_USER_UNIT\0" \
1605 "COREDUMP_USER_UNIT\0" \
1606 "OBJECT_SYSTEMD_USER_UNIT\0" \
1607 "_SYSTEMD_USER_SLICE\0"
1609 static int add_units(sd_journal
*j
) {
1610 _cleanup_strv_free_
char **patterns
= NULL
;
1616 STRV_FOREACH(i
, arg_system_units
) {
1617 _cleanup_free_
char *u
= NULL
;
1619 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1623 if (string_is_glob(u
)) {
1624 r
= strv_push(&patterns
, u
);
1629 r
= add_matches_for_unit(j
, u
);
1632 r
= sd_journal_add_disjunction(j
);
1639 if (!strv_isempty(patterns
)) {
1640 _cleanup_set_free_free_ Set
*units
= NULL
;
1643 r
= get_possible_units(j
, SYSTEM_UNITS
, patterns
, &units
);
1647 SET_FOREACH(u
, units
) {
1648 r
= add_matches_for_unit(j
, u
);
1651 r
= sd_journal_add_disjunction(j
);
1658 patterns
= strv_free(patterns
);
1660 STRV_FOREACH(i
, arg_user_units
) {
1661 _cleanup_free_
char *u
= NULL
;
1663 r
= unit_name_mangle(*i
, UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
), &u
);
1667 if (string_is_glob(u
)) {
1668 r
= strv_push(&patterns
, u
);
1673 r
= add_matches_for_user_unit(j
, u
, getuid());
1676 r
= sd_journal_add_disjunction(j
);
1683 if (!strv_isempty(patterns
)) {
1684 _cleanup_set_free_free_ Set
*units
= NULL
;
1687 r
= get_possible_units(j
, USER_UNITS
, patterns
, &units
);
1691 SET_FOREACH(u
, units
) {
1692 r
= add_matches_for_user_unit(j
, u
, getuid());
1695 r
= sd_journal_add_disjunction(j
);
1702 /* Complain if the user request matches but nothing whatsoever was
1703 * found, since otherwise everything would be matched. */
1704 if (!(strv_isempty(arg_system_units
) && strv_isempty(arg_user_units
)) && count
== 0)
1707 r
= sd_journal_add_conjunction(j
);
1714 static int add_priorities(sd_journal
*j
) {
1715 char match
[] = "PRIORITY=0";
1719 if (arg_priorities
== 0xFF)
1722 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
1723 if (arg_priorities
& (1 << i
)) {
1724 match
[sizeof(match
)-2] = '0' + i
;
1726 r
= sd_journal_add_match(j
, match
, strlen(match
));
1728 return log_error_errno(r
, "Failed to add match: %m");
1731 r
= sd_journal_add_conjunction(j
);
1733 return log_error_errno(r
, "Failed to add conjunction: %m");
1738 static int add_facilities(sd_journal
*j
) {
1742 SET_FOREACH(p
, arg_facilities
) {
1743 char match
[STRLEN("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
1745 xsprintf(match
, "SYSLOG_FACILITY=%d", PTR_TO_INT(p
));
1747 r
= sd_journal_add_match(j
, match
, strlen(match
));
1749 return log_error_errno(r
, "Failed to add match: %m");
1755 static int add_syslog_identifier(sd_journal
*j
) {
1761 STRV_FOREACH(i
, arg_syslog_identifier
) {
1762 _cleanup_free_
char *u
= NULL
;
1764 u
= strjoin("SYSLOG_IDENTIFIER=", *i
);
1767 r
= sd_journal_add_match(j
, u
, 0);
1770 r
= sd_journal_add_disjunction(j
);
1775 r
= sd_journal_add_conjunction(j
);
1783 static int format_journal_url(
1792 _cleanup_free_
char *url
= NULL
;
1793 _cleanup_fclose_
FILE *f
= NULL
;
1794 size_t url_size
= 0;
1798 assert(seed_size
> 0);
1800 f
= open_memstream_unlocked(&url
, &url_size
);
1807 for (size_t i
= 0; i
< seed_size
; i
++) {
1808 if (i
> 0 && i
% 3 == 0)
1810 fprintf(f
, "%02x", ((uint8_t*) seed
)[i
]);
1813 fprintf(f
, "/%"PRIx64
"-%"PRIx64
, start
, interval
);
1816 fprintf(f
, "?machine=" SD_ID128_FORMAT_STR
, SD_ID128_FORMAT_VAL(machine
));
1818 fprintf(f
, ";hostname=%s", hn
);
1821 r
= fflush_and_check(f
);
1826 *ret_url
= TAKE_PTR(url
);
1831 static int setup_keys(void) {
1833 size_t mpk_size
, seed_size
, state_size
;
1834 _cleanup_(unlink_and_freep
) char *k
= NULL
;
1835 _cleanup_free_
char *p
= NULL
;
1836 uint8_t *mpk
, *seed
, *state
;
1837 _cleanup_close_
int fd
= -1;
1838 sd_id128_t machine
, boot
;
1843 r
= stat("/var/log/journal", &st
);
1844 if (r
< 0 && !IN_SET(errno
, ENOENT
, ENOTDIR
))
1845 return log_error_errno(errno
, "stat(\"%s\") failed: %m", "/var/log/journal");
1847 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
1848 log_error("%s is not a directory, must be using persistent logging for FSS.",
1849 "/var/log/journal");
1850 return r
< 0 ? -errno
: -ENOTDIR
;
1853 r
= sd_id128_get_machine(&machine
);
1855 return log_error_errno(r
, "Failed to get machine ID: %m");
1857 r
= sd_id128_get_boot(&boot
);
1859 return log_error_errno(r
, "Failed to get boot ID: %m");
1861 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
1862 SD_ID128_FORMAT_VAL(machine
)) < 0)
1867 if (r
< 0 && errno
!= ENOENT
)
1868 return log_error_errno(errno
, "unlink(\"%s\") failed: %m", p
);
1869 } else if (access(p
, F_OK
) >= 0)
1870 return log_error_errno(SYNTHETIC_ERRNO(EEXIST
),
1871 "Sealing key file %s exists already. Use --force to recreate.", p
);
1873 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
1874 SD_ID128_FORMAT_VAL(machine
)) < 0)
1877 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
1878 mpk
= alloca(mpk_size
);
1880 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
1881 seed
= alloca(seed_size
);
1883 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1884 state
= alloca(state_size
);
1886 log_info("Generating seed...");
1887 r
= genuine_random_bytes(seed
, seed_size
, RANDOM_BLOCK
);
1889 return log_error_errno(r
, "Failed to acquire random seed: %m");
1891 log_info("Generating key pair...");
1892 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1894 log_info("Generating sealing key...");
1895 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1897 assert(arg_interval
> 0);
1899 n
= now(CLOCK_REALTIME
);
1903 fd
= mkostemp_safe(k
);
1905 return log_error_errno(fd
, "Failed to open %s: %m", k
);
1907 /* Enable secure remove, exclusion from dump, synchronous writing and in-place updating */
1908 static const unsigned chattr_flags
[] = {
1914 for (size_t j
= 0; j
< ELEMENTSOF(chattr_flags
); j
++) {
1915 r
= chattr_fd(fd
, chattr_flags
[j
], chattr_flags
[j
], NULL
);
1917 log_full_errno(ERRNO_IS_NOT_SUPPORTED(r
) ? LOG_DEBUG
: LOG_WARNING
, r
,
1918 "Failed to set file attribute 0x%x: %m", chattr_flags
[j
]);
1921 struct FSSHeader h
= {
1922 .signature
= { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' },
1923 .machine_id
= machine
,
1925 .header_size
= htole64(sizeof(h
)),
1926 .start_usec
= htole64(n
* arg_interval
),
1927 .interval_usec
= htole64(arg_interval
),
1928 .fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
),
1929 .fsprg_state_size
= htole64(state_size
),
1932 r
= loop_write(fd
, &h
, sizeof(h
), false);
1934 return log_error_errno(r
, "Failed to write header: %m");
1936 r
= loop_write(fd
, state
, state_size
, false);
1938 return log_error_errno(r
, "Failed to write state: %m");
1940 if (rename(k
, p
) < 0)
1941 return log_error_errno(errno
, "Failed to link file: %m");
1945 _cleanup_free_
char *hn
= NULL
, *key
= NULL
;
1947 r
= format_journal_url(seed
, seed_size
, n
, arg_interval
, hn
, machine
, false, &key
);
1952 hn
= gethostname_malloc();
1954 hostname_cleanup(hn
);
1956 char tsb
[FORMAT_TIMESPAN_MAX
];
1958 "\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR
".\n"
1960 "The %ssecret sealing key%s has been written to the following local file.\n"
1961 "This key file is automatically updated when the sealing key is advanced.\n"
1962 "It should not be used on multiple hosts.\n"
1966 "The sealing key is automatically changed every %s.\n"
1968 "Please write down the following %ssecret verification key%s. It should be stored\n"
1969 "in a safe location and should not be saved locally on disk.\n"
1971 strempty(hn
), hn
? "/" : "",
1972 SD_ID128_FORMAT_VAL(machine
),
1973 ansi_highlight(), ansi_normal(),
1975 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0),
1976 ansi_highlight(), ansi_normal(),
1977 ansi_highlight_red());
1984 fprintf(stderr
, "%s", ansi_normal());
1986 _cleanup_free_
char *url
= NULL
;
1987 r
= format_journal_url(seed
, seed_size
, n
, arg_interval
, hn
, machine
, true, &url
);
1991 (void) print_qrcode(stderr
,
1992 "To transfer the verification key to your phone scan the QR code below",
1999 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2000 "Forward-secure sealing not available.");
2004 static int verify(sd_journal
*j
) {
2010 log_show_color(true);
2012 ORDERED_HASHMAP_FOREACH(f
, j
->files
) {
2014 usec_t first
= 0, validated
= 0, last
= 0;
2017 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
2018 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
2021 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
2023 /* If the key was invalid give up right-away. */
2026 r
= log_warning_errno(k
, "FAIL: %s (%m)", f
->path
);
2028 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
2029 log_info("PASS: %s", f
->path
);
2031 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
2032 if (validated
> 0) {
2033 log_info("=> Validated from %s to %s, final %s entries not sealed.",
2034 format_timestamp_maybe_utc(a
, sizeof(a
), first
),
2035 format_timestamp_maybe_utc(b
, sizeof(b
), validated
),
2036 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
2037 } else if (last
> 0)
2038 log_info("=> No sealing yet, %s of entries not sealed.",
2039 format_timespan(c
, sizeof(c
), last
- first
, 0));
2041 log_info("=> No sealing yet, no entries in file.");
2049 static int simple_varlink_call(const char *option
, const char *method
) {
2050 _cleanup_(varlink_flush_close_unrefp
) Varlink
*link
= NULL
;
2051 const char *error
, *fn
;
2055 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "%s is not supported in conjunction with --machine=.", option
);
2057 fn
= arg_namespace
?
2058 strjoina("/run/systemd/journal.", arg_namespace
, "/io.systemd.journal") :
2059 "/run/systemd/journal/io.systemd.journal";
2061 r
= varlink_connect_address(&link
, fn
);
2063 return log_error_errno(r
, "Failed to connect to %s: %m", fn
);
2065 (void) varlink_set_description(link
, "journal");
2066 (void) varlink_set_relative_timeout(link
, USEC_INFINITY
);
2068 r
= varlink_call(link
, method
, NULL
, NULL
, &error
, NULL
);
2070 return log_error_errno(r
, "Failed to execute varlink call: %m");
2072 return log_error_errno(SYNTHETIC_ERRNO(ENOANO
),
2073 "Failed to execute varlink call: %s", error
);
2078 static int flush_to_var(void) {
2079 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
2082 static int relinquish_var(void) {
2083 return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
2086 static int rotate(void) {
2087 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
2090 static int sync_journal(void) {
2091 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
2094 static int wait_for_change(sd_journal
*j
, int poll_fd
) {
2095 struct pollfd pollfds
[] = {
2096 { .fd
= poll_fd
, .events
= POLLIN
},
2097 { .fd
= STDOUT_FILENO
},
2105 assert(poll_fd
>= 0);
2107 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
2108 * i.e. when it is closed. */
2110 r
= sd_journal_get_timeout(j
, &timeout
);
2112 return log_error_errno(r
, "Failed to determine journal waiting time: %m");
2114 if (ppoll(pollfds
, ELEMENTSOF(pollfds
),
2115 timeout
== USEC_INFINITY
? NULL
: timespec_store(&ts
, timeout
), NULL
) < 0) {
2119 return log_error_errno(errno
, "Couldn't wait for journal event: %m");
2122 if (pollfds
[1].revents
& (POLLHUP
|POLLERR
|POLLNVAL
)) /* STDOUT has been closed? */
2123 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED
),
2124 "Standard output has been closed.");
2126 if (pollfds
[0].revents
& POLLNVAL
)
2127 return log_debug_errno(SYNTHETIC_ERRNO(EBADF
), "Change fd closed?");
2129 r
= sd_journal_process(j
);
2131 return log_error_errno(r
, "Failed to process journal events: %m");
2136 int main(int argc
, char *argv
[]) {
2137 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
2138 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*decrypted_image
= NULL
;
2139 _cleanup_(umount_and_rmdir_and_freep
) char *unlink_dir
= NULL
;
2140 bool previous_boot_id_valid
= false, first_line
= true, ellipsized
= false, need_seek
= false;
2141 bool use_cursor
= false, after_cursor
= false;
2142 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2143 sd_id128_t previous_boot_id
;
2144 int n_shown
= 0, r
, poll_fd
= -1;
2146 setlocale(LC_ALL
, "");
2149 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2150 * split up into many files. */
2151 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE
);
2153 r
= parse_argv(argc
, argv
);
2160 r
= mount_image_privately_interactively(
2162 DISSECT_IMAGE_REQUIRE_ROOT
|DISSECT_IMAGE_VALIDATE_OS
|DISSECT_IMAGE_RELAX_VAR_CHECK
|
2163 (arg_action
== ACTION_UPDATE_CATALOG
? DISSECT_IMAGE_FSCK
: DISSECT_IMAGE_READ_ONLY
),
2170 arg_root
= strdup(unlink_dir
);
2175 signal(SIGWINCH
, columns_lines_cache_reset
);
2178 switch (arg_action
) {
2180 case ACTION_NEW_ID128
:
2181 r
= id128_print_new(ID128_PRINT_PRETTY
);
2184 case ACTION_SETUP_KEYS
:
2188 case ACTION_LIST_CATALOG
:
2189 case ACTION_DUMP_CATALOG
:
2190 case ACTION_UPDATE_CATALOG
: {
2191 _cleanup_free_
char *database
;
2193 database
= path_join(arg_root
, CATALOG_DATABASE
);
2199 if (arg_action
== ACTION_UPDATE_CATALOG
) {
2200 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
2202 log_error_errno(r
, "Failed to list catalog: %m");
2204 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
2206 (void) pager_open(arg_pager_flags
);
2209 r
= catalog_list_items(stdout
, database
, oneline
, argv
+ optind
);
2211 r
= catalog_list(stdout
, database
, oneline
);
2213 log_error_errno(r
, "Failed to list catalog: %m");
2223 case ACTION_RELINQUISH_VAR
:
2224 r
= relinquish_var();
2236 case ACTION_PRINT_HEADER
:
2238 case ACTION_DISK_USAGE
:
2239 case ACTION_LIST_BOOTS
:
2241 case ACTION_ROTATE_AND_VACUUM
:
2242 case ACTION_LIST_FIELDS
:
2243 case ACTION_LIST_FIELD_NAMES
:
2244 /* These ones require access to the journal files, continue below. */
2248 assert_not_reached("Unknown action");
2252 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
2254 r
= sd_journal_open_directory(&j
, arg_root
, arg_journal_type
| SD_JOURNAL_OS_ROOT
);
2255 else if (arg_file_stdin
)
2256 r
= sd_journal_open_files_fd(&j
, (int[]) { STDIN_FILENO
}, 1, 0);
2258 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
2259 else if (arg_machine
) {
2260 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2261 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2262 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2265 if (geteuid() != 0) {
2266 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2267 * the container, thus we need root privileges to override them. */
2268 r
= log_error_errno(SYNTHETIC_ERRNO(EPERM
), "Using the --machine= switch requires root privileges.");
2272 r
= sd_bus_open_system(&bus
);
2274 log_error_errno(r
, "Failed to open system bus: %m");
2278 r
= sd_bus_call_method(
2280 "org.freedesktop.machine1",
2281 "/org/freedesktop/machine1",
2282 "org.freedesktop.machine1.Manager",
2283 "OpenMachineRootDirectory",
2288 log_error_errno(r
, "Failed to open root directory: %s", bus_error_message(&error
, r
));
2292 r
= sd_bus_message_read(reply
, "h", &fd
);
2294 bus_log_parse_error(r
);
2298 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
2300 r
= log_error_errno(errno
, "Failed to duplicate file descriptor: %m");
2304 r
= sd_journal_open_directory_fd(&j
, fd
, SD_JOURNAL_OS_ROOT
);
2308 r
= sd_journal_open_namespace(
2311 (arg_merge
? 0 : SD_JOURNAL_LOCAL_ONLY
) |
2312 arg_namespace_flags
| arg_journal_type
);
2314 log_error_errno(r
, "Failed to open %s: %m", arg_directory
?: arg_file
? "files" : "journal");
2318 r
= journal_access_check_and_warn(j
, arg_quiet
,
2319 !(arg_journal_type
== SD_JOURNAL_CURRENT_USER
|| arg_user_units
));
2323 switch (arg_action
) {
2325 case ACTION_NEW_ID128
:
2326 case ACTION_SETUP_KEYS
:
2327 case ACTION_LIST_CATALOG
:
2328 case ACTION_DUMP_CATALOG
:
2329 case ACTION_UPDATE_CATALOG
:
2333 assert_not_reached("Unexpected action.");
2335 case ACTION_PRINT_HEADER
:
2336 journal_print_header(j
);
2344 case ACTION_DISK_USAGE
: {
2346 char sbytes
[FORMAT_BYTES_MAX
];
2348 r
= sd_journal_get_usage(j
, &bytes
);
2352 printf("Archived and active journals take up %s in the file system.\n",
2353 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
2357 case ACTION_LIST_BOOTS
:
2361 case ACTION_ROTATE_AND_VACUUM
:
2369 case ACTION_VACUUM
: {
2372 HASHMAP_FOREACH(d
, j
->directories_by_path
) {
2375 q
= journal_directory_vacuum(d
->path
, arg_vacuum_size
, arg_vacuum_n_files
, arg_vacuum_time
, NULL
, !arg_quiet
);
2377 r
= log_error_errno(q
, "Failed to vacuum %s: %m", d
->path
);
2383 case ACTION_LIST_FIELD_NAMES
: {
2386 SD_JOURNAL_FOREACH_FIELD(j
, field
) {
2387 printf("%s\n", field
);
2396 case ACTION_LIST_FIELDS
:
2400 assert_not_reached("Unknown action");
2403 if (arg_boot_offset
!= 0 &&
2404 sd_journal_has_runtime_files(j
) > 0 &&
2405 sd_journal_has_persistent_files(j
) == 0) {
2406 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
2410 /* add_boot() must be called first!
2411 * It may need to seek the journal to find parent boot IDs. */
2422 log_error_errno(r
, "Failed to add filter for units: %m");
2426 r
= add_syslog_identifier(j
);
2428 log_error_errno(r
, "Failed to add filter for syslog identifiers: %m");
2432 r
= add_priorities(j
);
2436 r
= add_facilities(j
);
2440 r
= add_matches(j
, argv
+ optind
);
2444 if (DEBUG_LOGGING
) {
2445 _cleanup_free_
char *filter
;
2447 filter
= journal_make_match_string(j
);
2451 log_debug("Journal filter: %s", filter
);
2454 if (arg_action
== ACTION_LIST_FIELDS
) {
2460 r
= sd_journal_set_data_threshold(j
, 0);
2462 log_error_errno(r
, "Failed to unset data size threshold: %m");
2466 r
= sd_journal_query_unique(j
, arg_field
);
2468 log_error_errno(r
, "Failed to query unique data objects: %m");
2472 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
2475 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
2478 eq
= memchr(data
, '=', size
);
2480 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
2482 printf("%.*s\n", (int) size
, (const char*) data
);
2491 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2493 poll_fd
= sd_journal_get_fd(j
);
2494 if (poll_fd
== -EMFILE
) {
2495 log_warning_errno(poll_fd
, "Insufficient watch descriptors available. Reverting to -n.");
2497 } else if (poll_fd
== -EMEDIUMTYPE
) {
2498 log_error_errno(poll_fd
, "The --follow switch is not supported in conjunction with reading from STDIN.");
2500 } else if (poll_fd
< 0) {
2501 log_error_errno(poll_fd
, "Failed to get journal fd: %m");
2506 if (arg_cursor
|| arg_after_cursor
|| arg_cursor_file
) {
2507 _cleanup_free_
char *cursor_from_file
= NULL
;
2508 const char *cursor
= arg_cursor
?: arg_after_cursor
;
2510 if (arg_cursor_file
) {
2511 r
= read_one_line_file(arg_cursor_file
, &cursor_from_file
);
2512 if (r
< 0 && r
!= -ENOENT
) {
2513 log_error_errno(r
, "Failed to read cursor file %s: %m", arg_cursor_file
);
2518 cursor
= cursor_from_file
;
2519 after_cursor
= true;
2522 after_cursor
= arg_after_cursor
;
2525 r
= sd_journal_seek_cursor(j
, cursor
);
2527 log_error_errno(r
, "Failed to seek to cursor: %m");
2536 r
= sd_journal_next_skip(j
, 1 + after_cursor
);
2538 r
= sd_journal_previous_skip(j
, 1 + after_cursor
);
2540 if (after_cursor
&& r
< 2) {
2541 /* We couldn't find the next entry after the cursor. */
2548 } else if (arg_since_set
&& !arg_reverse
) {
2549 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
2551 log_error_errno(r
, "Failed to seek to date: %m");
2554 r
= sd_journal_next(j
);
2556 } else if (arg_until_set
&& arg_reverse
) {
2557 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
2559 log_error_errno(r
, "Failed to seek to date: %m");
2562 r
= sd_journal_previous(j
);
2564 } else if (arg_reverse
) {
2565 r
= sd_journal_seek_tail(j
);
2567 log_error_errno(r
, "Failed to seek to tail: %m");
2571 r
= sd_journal_previous(j
);
2573 } else if (arg_lines
>= 0) {
2574 r
= sd_journal_seek_tail(j
);
2576 log_error_errno(r
, "Failed to seek to tail: %m");
2580 r
= sd_journal_previous_skip(j
, arg_lines
);
2583 r
= sd_journal_seek_head(j
);
2585 log_error_errno(r
, "Failed to seek to head: %m");
2589 r
= sd_journal_next(j
);
2593 log_error_errno(r
, "Failed to iterate through journal: %m");
2600 (void) pager_open(arg_pager_flags
);
2602 if (!arg_quiet
&& (arg_lines
!= 0 || arg_follow
)) {
2604 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
2606 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
2608 log_error_errno(r
, "Failed to get cutoff: %m");
2614 printf("-- Journal begins at %s. --\n",
2615 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
));
2617 printf("-- Journal begins at %s, ends at %s. --\n",
2618 format_timestamp_maybe_utc(start_buf
, sizeof(start_buf
), start
),
2619 format_timestamp_maybe_utc(end_buf
, sizeof(end_buf
), end
));
2624 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
2626 size_t highlight
[2] = {};
2630 r
= sd_journal_next(j
);
2632 r
= sd_journal_previous(j
);
2634 log_error_errno(r
, "Failed to iterate through journal: %m");
2641 if (arg_until_set
&& !arg_reverse
) {
2644 r
= sd_journal_get_realtime_usec(j
, &usec
);
2646 log_error_errno(r
, "Failed to determine timestamp: %m");
2649 if (usec
> arg_until
)
2653 if (arg_since_set
&& arg_reverse
) {
2656 r
= sd_journal_get_realtime_usec(j
, &usec
);
2658 log_error_errno(r
, "Failed to determine timestamp: %m");
2661 if (usec
< arg_since
)
2665 if (!arg_merge
&& !arg_quiet
) {
2668 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
2670 if (previous_boot_id_valid
&&
2671 !sd_id128_equal(boot_id
, previous_boot_id
))
2672 printf("%s-- Boot "SD_ID128_FORMAT_STR
" --%s\n",
2673 ansi_highlight(), SD_ID128_FORMAT_VAL(boot_id
), ansi_normal());
2675 previous_boot_id
= boot_id
;
2676 previous_boot_id_valid
= true;
2681 if (arg_compiled_pattern
) {
2682 _cleanup_(sym_pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
2683 const void *message
;
2687 md
= sym_pcre2_match_data_create(1, NULL
);
2691 r
= sd_journal_get_data(j
, "MESSAGE", &message
, &len
);
2698 log_error_errno(r
, "Failed to get MESSAGE field: %m");
2702 assert_se(message
= startswith(message
, "MESSAGE="));
2704 r
= sym_pcre2_match(arg_compiled_pattern
,
2706 len
- strlen("MESSAGE="),
2707 0, /* start at offset 0 in the subject */
2708 0, /* default options */
2711 if (r
== PCRE2_ERROR_NOMATCH
) {
2716 unsigned char buf
[LINE_MAX
];
2719 r2
= sym_pcre2_get_error_message(r
, buf
, sizeof buf
);
2720 log_error("Pattern matching failed: %s",
2721 r2
< 0 ? "unknown error" : (char*) buf
);
2726 ovec
= sym_pcre2_get_ovector_pointer(md
);
2727 highlight
[0] = ovec
[0];
2728 highlight
[1] = ovec
[1];
2733 arg_all
* OUTPUT_SHOW_ALL
|
2734 arg_full
* OUTPUT_FULL_WIDTH
|
2735 colors_enabled() * OUTPUT_COLOR
|
2736 arg_catalog
* OUTPUT_CATALOG
|
2737 arg_utc
* OUTPUT_UTC
|
2738 arg_no_hostname
* OUTPUT_NO_HOSTNAME
;
2740 r
= show_journal_entry(stdout
, j
, arg_output
, 0, flags
,
2741 arg_output_fields
, highlight
, &ellipsized
);
2743 if (r
== -EADDRNOTAVAIL
)
2750 /* If journalctl take a long time to process messages, and during that time journal file
2751 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2752 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2753 * in the "following" case. By periodically calling sd_journal_process() during the processing
2754 * loop we shrink the window of time a client instance has open file descriptors for rotated
2755 * (deleted) journal files. */
2756 if ((n_shown
% PROCESS_INOTIFY_INTERVAL
) == 0) {
2757 r
= sd_journal_process(j
);
2759 log_error_errno(r
, "Failed to process inotify events: %m");
2766 if (n_shown
== 0 && !arg_quiet
)
2767 printf("-- No entries --\n");
2773 r
= wait_for_change(j
, poll_fd
);
2780 if (arg_show_cursor
|| arg_cursor_file
) {
2781 _cleanup_free_
char *cursor
= NULL
;
2783 r
= sd_journal_get_cursor(j
, &cursor
);
2784 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
2785 log_error_errno(r
, "Failed to get cursor: %m");
2787 if (arg_show_cursor
)
2788 printf("-- cursor: %s\n", cursor
);
2790 if (arg_cursor_file
) {
2791 r
= write_string_file(arg_cursor_file
, cursor
,
2792 WRITE_STRING_FILE_CREATE
|
2793 WRITE_STRING_FILE_ATOMIC
);
2796 "Failed to write new cursor to %s: %m",
2805 strv_free(arg_file
);
2807 set_free(arg_facilities
);
2808 strv_free(arg_syslog_identifier
);
2809 strv_free(arg_system_units
);
2810 strv_free(arg_user_units
);
2811 strv_free(arg_output_fields
);
2814 free(arg_verify_key
);
2817 if (arg_compiled_pattern
) {
2818 sym_pcre2_code_free(arg_compiled_pattern
);
2820 /* --grep was used, no error was thrown, but the pattern didn't
2821 * match anything. Let's mimic grep's behavior here and return
2822 * a non-zero exit code, so journalctl --grep can be used
2823 * in scripts and such */
2824 if (r
== 0 && n_shown
== 0)
2829 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;