1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "sd-journal.h"
9 #include "dissect-image.h"
10 #include "extract-word.h"
11 #include "glob-util.h"
12 #include "id128-print.h"
13 #include "image-policy.h"
14 #include "journalctl.h"
15 #include "journalctl-authenticate.h"
16 #include "journalctl-catalog.h"
17 #include "journalctl-misc.h"
18 #include "journalctl-show.h"
19 #include "journalctl-varlink.h"
21 #include "loop-util.h"
22 #include "main-func.h"
23 #include "mount-util.h"
24 #include "mountpoint-util.h"
25 #include "output-mode.h"
27 #include "parse-argument.h"
28 #include "parse-util.h"
29 #include "pcre2-util.h"
30 #include "pretty-print.h"
32 #include "static-destruct.h"
33 #include "string-table.h"
34 #include "string-util.h"
36 #include "syslog-util.h"
37 #include "time-util.h"
39 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
42 /* Special values for arg_lines */
43 ARG_LINES_DEFAULT
= -2,
47 JournalctlAction arg_action
= ACTION_SHOW
;
48 OutputMode arg_output
= OUTPUT_SHORT
;
49 sd_json_format_flags_t arg_json_format_flags
= SD_JSON_FORMAT_OFF
;
50 PagerFlags arg_pager_flags
= 0;
52 bool arg_follow
= false;
55 int arg_lines
= ARG_LINES_DEFAULT
;
56 bool arg_lines_oldest
= false;
57 bool arg_no_tail
= false;
58 bool arg_truncate_newline
= false;
59 bool arg_quiet
= false;
60 bool arg_merge
= false;
61 int arg_boot
= -1; /* tristate */
62 sd_id128_t arg_boot_id
= {};
63 int arg_boot_offset
= 0;
64 bool arg_dmesg
= false;
65 bool arg_no_hostname
= false;
66 char *arg_cursor
= NULL
;
67 char *arg_cursor_file
= NULL
;
68 char *arg_after_cursor
= NULL
;
69 bool arg_show_cursor
= false;
70 char *arg_directory
= NULL
;
71 char **arg_file
= NULL
;
72 bool arg_file_stdin
= false;
73 int arg_priorities
= 0;
74 Set
*arg_facilities
= NULL
;
75 char *arg_verify_key
= NULL
;
77 usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
78 bool arg_force
= false;
82 bool arg_since_set
= false;
83 bool arg_until_set
= false;
84 char **arg_syslog_identifier
= NULL
;
85 char **arg_exclude_identifier
= NULL
;
86 char **arg_system_units
= NULL
;
87 char **arg_user_units
= NULL
;
88 bool arg_invocation
= false;
89 sd_id128_t arg_invocation_id
= SD_ID128_NULL
;
90 int arg_invocation_offset
= 0;
91 char *arg_field
= NULL
;
92 bool arg_catalog
= false;
93 bool arg_reverse
= false;
94 int arg_journal_type
= 0;
95 int arg_journal_additional_open_flags
= 0;
96 int arg_namespace_flags
= 0;
97 char *arg_root
= NULL
;
98 char *arg_image
= NULL
;
99 char *arg_machine
= NULL
;
100 char *arg_namespace
= NULL
;
101 uint64_t arg_vacuum_size
= 0;
102 uint64_t arg_vacuum_n_files
= 0;
103 usec_t arg_vacuum_time
= 0;
104 Set
*arg_output_fields
= NULL
;
105 char *arg_pattern
= NULL
;
106 pcre2_code
*arg_compiled_pattern
= NULL
;
107 PatternCompileCase arg_case
= PATTERN_COMPILE_CASE_AUTO
;
108 ImagePolicy
*arg_image_policy
= NULL
;
109 bool arg_synchronize_on_exit
= false;
111 STATIC_DESTRUCTOR_REGISTER(arg_cursor
, freep
);
112 STATIC_DESTRUCTOR_REGISTER(arg_cursor_file
, freep
);
113 STATIC_DESTRUCTOR_REGISTER(arg_after_cursor
, freep
);
114 STATIC_DESTRUCTOR_REGISTER(arg_directory
, freep
);
115 STATIC_DESTRUCTOR_REGISTER(arg_file
, strv_freep
);
116 STATIC_DESTRUCTOR_REGISTER(arg_facilities
, set_freep
);
117 STATIC_DESTRUCTOR_REGISTER(arg_verify_key
, erase_and_freep
);
118 STATIC_DESTRUCTOR_REGISTER(arg_syslog_identifier
, strv_freep
);
119 STATIC_DESTRUCTOR_REGISTER(arg_exclude_identifier
, strv_freep
);
120 STATIC_DESTRUCTOR_REGISTER(arg_system_units
, strv_freep
);
121 STATIC_DESTRUCTOR_REGISTER(arg_user_units
, strv_freep
);
122 STATIC_DESTRUCTOR_REGISTER(arg_field
, freep
);
123 STATIC_DESTRUCTOR_REGISTER(arg_root
, freep
);
124 STATIC_DESTRUCTOR_REGISTER(arg_image
, freep
);
125 STATIC_DESTRUCTOR_REGISTER(arg_machine
, freep
);
126 STATIC_DESTRUCTOR_REGISTER(arg_namespace
, freep
);
127 STATIC_DESTRUCTOR_REGISTER(arg_output_fields
, set_freep
);
128 STATIC_DESTRUCTOR_REGISTER(arg_pattern
, freep
);
129 STATIC_DESTRUCTOR_REGISTER(arg_compiled_pattern
, pattern_freep
);
130 STATIC_DESTRUCTOR_REGISTER(arg_image_policy
, image_policy_freep
);
132 static int parse_id_descriptor(const char *x
, sd_id128_t
*ret_id
, int *ret_offset
) {
133 sd_id128_t id
= SD_ID128_NULL
;
140 if (streq(x
, "all")) {
141 *ret_id
= SD_ID128_NULL
;
146 if (strlen(x
) >= SD_ID128_STRING_MAX
- 1) {
149 t
= strndupa_safe(x
, SD_ID128_STRING_MAX
- 1);
150 r
= sd_id128_from_string(t
, &id
);
152 x
+= SD_ID128_STRING_MAX
- 1;
154 if (!IN_SET(*x
, 0, '-', '+'))
158 r
= safe_atoi(x
, &off
);
163 r
= safe_atoi(x
, &off
);
173 static int parse_lines(const char *arg
, bool graceful
) {
177 assert(arg
|| graceful
);
182 if (streq(arg
, "all")) {
183 arg_lines
= ARG_LINES_ALL
;
187 l
= startswith(arg
, "+");
189 r
= safe_atoi(l
?: arg
, &n
);
190 if (r
< 0 || n
< 0) {
194 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse --lines='%s'.", arg
);
198 arg_lines_oldest
= l
;
204 arg_lines_oldest
= false;
208 static int help_facilities(void) {
210 puts("Available facilities:");
212 for (int i
= 0; i
< LOG_NFACILITIES
; i
++) {
213 _cleanup_free_
char *t
= NULL
;
215 if (log_facility_unshifted_to_string_alloc(i
, &t
) < 0)
223 static int help(void) {
224 _cleanup_free_
char *link
= NULL
;
227 pager_open(arg_pager_flags
);
229 r
= terminal_urlify_man("journalctl", "1", &link
);
233 printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
234 "%5$sQuery the journal.%6$s\n\n"
235 "%3$sSource Options:%4$s\n"
236 " --system Show the system journal\n"
237 " --user Show the user journal for the current user\n"
238 " -M --machine=CONTAINER Operate on local container\n"
239 " -m --merge Show entries from all available journals\n"
240 " -D --directory=PATH Show journal files from directory\n"
241 " -i --file=PATH Show journal file\n"
242 " --root=PATH Operate on an alternate filesystem root\n"
243 " --image=PATH Operate on disk image as filesystem root\n"
244 " --image-policy=POLICY Specify disk image dissection policy\n"
245 " --namespace=NAMESPACE Show journal data from specified journal namespace\n"
246 "\n%3$sFiltering Options:%4$s\n"
247 " -S --since=DATE Show entries not older than the specified date\n"
248 " -U --until=DATE Show entries not newer than the specified date\n"
249 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
250 " --after-cursor=CURSOR Show entries after the specified cursor\n"
251 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
252 " -b --boot[=ID] Show current boot or the specified boot\n"
253 " -u --unit=UNIT Show logs from the specified unit\n"
254 " --user-unit=UNIT Show logs from the specified user unit\n"
255 " --invocation=ID Show logs from the matching invocation ID\n"
256 " -I Show logs from the latest invocation of unit\n"
257 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
258 " -T --exclude-identifier=STRING\n"
259 " Hide entries with the specified syslog identifier\n"
260 " -p --priority=RANGE Show entries within the specified priority range\n"
261 " --facility=FACILITY... Show entries with the specified facilities\n"
262 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
263 " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
264 " -k --dmesg Show kernel message log from the current boot\n"
265 "\n%3$sOutput Control Options:%4$s\n"
266 " -o --output=STRING Change journal output mode (short, short-precise,\n"
267 " short-iso, short-iso-precise, short-full,\n"
268 " short-monotonic, short-unix, verbose, export,\n"
269 " json, json-pretty, json-sse, json-seq, cat,\n"
271 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
272 " -n --lines[=[+]INTEGER] Number of journal entries to show\n"
273 " -r --reverse Show the newest entries first\n"
274 " --show-cursor Print the cursor after all the entries\n"
275 " --utc Express time in Coordinated Universal Time (UTC)\n"
276 " -x --catalog Add message explanations where available\n"
277 " --no-hostname Suppress output of hostname field\n"
278 " --no-full Ellipsize fields\n"
279 " -a --all Show all fields, including long and unprintable\n"
280 " -f --follow Follow the journal\n"
281 " --no-tail Show all lines, even in follow mode\n"
282 " --truncate-newline Truncate entries by first newline character\n"
283 " -q --quiet Do not show info messages and privilege warning\n"
284 " --synchronize-on-exit=BOOL\n"
285 " Wait for Journal synchronization before exiting\n"
286 "\n%3$sPager Control Options:%4$s\n"
287 " --no-pager Do not pipe output into a pager\n"
288 " -e --pager-end Immediately jump to the end in the pager\n"
289 "\n%3$sForward Secure Sealing (FSS) Options:%4$s\n"
290 " --interval=TIME Time interval for changing the FSS sealing key\n"
291 " --verify-key=KEY Specify FSS verification key\n"
292 " --force Override of the FSS key pair with --setup-keys\n"
293 "\n%3$sCommands:%4$s\n"
294 " -h --help Show this help text\n"
295 " --version Show package version\n"
296 " -N --fields List all field names currently used\n"
297 " -F --field=FIELD List all values that a specified field takes\n"
298 " --list-boots Show terse information about recorded boots\n"
299 " --list-invocations Show invocation IDs of specified unit\n"
300 " --list-namespaces Show list of journal namespaces\n"
301 " --disk-usage Show total disk usage of all journal files\n"
302 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
303 " --vacuum-files=INT Leave only the specified number of journal files\n"
304 " --vacuum-time=TIME Remove journal files older than specified time\n"
305 " --verify Verify journal file consistency\n"
306 " --sync Synchronize unwritten journal messages to disk\n"
307 " --relinquish-var Stop logging to disk, log to temporary file system\n"
308 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
309 " --flush Flush all journal data from /run into /var\n"
310 " --rotate Request immediate rotation of the journal files\n"
311 " --header Show journal header information\n"
312 " --list-catalog Show all message IDs in the catalog\n"
313 " --dump-catalog Show entries in the message catalog\n"
314 " --update-catalog Update the message catalog database\n"
315 " --setup-keys Generate a new FSS key pair\n"
316 "\nSee the %2$s for details.\n",
317 program_invocation_short_name
,
327 static int parse_argv(int argc
, char *argv
[]) {
337 ARG_LIST_INVOCATIONS
,
364 ARG_SMART_RELINQUISH_VAR
,
366 ARG_TRUNCATE_NEWLINE
,
374 ARG_SYNCHRONIZE_ON_EXIT
,
377 static const struct option options
[] = {
378 { "help", no_argument
, NULL
, 'h' },
379 { "version" , no_argument
, NULL
, ARG_VERSION
},
380 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
381 { "pager-end", no_argument
, NULL
, 'e' },
382 { "follow", no_argument
, NULL
, 'f' },
383 { "force", no_argument
, NULL
, ARG_FORCE
},
384 { "output", required_argument
, NULL
, 'o' },
385 { "all", no_argument
, NULL
, 'a' },
386 { "full", no_argument
, NULL
, 'l' },
387 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
388 { "lines", optional_argument
, NULL
, 'n' },
389 { "truncate-newline", no_argument
, NULL
, ARG_TRUNCATE_NEWLINE
},
390 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
391 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
392 { "quiet", no_argument
, NULL
, 'q' },
393 { "merge", no_argument
, NULL
, 'm' },
394 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
395 { "boot", optional_argument
, NULL
, 'b' },
396 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
397 { "list-invocations", no_argument
, NULL
, ARG_LIST_INVOCATIONS
},
398 { "dmesg", no_argument
, NULL
, 'k' },
399 { "system", no_argument
, NULL
, ARG_SYSTEM
},
400 { "user", no_argument
, NULL
, ARG_USER
},
401 { "directory", required_argument
, NULL
, 'D' },
402 { "file", required_argument
, NULL
, 'i' },
403 { "root", required_argument
, NULL
, ARG_ROOT
},
404 { "image", required_argument
, NULL
, ARG_IMAGE
},
405 { "image-policy", required_argument
, NULL
, ARG_IMAGE_POLICY
},
406 { "header", no_argument
, NULL
, ARG_HEADER
},
407 { "identifier", required_argument
, NULL
, 't' },
408 { "exclude-identifier", required_argument
, NULL
, 'T' },
409 { "priority", required_argument
, NULL
, 'p' },
410 { "facility", required_argument
, NULL
, ARG_FACILITY
},
411 { "grep", required_argument
, NULL
, 'g' },
412 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
413 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
414 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
415 { "verify", no_argument
, NULL
, ARG_VERIFY
},
416 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
417 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
418 { "cursor", required_argument
, NULL
, 'c' },
419 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
420 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
421 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
422 { "since", required_argument
, NULL
, 'S' },
423 { "until", required_argument
, NULL
, 'U' },
424 { "unit", required_argument
, NULL
, 'u' },
425 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
426 { "invocation", required_argument
, NULL
, ARG_INVOCATION
},
427 { "field", required_argument
, NULL
, 'F' },
428 { "fields", no_argument
, NULL
, 'N' },
429 { "catalog", no_argument
, NULL
, 'x' },
430 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
431 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
432 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
433 { "reverse", no_argument
, NULL
, 'r' },
434 { "machine", required_argument
, NULL
, 'M' },
435 { "utc", no_argument
, NULL
, ARG_UTC
},
436 { "flush", no_argument
, NULL
, ARG_FLUSH
},
437 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
438 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
439 { "sync", no_argument
, NULL
, ARG_SYNC
},
440 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
441 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
442 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
443 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
444 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
445 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
446 { "namespace", required_argument
, NULL
, ARG_NAMESPACE
},
447 { "list-namespaces", no_argument
, NULL
, ARG_LIST_NAMESPACES
},
448 { "synchronize-on-exit", required_argument
, NULL
, ARG_SYNCHRONIZE_ON_EXIT
},
457 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:T:u:INF:xrM:i:", options
, NULL
)) >= 0)
468 arg_pager_flags
|= PAGER_DISABLE
;
472 arg_pager_flags
|= PAGER_JUMP_TO_END
;
480 if (streq(optarg
, "help")) {
481 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
485 arg_output
= output_mode_from_string(optarg
);
487 return log_error_errno(arg_output
, "Unknown output format '%s'.", optarg
);
489 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
492 if (OUTPUT_MODE_IS_JSON(arg_output
))
493 arg_json_format_flags
= output_mode_to_json_format_flags(arg_output
) | SD_JSON_FORMAT_COLOR_AUTO
;
495 arg_json_format_flags
= SD_JSON_FORMAT_OFF
;
512 r
= parse_lines(optarg
?: argv
[optind
], !optarg
);
515 if (r
> 0 && !optarg
)
524 case ARG_TRUNCATE_NEWLINE
:
525 arg_truncate_newline
= true;
529 arg_action
= ACTION_NEW_ID128
;
542 arg_boot_id
= SD_ID128_NULL
;
548 arg_boot_id
= SD_ID128_NULL
;
552 r
= parse_id_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
554 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
558 } else if (optind
< argc
) {
559 /* Hmm, no argument? Maybe the next word on the command line is supposed to be the
560 * argument? Let's see if there is one and is parsable as a boot descriptor... */
561 r
= parse_id_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
570 arg_action
= ACTION_LIST_BOOTS
;
573 case ARG_LIST_INVOCATIONS
:
574 arg_action
= ACTION_LIST_INVOCATIONS
;
582 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
586 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
590 r
= free_and_strdup_warn(&arg_machine
, optarg
);
596 if (streq(optarg
, "*")) {
597 arg_namespace_flags
= SD_JOURNAL_ALL_NAMESPACES
;
598 arg_namespace
= mfree(arg_namespace
);
599 } else if (startswith(optarg
, "+")) {
600 arg_namespace_flags
= SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
;
601 r
= free_and_strdup_warn(&arg_namespace
, optarg
+ 1);
604 } else if (isempty(optarg
)) {
605 arg_namespace_flags
= 0;
606 arg_namespace
= mfree(arg_namespace
);
608 arg_namespace_flags
= 0;
609 r
= free_and_strdup_warn(&arg_namespace
, optarg
);
615 case ARG_LIST_NAMESPACES
:
616 arg_action
= ACTION_LIST_NAMESPACES
;
620 r
= free_and_strdup_warn(&arg_directory
, optarg
);
626 if (streq(optarg
, "-"))
627 /* An undocumented feature: we can read journal files from STDIN. We don't document
628 * this though, since after all we only support this for mmap-able, seekable files, and
629 * not for example pipes which are probably the primary use case for reading things from
630 * STDIN. To avoid confusion we hence don't document this feature. */
631 arg_file_stdin
= true;
633 r
= glob_extend(&arg_file
, optarg
, GLOB_NOCHECK
);
635 return log_error_errno(r
, "Failed to add paths: %m");
640 r
= parse_path_argument(optarg
, /* suppress_root= */ true, &arg_root
);
646 r
= parse_path_argument(optarg
, /* suppress_root= */ false, &arg_image
);
651 case ARG_IMAGE_POLICY
:
652 r
= parse_image_policy_argument(optarg
, &arg_image_policy
);
658 r
= free_and_strdup_warn(&arg_cursor
, optarg
);
663 case ARG_CURSOR_FILE
:
664 r
= free_and_strdup_warn(&arg_cursor_file
, optarg
);
669 case ARG_AFTER_CURSOR
:
670 r
= free_and_strdup_warn(&arg_after_cursor
, optarg
);
675 case ARG_SHOW_CURSOR
:
676 arg_show_cursor
= true;
680 arg_action
= ACTION_PRINT_HEADER
;
684 arg_action
= ACTION_VERIFY
;
688 arg_action
= ACTION_DISK_USAGE
;
691 case ARG_VACUUM_SIZE
:
692 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
694 return log_error_errno(r
, "Failed to parse vacuum size: %s", optarg
);
696 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
699 case ARG_VACUUM_FILES
:
700 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
702 return log_error_errno(r
, "Failed to parse vacuum files: %s", optarg
);
704 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
707 case ARG_VACUUM_TIME
:
708 r
= parse_sec(optarg
, &arg_vacuum_time
);
710 return log_error_errno(r
, "Failed to parse vacuum time: %s", optarg
);
712 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
721 arg_action
= ACTION_SETUP_KEYS
;
725 erase_and_free(arg_verify_key
);
726 arg_verify_key
= strdup(optarg
);
730 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
731 * in ps or htop output. */
732 memset(optarg
, 'x', strlen(optarg
));
734 arg_action
= ACTION_VERIFY
;
739 r
= parse_sec(optarg
, &arg_interval
);
740 if (r
< 0 || arg_interval
<= 0)
741 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
742 "Failed to parse sealing key change interval: %s", optarg
);
749 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
750 "Compiled without forward-secure sealing support.");
756 dots
= strstr(optarg
, "..");
758 _cleanup_free_
char *a
= NULL
;
762 a
= strndup(optarg
, dots
- optarg
);
766 from
= log_level_from_string(a
);
767 to
= log_level_from_string(dots
+ 2);
769 if (from
< 0 || to
< 0)
770 return log_error_errno(from
< 0 ? from
: to
,
771 "Failed to parse log level range %s", optarg
);
776 for (i
= from
; i
<= to
; i
++)
777 arg_priorities
|= 1 << i
;
779 for (i
= to
; i
<= from
; i
++)
780 arg_priorities
|= 1 << i
;
786 p
= log_level_from_string(optarg
);
788 return log_error_errno(p
, "Unknown log level %s", optarg
);
792 for (i
= 0; i
<= p
; i
++)
793 arg_priorities
|= 1 << i
;
803 _cleanup_free_
char *fac
= NULL
;
806 r
= extract_first_word(&p
, &fac
, ",", 0);
808 return log_error_errno(r
, "Failed to parse facilities: %s", optarg
);
812 if (streq(fac
, "help")) {
817 num
= log_facility_unshifted_from_string(fac
);
819 return log_error_errno(num
, "Bad --facility= argument \"%s\".", fac
);
821 if (set_ensure_put(&arg_facilities
, NULL
, INT_TO_PTR(num
)) < 0)
829 r
= free_and_strdup_warn(&arg_pattern
, optarg
);
834 case ARG_CASE_SENSITIVE
:
836 r
= parse_boolean(optarg
);
838 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
839 arg_case
= r
? PATTERN_COMPILE_CASE_SENSITIVE
: PATTERN_COMPILE_CASE_INSENSITIVE
;
841 arg_case
= PATTERN_COMPILE_CASE_SENSITIVE
;
846 r
= parse_timestamp(optarg
, &arg_since
);
848 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
849 "Failed to parse timestamp: %s", optarg
);
850 arg_since_set
= true;
854 r
= parse_timestamp(optarg
, &arg_until
);
856 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
857 "Failed to parse timestamp: %s", optarg
);
858 arg_until_set
= true;
862 r
= strv_extend(&arg_syslog_identifier
, optarg
);
868 r
= strv_extend(&arg_exclude_identifier
, optarg
);
874 r
= strv_extend(&arg_system_units
, optarg
);
880 r
= strv_extend(&arg_user_units
, optarg
);
886 r
= parse_id_descriptor(optarg
, &arg_invocation_id
, &arg_invocation_offset
);
888 return log_error_errno(r
, "Failed to parse invocation descriptor: %s", optarg
);
893 /* Equivalent to --invocation=0 */
894 arg_invocation
= true;
895 arg_invocation_id
= SD_ID128_NULL
;
896 arg_invocation_offset
= 0;
900 arg_action
= ACTION_LIST_FIELDS
;
901 r
= free_and_strdup_warn(&arg_field
, optarg
);
907 arg_action
= ACTION_LIST_FIELD_NAMES
;
910 case ARG_NO_HOSTNAME
:
911 arg_no_hostname
= true;
918 case ARG_LIST_CATALOG
:
919 arg_action
= ACTION_LIST_CATALOG
;
922 case ARG_DUMP_CATALOG
:
923 arg_action
= ACTION_DUMP_CATALOG
;
926 case ARG_UPDATE_CATALOG
:
927 arg_action
= ACTION_UPDATE_CATALOG
;
939 arg_action
= ACTION_FLUSH
;
942 case ARG_SMART_RELINQUISH_VAR
: {
943 int root_mnt_id
, log_mnt_id
;
945 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
946 * if it's on the same mount as the root file system there's no point in
947 * relinquishing access and we can leave journald write to it until the very last
950 r
= path_get_mnt_id("/", &root_mnt_id
);
952 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
954 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
956 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
957 else if (root_mnt_id
== log_mnt_id
) {
958 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
961 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
967 case ARG_RELINQUISH_VAR
:
968 arg_action
= ACTION_RELINQUISH_VAR
;
972 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
976 arg_action
= ACTION_SYNC
;
979 case ARG_OUTPUT_FIELDS
: {
980 _cleanup_strv_free_
char **v
= NULL
;
982 v
= strv_split(optarg
, ",");
986 r
= set_put_strdupv(&arg_output_fields
, v
);
993 case ARG_SYNCHRONIZE_ON_EXIT
:
994 r
= parse_boolean_argument("--synchronize-on-exit", optarg
, &arg_synchronize_on_exit
);
1004 assert_not_reached();
1008 arg_lines
= ARG_LINES_ALL
;
1010 if (arg_lines
== ARG_LINES_DEFAULT
) {
1011 if (arg_follow
&& !arg_since_set
)
1013 else if (FLAGS_SET(arg_pager_flags
, PAGER_JUMP_TO_END
))
1018 /* Show the current boot if -f/--follow, -k/--dmesg, or -e/--pager-end is specified unless
1019 * -m/--merge is specified. */
1020 arg_boot
= !arg_merge
&& (arg_follow
|| arg_dmesg
|| FLAGS_SET(arg_pager_flags
, PAGER_JUMP_TO_END
));
1022 /* Clear the boot ID and offset if -b/--boot is unspecified for safety. */
1023 arg_boot_id
= SD_ID128_NULL
;
1024 arg_boot_offset
= 0;
1027 if (!!arg_directory
+ !!arg_file
+ arg_file_stdin
+ !!arg_machine
+ !!arg_root
+ !!arg_image
> 1)
1028 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1029 "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
1031 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
)
1032 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1033 "--since= must be before --until=.");
1035 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_cursor_file
+ !!arg_since_set
> 1)
1036 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1037 "Please specify only one of --since=, --cursor=, --cursor-file=, and --after-cursor=.");
1039 if (arg_follow
&& arg_reverse
)
1040 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1041 "Please specify either --reverse or --follow, not both.");
1043 if (arg_action
== ACTION_SHOW
&& arg_lines
>= 0 && arg_lines_oldest
&& (arg_reverse
|| arg_follow
))
1044 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1045 "--lines=+N is unsupported when --reverse or --follow is specified.");
1047 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
)
1048 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1049 "Extraneous arguments starting with '%s'",
1052 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
)
1053 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1054 "Using --boot or --list-boots with --merge is not supported.");
1056 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
1057 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1058 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1059 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1060 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
1064 arg_system_units
= strv_free(arg_system_units
);
1068 r
= pattern_compile_and_log(arg_pattern
, arg_case
, &arg_compiled_pattern
);
1072 /* When --grep is used along with --lines without '+', i.e. when we start from the end of the
1073 * journal, we don't know how many lines we can print. So we search backwards and count until
1074 * enough lines have been printed or we hit the head.
1075 * An exception is that --follow might set arg_lines, so let's not imply --reverse
1076 * if that is specified. */
1077 if (arg_lines_needs_seek_end() && !arg_follow
)
1082 arg_journal_additional_open_flags
= SD_JOURNAL_ASSUME_IMMUTABLE
;
1087 static int run(int argc
, char *argv
[]) {
1088 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
1089 _cleanup_(umount_and_freep
) char *mounted_dir
= NULL
;
1090 _cleanup_strv_free_
char **args
= NULL
;
1093 setlocale(LC_ALL
, "");
1096 r
= parse_argv(argc
, argv
);
1100 r
= strv_copy_unless_empty(strv_skip(argv
, optind
), &args
);
1107 r
= mount_image_privately_interactively(
1110 DISSECT_IMAGE_GENERIC_ROOT
|
1111 DISSECT_IMAGE_REQUIRE_ROOT
|
1112 DISSECT_IMAGE_VALIDATE_OS
|
1113 DISSECT_IMAGE_RELAX_VAR_CHECK
|
1114 (arg_action
== ACTION_UPDATE_CATALOG
? DISSECT_IMAGE_FSCK
|DISSECT_IMAGE_GROWFS
: DISSECT_IMAGE_READ_ONLY
) |
1115 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY
,
1117 /* ret_dir_fd= */ NULL
,
1122 arg_root
= strdup(mounted_dir
);
1127 switch (arg_action
) {
1130 return action_show(args
);
1132 case ACTION_NEW_ID128
:
1133 return id128_print_new(ID128_PRINT_PRETTY
);
1135 case ACTION_SETUP_KEYS
:
1136 return action_setup_keys();
1138 case ACTION_LIST_CATALOG
:
1139 case ACTION_DUMP_CATALOG
:
1140 return action_list_catalog(args
);
1142 case ACTION_UPDATE_CATALOG
:
1143 return action_update_catalog();
1145 case ACTION_PRINT_HEADER
:
1146 return action_print_header();
1149 return action_verify();
1151 case ACTION_DISK_USAGE
:
1152 return action_disk_usage();
1154 case ACTION_LIST_BOOTS
:
1155 return action_list_boots();
1157 case ACTION_LIST_FIELDS
:
1158 return action_list_fields();
1160 case ACTION_LIST_FIELD_NAMES
:
1161 return action_list_field_names();
1163 case ACTION_LIST_INVOCATIONS
:
1164 return action_list_invocations();
1166 case ACTION_LIST_NAMESPACES
:
1167 return action_list_namespaces();
1170 return action_flush_to_var();
1172 case ACTION_RELINQUISH_VAR
:
1173 return action_relinquish_var();
1176 return action_sync();
1179 return action_rotate();
1182 return action_vacuum();
1184 case ACTION_ROTATE_AND_VACUUM
:
1185 return action_rotate_and_vacuum();
1188 assert_not_reached();
1192 DEFINE_MAIN_FUNCTION_WITH_POSITIVE_SIGNAL(run
);