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
, pcre2_code_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 " -W --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
,
373 ARG_SYNCHRONIZE_ON_EXIT
,
376 static const struct option options
[] = {
377 { "help", no_argument
, NULL
, 'h' },
378 { "version" , no_argument
, NULL
, ARG_VERSION
},
379 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
380 { "pager-end", no_argument
, NULL
, 'e' },
381 { "follow", no_argument
, NULL
, 'f' },
382 { "force", no_argument
, NULL
, ARG_FORCE
},
383 { "output", required_argument
, NULL
, 'o' },
384 { "all", no_argument
, NULL
, 'a' },
385 { "full", no_argument
, NULL
, 'l' },
386 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
387 { "lines", optional_argument
, NULL
, 'n' },
388 { "truncate-newline", no_argument
, NULL
, ARG_TRUNCATE_NEWLINE
},
389 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
390 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
391 { "quiet", no_argument
, NULL
, 'q' },
392 { "merge", no_argument
, NULL
, 'm' },
393 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
394 { "boot", optional_argument
, NULL
, 'b' },
395 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
396 { "list-invocations", no_argument
, NULL
, ARG_LIST_INVOCATIONS
},
397 { "dmesg", no_argument
, NULL
, 'k' },
398 { "system", no_argument
, NULL
, ARG_SYSTEM
},
399 { "user", no_argument
, NULL
, ARG_USER
},
400 { "directory", required_argument
, NULL
, 'D' },
401 { "file", required_argument
, NULL
, 'i' },
402 { "root", required_argument
, NULL
, ARG_ROOT
},
403 { "image", required_argument
, NULL
, ARG_IMAGE
},
404 { "image-policy", required_argument
, NULL
, ARG_IMAGE_POLICY
},
405 { "header", no_argument
, NULL
, ARG_HEADER
},
406 { "identifier", required_argument
, NULL
, 't' },
407 { "exclude-identifier", required_argument
, NULL
, 'T' },
408 { "priority", required_argument
, NULL
, 'p' },
409 { "facility", required_argument
, NULL
, ARG_FACILITY
},
410 { "grep", required_argument
, NULL
, 'g' },
411 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
412 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
413 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
414 { "verify", no_argument
, NULL
, ARG_VERIFY
},
415 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
416 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
417 { "cursor", required_argument
, NULL
, 'c' },
418 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
419 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
420 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
421 { "since", required_argument
, NULL
, 'S' },
422 { "until", required_argument
, NULL
, 'U' },
423 { "unit", required_argument
, NULL
, 'u' },
424 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
425 { "invocation", required_argument
, NULL
, ARG_INVOCATION
},
426 { "field", required_argument
, NULL
, 'F' },
427 { "fields", no_argument
, NULL
, 'N' },
428 { "catalog", no_argument
, NULL
, 'x' },
429 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
430 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
431 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
432 { "reverse", no_argument
, NULL
, 'r' },
433 { "machine", required_argument
, NULL
, 'M' },
434 { "utc", no_argument
, NULL
, ARG_UTC
},
435 { "flush", no_argument
, NULL
, ARG_FLUSH
},
436 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
437 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
438 { "sync", no_argument
, NULL
, ARG_SYNC
},
439 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
440 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
441 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
442 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
443 { "no-hostname", no_argument
, NULL
, 'W' },
444 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
445 { "namespace", required_argument
, NULL
, ARG_NAMESPACE
},
446 { "list-namespaces", no_argument
, NULL
, ARG_LIST_NAMESPACES
},
447 { "synchronize-on-exit", required_argument
, NULL
, ARG_SYNCHRONIZE_ON_EXIT
},
456 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:T:u:INF:xrM:i:W", options
, NULL
)) >= 0)
467 arg_pager_flags
|= PAGER_DISABLE
;
471 arg_pager_flags
|= PAGER_JUMP_TO_END
;
479 if (streq(optarg
, "help"))
480 return DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
482 arg_output
= output_mode_from_string(optarg
);
484 return log_error_errno(arg_output
, "Unknown output format '%s'.", optarg
);
486 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
489 if (OUTPUT_MODE_IS_JSON(arg_output
))
490 arg_json_format_flags
= output_mode_to_json_format_flags(arg_output
) | SD_JSON_FORMAT_COLOR_AUTO
;
492 arg_json_format_flags
= SD_JSON_FORMAT_OFF
;
509 r
= parse_lines(optarg
?: argv
[optind
], !optarg
);
512 if (r
> 0 && !optarg
)
521 case ARG_TRUNCATE_NEWLINE
:
522 arg_truncate_newline
= true;
526 arg_action
= ACTION_NEW_ID128
;
539 arg_boot_id
= SD_ID128_NULL
;
545 arg_boot_id
= SD_ID128_NULL
;
549 r
= parse_id_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
551 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
555 } else if (optind
< argc
) {
556 /* Hmm, no argument? Maybe the next word on the command line is supposed to be the
557 * argument? Let's see if there is one and is parsable as a boot descriptor... */
558 r
= parse_id_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
567 arg_action
= ACTION_LIST_BOOTS
;
570 case ARG_LIST_INVOCATIONS
:
571 arg_action
= ACTION_LIST_INVOCATIONS
;
579 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
583 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
587 r
= free_and_strdup_warn(&arg_machine
, optarg
);
593 if (streq(optarg
, "*")) {
594 arg_namespace_flags
= SD_JOURNAL_ALL_NAMESPACES
;
595 arg_namespace
= mfree(arg_namespace
);
596 } else if (startswith(optarg
, "+")) {
597 arg_namespace_flags
= SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
;
598 r
= free_and_strdup_warn(&arg_namespace
, optarg
+ 1);
601 } else if (isempty(optarg
)) {
602 arg_namespace_flags
= 0;
603 arg_namespace
= mfree(arg_namespace
);
605 arg_namespace_flags
= 0;
606 r
= free_and_strdup_warn(&arg_namespace
, optarg
);
612 case ARG_LIST_NAMESPACES
:
613 arg_action
= ACTION_LIST_NAMESPACES
;
617 r
= free_and_strdup_warn(&arg_directory
, optarg
);
623 if (streq(optarg
, "-"))
624 /* An undocumented feature: we can read journal files from STDIN. We don't document
625 * this though, since after all we only support this for mmap-able, seekable files, and
626 * not for example pipes which are probably the primary use case for reading things from
627 * STDIN. To avoid confusion we hence don't document this feature. */
628 arg_file_stdin
= true;
630 r
= glob_extend(&arg_file
, optarg
, GLOB_NOCHECK
);
632 return log_error_errno(r
, "Failed to add paths: %m");
637 r
= parse_path_argument(optarg
, /* suppress_root= */ true, &arg_root
);
643 r
= parse_path_argument(optarg
, /* suppress_root= */ false, &arg_image
);
648 case ARG_IMAGE_POLICY
:
649 r
= parse_image_policy_argument(optarg
, &arg_image_policy
);
655 r
= free_and_strdup_warn(&arg_cursor
, optarg
);
660 case ARG_CURSOR_FILE
:
661 r
= free_and_strdup_warn(&arg_cursor_file
, optarg
);
666 case ARG_AFTER_CURSOR
:
667 r
= free_and_strdup_warn(&arg_after_cursor
, optarg
);
672 case ARG_SHOW_CURSOR
:
673 arg_show_cursor
= true;
677 arg_action
= ACTION_PRINT_HEADER
;
681 arg_action
= ACTION_VERIFY
;
685 arg_action
= ACTION_DISK_USAGE
;
688 case ARG_VACUUM_SIZE
:
689 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
691 return log_error_errno(r
, "Failed to parse vacuum size: %s", optarg
);
693 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
696 case ARG_VACUUM_FILES
:
697 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
699 return log_error_errno(r
, "Failed to parse vacuum files: %s", optarg
);
701 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
704 case ARG_VACUUM_TIME
:
705 r
= parse_sec(optarg
, &arg_vacuum_time
);
707 return log_error_errno(r
, "Failed to parse vacuum time: %s", optarg
);
709 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
718 arg_action
= ACTION_SETUP_KEYS
;
722 erase_and_free(arg_verify_key
);
723 arg_verify_key
= strdup(optarg
);
727 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
728 * in ps or htop output. */
729 memset(optarg
, 'x', strlen(optarg
));
731 arg_action
= ACTION_VERIFY
;
736 r
= parse_sec(optarg
, &arg_interval
);
737 if (r
< 0 || arg_interval
<= 0)
738 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
739 "Failed to parse sealing key change interval: %s", optarg
);
746 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
747 "Compiled without forward-secure sealing support.");
753 dots
= strstr(optarg
, "..");
755 _cleanup_free_
char *a
= NULL
;
759 a
= strndup(optarg
, dots
- optarg
);
763 from
= log_level_from_string(a
);
764 to
= log_level_from_string(dots
+ 2);
766 if (from
< 0 || to
< 0)
767 return log_error_errno(from
< 0 ? from
: to
,
768 "Failed to parse log level range %s", optarg
);
773 for (i
= from
; i
<= to
; i
++)
774 arg_priorities
|= 1 << i
;
776 for (i
= to
; i
<= from
; i
++)
777 arg_priorities
|= 1 << i
;
783 p
= log_level_from_string(optarg
);
785 return log_error_errno(p
, "Unknown log level %s", optarg
);
789 for (i
= 0; i
<= p
; i
++)
790 arg_priorities
|= 1 << i
;
800 _cleanup_free_
char *fac
= NULL
;
803 r
= extract_first_word(&p
, &fac
, ",", 0);
805 return log_error_errno(r
, "Failed to parse facilities: %s", optarg
);
809 if (streq(fac
, "help")) {
814 num
= log_facility_unshifted_from_string(fac
);
816 return log_error_errno(num
, "Bad --facility= argument \"%s\".", fac
);
818 if (set_ensure_put(&arg_facilities
, NULL
, INT_TO_PTR(num
)) < 0)
826 r
= free_and_strdup_warn(&arg_pattern
, optarg
);
831 case ARG_CASE_SENSITIVE
:
833 r
= parse_boolean(optarg
);
835 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
836 arg_case
= r
? PATTERN_COMPILE_CASE_SENSITIVE
: PATTERN_COMPILE_CASE_INSENSITIVE
;
838 arg_case
= PATTERN_COMPILE_CASE_SENSITIVE
;
843 r
= parse_timestamp(optarg
, &arg_since
);
845 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
846 "Failed to parse timestamp: %s", optarg
);
847 arg_since_set
= true;
851 r
= parse_timestamp(optarg
, &arg_until
);
853 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
854 "Failed to parse timestamp: %s", optarg
);
855 arg_until_set
= true;
859 r
= strv_extend(&arg_syslog_identifier
, optarg
);
865 r
= strv_extend(&arg_exclude_identifier
, optarg
);
871 r
= strv_extend(&arg_system_units
, optarg
);
877 r
= strv_extend(&arg_user_units
, optarg
);
883 r
= parse_id_descriptor(optarg
, &arg_invocation_id
, &arg_invocation_offset
);
885 return log_error_errno(r
, "Failed to parse invocation descriptor: %s", optarg
);
890 /* Equivalent to --invocation=0 */
891 arg_invocation
= true;
892 arg_invocation_id
= SD_ID128_NULL
;
893 arg_invocation_offset
= 0;
897 arg_action
= ACTION_LIST_FIELDS
;
898 r
= free_and_strdup_warn(&arg_field
, optarg
);
904 arg_action
= ACTION_LIST_FIELD_NAMES
;
908 arg_no_hostname
= true;
915 case ARG_LIST_CATALOG
:
916 arg_action
= ACTION_LIST_CATALOG
;
919 case ARG_DUMP_CATALOG
:
920 arg_action
= ACTION_DUMP_CATALOG
;
923 case ARG_UPDATE_CATALOG
:
924 arg_action
= ACTION_UPDATE_CATALOG
;
936 arg_action
= ACTION_FLUSH
;
939 case ARG_SMART_RELINQUISH_VAR
: {
940 int root_mnt_id
, log_mnt_id
;
942 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
943 * if it's on the same mount as the root file system there's no point in
944 * relinquishing access and we can leave journald write to it until the very last
947 r
= path_get_mnt_id("/", &root_mnt_id
);
949 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
951 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
953 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
954 else if (root_mnt_id
== log_mnt_id
) {
955 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
958 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
964 case ARG_RELINQUISH_VAR
:
965 arg_action
= ACTION_RELINQUISH_VAR
;
969 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
973 arg_action
= ACTION_SYNC
;
976 case ARG_OUTPUT_FIELDS
: {
977 _cleanup_strv_free_
char **v
= NULL
;
979 v
= strv_split(optarg
, ",");
983 r
= set_put_strdupv(&arg_output_fields
, v
);
990 case ARG_SYNCHRONIZE_ON_EXIT
:
991 r
= parse_boolean_argument("--synchronize-on-exit", optarg
, &arg_synchronize_on_exit
);
1001 assert_not_reached();
1005 arg_lines
= ARG_LINES_ALL
;
1007 if (arg_lines
== ARG_LINES_DEFAULT
) {
1008 if (arg_follow
&& !arg_since_set
)
1010 else if (FLAGS_SET(arg_pager_flags
, PAGER_JUMP_TO_END
))
1015 /* Show the current boot if -f/--follow, -k/--dmesg, or -e/--pager-end is specified unless
1016 * -m/--merge is specified. */
1017 arg_boot
= !arg_merge
&& (arg_follow
|| arg_dmesg
|| FLAGS_SET(arg_pager_flags
, PAGER_JUMP_TO_END
));
1019 /* Clear the boot ID and offset if -b/--boot is unspecified for safety. */
1020 arg_boot_id
= SD_ID128_NULL
;
1021 arg_boot_offset
= 0;
1024 if (!!arg_directory
+ !!arg_file
+ arg_file_stdin
+ !!arg_machine
+ !!arg_root
+ !!arg_image
> 1)
1025 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1026 "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
1028 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
)
1029 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1030 "--since= must be before --until=.");
1032 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_cursor_file
+ !!arg_since_set
> 1)
1033 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1034 "Please specify only one of --since=, --cursor=, --cursor-file=, and --after-cursor=.");
1036 if (arg_follow
&& arg_reverse
)
1037 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1038 "Please specify either --reverse or --follow, not both.");
1040 if (arg_action
== ACTION_SHOW
&& arg_lines
>= 0 && arg_lines_oldest
&& (arg_reverse
|| arg_follow
))
1041 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1042 "--lines=+N is unsupported when --reverse or --follow is specified.");
1044 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
)
1045 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1046 "Extraneous arguments starting with '%s'",
1049 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
)
1050 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1051 "Using --boot or --list-boots with --merge is not supported.");
1053 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
1054 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1055 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1056 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1057 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
1061 arg_system_units
= strv_free(arg_system_units
);
1065 r
= pattern_compile_and_log(arg_pattern
, arg_case
, &arg_compiled_pattern
);
1069 /* When --grep is used along with --lines without '+', i.e. when we start from the end of the
1070 * journal, we don't know how many lines we can print. So we search backwards and count until
1071 * enough lines have been printed or we hit the head.
1072 * An exception is that --follow might set arg_lines, so let's not imply --reverse
1073 * if that is specified. */
1074 if (arg_lines_needs_seek_end() && !arg_follow
)
1079 arg_journal_additional_open_flags
= SD_JOURNAL_ASSUME_IMMUTABLE
;
1084 static int run(int argc
, char *argv
[]) {
1085 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
1086 _cleanup_(umount_and_freep
) char *mounted_dir
= NULL
;
1087 _cleanup_strv_free_
char **args
= NULL
;
1090 setlocale(LC_ALL
, "");
1093 r
= parse_argv(argc
, argv
);
1097 r
= strv_copy_unless_empty(strv_skip(argv
, optind
), &args
);
1104 r
= mount_image_privately_interactively(
1107 DISSECT_IMAGE_GENERIC_ROOT
|
1108 DISSECT_IMAGE_REQUIRE_ROOT
|
1109 DISSECT_IMAGE_VALIDATE_OS
|
1110 DISSECT_IMAGE_RELAX_VAR_CHECK
|
1111 (arg_action
== ACTION_UPDATE_CATALOG
? DISSECT_IMAGE_FSCK
|DISSECT_IMAGE_GROWFS
: DISSECT_IMAGE_READ_ONLY
) |
1112 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY
,
1114 /* ret_dir_fd= */ NULL
,
1119 arg_root
= strdup(mounted_dir
);
1124 switch (arg_action
) {
1127 return action_show(args
);
1129 case ACTION_NEW_ID128
:
1130 return id128_print_new(ID128_PRINT_PRETTY
);
1132 case ACTION_SETUP_KEYS
:
1133 return action_setup_keys();
1135 case ACTION_LIST_CATALOG
:
1136 case ACTION_DUMP_CATALOG
:
1137 return action_list_catalog(args
);
1139 case ACTION_UPDATE_CATALOG
:
1140 return action_update_catalog();
1142 case ACTION_PRINT_HEADER
:
1143 return action_print_header();
1146 return action_verify();
1148 case ACTION_DISK_USAGE
:
1149 return action_disk_usage();
1151 case ACTION_LIST_BOOTS
:
1152 return action_list_boots();
1154 case ACTION_LIST_FIELDS
:
1155 return action_list_fields();
1157 case ACTION_LIST_FIELD_NAMES
:
1158 return action_list_field_names();
1160 case ACTION_LIST_INVOCATIONS
:
1161 return action_list_invocations();
1163 case ACTION_LIST_NAMESPACES
:
1164 return action_list_namespaces();
1167 return action_flush_to_var();
1169 case ACTION_RELINQUISH_VAR
:
1170 return action_relinquish_var();
1173 return action_sync();
1176 return action_rotate();
1179 return action_vacuum();
1181 case ACTION_ROTATE_AND_VACUUM
:
1182 return action_rotate_and_vacuum();
1185 assert_not_reached();
1189 DEFINE_MAIN_FUNCTION(run
);