1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "sd-journal.h"
9 #include "id128-print.h"
10 #include "journalctl.h"
11 #include "journalctl-authenticate.h"
12 #include "journalctl-catalog.h"
13 #include "journalctl-misc.h"
14 #include "journalctl-show.h"
15 #include "journalctl-varlink.h"
16 #include "locale-util.h"
17 #include "main-func.h"
18 #include "mount-util.h"
19 #include "mountpoint-util.h"
20 #include "parse-argument.h"
21 #include "pretty-print.h"
22 #include "static-destruct.h"
23 #include "string-table.h"
24 #include "syslog-util.h"
26 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
29 /* Special values for arg_lines */
30 ARG_LINES_DEFAULT
= -2,
34 JournalctlAction arg_action
= ACTION_SHOW
;
35 OutputMode arg_output
= OUTPUT_SHORT
;
36 JsonFormatFlags arg_json_format_flags
= JSON_FORMAT_OFF
;
37 PagerFlags arg_pager_flags
= 0;
39 bool arg_follow
= false;
42 int arg_lines
= ARG_LINES_DEFAULT
;
43 bool arg_lines_oldest
= false;
44 bool arg_no_tail
= false;
45 bool arg_truncate_newline
= false;
46 bool arg_quiet
= false;
47 bool arg_merge
= false;
48 bool arg_boot
= false;
49 sd_id128_t arg_boot_id
= {};
50 int arg_boot_offset
= 0;
51 bool arg_dmesg
= false;
52 bool arg_no_hostname
= false;
53 const char *arg_cursor
= NULL
;
54 const char *arg_cursor_file
= NULL
;
55 const char *arg_after_cursor
= NULL
;
56 bool arg_show_cursor
= false;
57 const char *arg_directory
= NULL
;
58 char **arg_file
= NULL
;
59 bool arg_file_stdin
= false;
60 int arg_priorities
= 0xFF;
61 Set
*arg_facilities
= NULL
;
62 char *arg_verify_key
= NULL
;
64 usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
65 bool arg_force
= false;
69 bool arg_since_set
= false;
70 bool arg_until_set
= false;
71 char **arg_syslog_identifier
= NULL
;
72 char **arg_exclude_identifier
= NULL
;
73 char **arg_system_units
= NULL
;
74 char **arg_user_units
= NULL
;
75 const char *arg_field
= NULL
;
76 bool arg_catalog
= false;
77 bool arg_reverse
= false;
78 int arg_journal_type
= 0;
79 int arg_journal_additional_open_flags
= 0;
80 int arg_namespace_flags
= 0;
81 char *arg_root
= NULL
;
82 char *arg_image
= NULL
;
83 const char *arg_machine
= NULL
;
84 const char *arg_namespace
= NULL
;
85 uint64_t arg_vacuum_size
= 0;
86 uint64_t arg_vacuum_n_files
= 0;
87 usec_t arg_vacuum_time
= 0;
88 Set
*arg_output_fields
= NULL
;
89 const char *arg_pattern
= NULL
;
90 pcre2_code
*arg_compiled_pattern
= NULL
;
91 PatternCompileCase arg_case
= PATTERN_COMPILE_CASE_AUTO
;
92 static ImagePolicy
*arg_image_policy
= NULL
;
94 STATIC_DESTRUCTOR_REGISTER(arg_file
, strv_freep
);
95 STATIC_DESTRUCTOR_REGISTER(arg_facilities
, set_freep
);
96 STATIC_DESTRUCTOR_REGISTER(arg_verify_key
, freep
);
97 STATIC_DESTRUCTOR_REGISTER(arg_syslog_identifier
, strv_freep
);
98 STATIC_DESTRUCTOR_REGISTER(arg_exclude_identifier
, strv_freep
);
99 STATIC_DESTRUCTOR_REGISTER(arg_system_units
, strv_freep
);
100 STATIC_DESTRUCTOR_REGISTER(arg_user_units
, strv_freep
);
101 STATIC_DESTRUCTOR_REGISTER(arg_root
, freep
);
102 STATIC_DESTRUCTOR_REGISTER(arg_image
, freep
);
103 STATIC_DESTRUCTOR_REGISTER(arg_output_fields
, set_freep
);
104 STATIC_DESTRUCTOR_REGISTER(arg_compiled_pattern
, pattern_freep
);
105 STATIC_DESTRUCTOR_REGISTER(arg_image_policy
, image_policy_freep
);
107 static int parse_boot_descriptor(const char *x
, sd_id128_t
*boot_id
, int *offset
) {
108 sd_id128_t id
= SD_ID128_NULL
;
111 if (streq(x
, "all")) {
112 *boot_id
= SD_ID128_NULL
;
115 } else if (strlen(x
) >= SD_ID128_STRING_MAX
- 1) {
118 t
= strndupa_safe(x
, SD_ID128_STRING_MAX
- 1);
119 r
= sd_id128_from_string(t
, &id
);
121 x
+= SD_ID128_STRING_MAX
- 1;
123 if (!IN_SET(*x
, 0, '-', '+'))
127 r
= safe_atoi(x
, &off
);
132 r
= safe_atoi(x
, &off
);
146 static int parse_lines(const char *arg
, bool graceful
) {
150 assert(arg
|| graceful
);
155 if (streq(arg
, "all")) {
156 arg_lines
= ARG_LINES_ALL
;
160 l
= startswith(arg
, "+");
162 r
= safe_atoi(l
?: arg
, &n
);
163 if (r
< 0 || n
< 0) {
167 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to parse --lines='%s'.", arg
);
171 arg_lines_oldest
= l
;
177 arg_lines_oldest
= false;
181 static int help_facilities(void) {
183 puts("Available facilities:");
185 for (int i
= 0; i
< LOG_NFACILITIES
; i
++) {
186 _cleanup_free_
char *t
= NULL
;
188 if (log_facility_unshifted_to_string_alloc(i
, &t
) < 0)
196 static int help(void) {
197 _cleanup_free_
char *link
= NULL
;
200 pager_open(arg_pager_flags
);
202 r
= terminal_urlify_man("journalctl", "1", &link
);
206 printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
207 "%5$sQuery the journal.%6$s\n\n"
208 "%3$sSource Options:%4$s\n"
209 " --system Show the system journal\n"
210 " --user Show the user journal for the current user\n"
211 " -M --machine=CONTAINER Operate on local container\n"
212 " -m --merge Show entries from all available journals\n"
213 " -D --directory=PATH Show journal files from directory\n"
214 " -i --file=PATH Show journal file\n"
215 " --root=PATH Operate on an alternate filesystem root\n"
216 " --image=PATH Operate on disk image as filesystem root\n"
217 " --image-policy=POLICY Specify disk image dissection policy\n"
218 " --namespace=NAMESPACE Show journal data from specified journal namespace\n"
219 "\n%3$sFiltering Options:%4$s\n"
220 " -S --since=DATE Show entries not older than the specified date\n"
221 " -U --until=DATE Show entries not newer than the specified date\n"
222 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
223 " --after-cursor=CURSOR Show entries after the specified cursor\n"
224 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
225 " -b --boot[=ID] Show current boot or the specified boot\n"
226 " -u --unit=UNIT Show logs from the specified unit\n"
227 " --user-unit=UNIT Show logs from the specified user unit\n"
228 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
229 " -T --exclude-identifier=STRING\n"
230 " Hide entries with the specified syslog identifier\n"
231 " -p --priority=RANGE Show entries with the specified priority\n"
232 " --facility=FACILITY... Show entries with the specified facilities\n"
233 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
234 " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
235 " -k --dmesg Show kernel message log from the current boot\n"
236 "\n%3$sOutput Control Options:%4$s\n"
237 " -o --output=STRING Change journal output mode (short, short-precise,\n"
238 " short-iso, short-iso-precise, short-full,\n"
239 " short-monotonic, short-unix, verbose, export,\n"
240 " json, json-pretty, json-sse, json-seq, cat,\n"
242 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
243 " -n --lines[=[+]INTEGER] Number of journal entries to show\n"
244 " -r --reverse Show the newest entries first\n"
245 " --show-cursor Print the cursor after all the entries\n"
246 " --utc Express time in Coordinated Universal Time (UTC)\n"
247 " -x --catalog Add message explanations where available\n"
248 " --no-hostname Suppress output of hostname field\n"
249 " --no-full Ellipsize fields\n"
250 " -a --all Show all fields, including long and unprintable\n"
251 " -f --follow Follow the journal\n"
252 " --no-tail Show all lines, even in follow mode\n"
253 " --truncate-newline Truncate entries by first newline character\n"
254 " -q --quiet Do not show info messages and privilege warning\n"
255 "\n%3$sPager Control Options:%4$s\n"
256 " --no-pager Do not pipe output into a pager\n"
257 " -e --pager-end Immediately jump to the end in the pager\n"
258 "\n%3$sForward Secure Sealing (FSS) Options:%4$s\n"
259 " --interval=TIME Time interval for changing the FSS sealing key\n"
260 " --verify-key=KEY Specify FSS verification key\n"
261 " --force Override of the FSS key pair with --setup-keys\n"
262 "\n%3$sCommands:%4$s\n"
263 " -h --help Show this help text\n"
264 " --version Show package version\n"
265 " -N --fields List all field names currently used\n"
266 " -F --field=FIELD List all values that a specified field takes\n"
267 " --list-boots Show terse information about recorded boots\n"
268 " --disk-usage Show total disk usage of all journal files\n"
269 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
270 " --vacuum-files=INT Leave only the specified number of journal files\n"
271 " --vacuum-time=TIME Remove journal files older than specified time\n"
272 " --verify Verify journal file consistency\n"
273 " --sync Synchronize unwritten journal messages to disk\n"
274 " --relinquish-var Stop logging to disk, log to temporary file system\n"
275 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
276 " --flush Flush all journal data from /run into /var\n"
277 " --rotate Request immediate rotation of the journal files\n"
278 " --header Show journal header information\n"
279 " --list-catalog Show all message IDs in the catalog\n"
280 " --dump-catalog Show entries in the message catalog\n"
281 " --update-catalog Update the message catalog database\n"
282 " --setup-keys Generate a new FSS key pair\n"
283 "\nSee the %2$s for details.\n",
284 program_invocation_short_name
,
294 static int parse_argv(int argc
, char *argv
[]) {
329 ARG_SMART_RELINQUISH_VAR
,
331 ARG_TRUNCATE_NEWLINE
,
341 static const struct option options
[] = {
342 { "help", no_argument
, NULL
, 'h' },
343 { "version" , no_argument
, NULL
, ARG_VERSION
},
344 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
345 { "pager-end", no_argument
, NULL
, 'e' },
346 { "follow", no_argument
, NULL
, 'f' },
347 { "force", no_argument
, NULL
, ARG_FORCE
},
348 { "output", required_argument
, NULL
, 'o' },
349 { "all", no_argument
, NULL
, 'a' },
350 { "full", no_argument
, NULL
, 'l' },
351 { "no-full", no_argument
, NULL
, ARG_NO_FULL
},
352 { "lines", optional_argument
, NULL
, 'n' },
353 { "truncate-newline", no_argument
, NULL
, ARG_TRUNCATE_NEWLINE
},
354 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
355 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
}, /* deprecated */
356 { "quiet", no_argument
, NULL
, 'q' },
357 { "merge", no_argument
, NULL
, 'm' },
358 { "this-boot", no_argument
, NULL
, ARG_THIS_BOOT
}, /* deprecated */
359 { "boot", optional_argument
, NULL
, 'b' },
360 { "list-boots", no_argument
, NULL
, ARG_LIST_BOOTS
},
361 { "dmesg", no_argument
, NULL
, 'k' },
362 { "system", no_argument
, NULL
, ARG_SYSTEM
},
363 { "user", no_argument
, NULL
, ARG_USER
},
364 { "directory", required_argument
, NULL
, 'D' },
365 { "file", required_argument
, NULL
, 'i' },
366 { "root", required_argument
, NULL
, ARG_ROOT
},
367 { "image", required_argument
, NULL
, ARG_IMAGE
},
368 { "image-policy", required_argument
, NULL
, ARG_IMAGE_POLICY
},
369 { "header", no_argument
, NULL
, ARG_HEADER
},
370 { "identifier", required_argument
, NULL
, 't' },
371 { "exclude-identifier", required_argument
, NULL
, 'T' },
372 { "priority", required_argument
, NULL
, 'p' },
373 { "facility", required_argument
, NULL
, ARG_FACILITY
},
374 { "grep", required_argument
, NULL
, 'g' },
375 { "case-sensitive", optional_argument
, NULL
, ARG_CASE_SENSITIVE
},
376 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
377 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
378 { "verify", no_argument
, NULL
, ARG_VERIFY
},
379 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
380 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
381 { "cursor", required_argument
, NULL
, 'c' },
382 { "cursor-file", required_argument
, NULL
, ARG_CURSOR_FILE
},
383 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
384 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
385 { "since", required_argument
, NULL
, 'S' },
386 { "until", required_argument
, NULL
, 'U' },
387 { "unit", required_argument
, NULL
, 'u' },
388 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
389 { "field", required_argument
, NULL
, 'F' },
390 { "fields", no_argument
, NULL
, 'N' },
391 { "catalog", no_argument
, NULL
, 'x' },
392 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
393 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
394 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
395 { "reverse", no_argument
, NULL
, 'r' },
396 { "machine", required_argument
, NULL
, 'M' },
397 { "utc", no_argument
, NULL
, ARG_UTC
},
398 { "flush", no_argument
, NULL
, ARG_FLUSH
},
399 { "relinquish-var", no_argument
, NULL
, ARG_RELINQUISH_VAR
},
400 { "smart-relinquish-var", no_argument
, NULL
, ARG_SMART_RELINQUISH_VAR
},
401 { "sync", no_argument
, NULL
, ARG_SYNC
},
402 { "rotate", no_argument
, NULL
, ARG_ROTATE
},
403 { "vacuum-size", required_argument
, NULL
, ARG_VACUUM_SIZE
},
404 { "vacuum-files", required_argument
, NULL
, ARG_VACUUM_FILES
},
405 { "vacuum-time", required_argument
, NULL
, ARG_VACUUM_TIME
},
406 { "no-hostname", no_argument
, NULL
, ARG_NO_HOSTNAME
},
407 { "output-fields", required_argument
, NULL
, ARG_OUTPUT_FIELDS
},
408 { "namespace", required_argument
, NULL
, ARG_NAMESPACE
},
409 { "list-namespaces", no_argument
, NULL
, ARG_LIST_NAMESPACES
},
418 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:g:c:S:U:t:T:u:NF:xrM:i:", options
, NULL
)) >= 0)
429 arg_pager_flags
|= PAGER_DISABLE
;
433 arg_pager_flags
|= PAGER_JUMP_TO_END
;
435 if (arg_lines
== ARG_LINES_DEFAULT
)
447 if (streq(optarg
, "help")) {
448 DUMP_STRING_TABLE(output_mode
, OutputMode
, _OUTPUT_MODE_MAX
);
452 arg_output
= output_mode_from_string(optarg
);
454 return log_error_errno(arg_output
, "Unknown output format '%s'.", optarg
);
456 if (IN_SET(arg_output
, OUTPUT_EXPORT
, OUTPUT_JSON
, OUTPUT_JSON_PRETTY
, OUTPUT_JSON_SSE
, OUTPUT_JSON_SEQ
, OUTPUT_CAT
))
459 if (OUTPUT_MODE_IS_JSON(arg_output
))
460 arg_json_format_flags
= output_mode_to_json_format_flags(arg_output
) | JSON_FORMAT_COLOR_AUTO
;
462 arg_json_format_flags
= JSON_FORMAT_OFF
;
479 r
= parse_lines(optarg
?: argv
[optind
], !optarg
);
482 if (r
> 0 && !optarg
)
491 case ARG_TRUNCATE_NEWLINE
:
492 arg_truncate_newline
= true;
496 arg_action
= ACTION_NEW_ID128
;
509 arg_boot_id
= SD_ID128_NULL
;
515 arg_boot_id
= SD_ID128_NULL
;
519 r
= parse_boot_descriptor(optarg
, &arg_boot_id
, &arg_boot_offset
);
521 return log_error_errno(r
, "Failed to parse boot descriptor '%s'", optarg
);
525 /* Hmm, no argument? Maybe the next
526 * word on the command line is
527 * supposed to be the argument? Let's
528 * see if there is one and is parsable
529 * as a boot descriptor... */
530 } else if (optind
< argc
) {
531 r
= parse_boot_descriptor(argv
[optind
], &arg_boot_id
, &arg_boot_offset
);
540 arg_action
= ACTION_LIST_BOOTS
;
544 arg_boot
= arg_dmesg
= true;
548 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
552 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
556 arg_machine
= optarg
;
560 if (streq(optarg
, "*")) {
561 arg_namespace_flags
= SD_JOURNAL_ALL_NAMESPACES
;
562 arg_namespace
= NULL
;
563 } else if (startswith(optarg
, "+")) {
564 arg_namespace_flags
= SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
;
565 arg_namespace
= optarg
+ 1;
566 } else if (isempty(optarg
)) {
567 arg_namespace_flags
= 0;
568 arg_namespace
= NULL
;
570 arg_namespace_flags
= 0;
571 arg_namespace
= optarg
;
576 case ARG_LIST_NAMESPACES
:
577 arg_action
= ACTION_LIST_NAMESPACES
;
581 arg_directory
= optarg
;
585 if (streq(optarg
, "-"))
586 /* An undocumented feature: we can read journal files from STDIN. We don't document
587 * this though, since after all we only support this for mmap-able, seekable files, and
588 * not for example pipes which are probably the primary use case for reading things from
589 * STDIN. To avoid confusion we hence don't document this feature. */
590 arg_file_stdin
= true;
592 r
= glob_extend(&arg_file
, optarg
, GLOB_NOCHECK
);
594 return log_error_errno(r
, "Failed to add paths: %m");
599 r
= parse_path_argument(optarg
, /* suppress_root= */ true, &arg_root
);
605 r
= parse_path_argument(optarg
, /* suppress_root= */ false, &arg_image
);
610 case ARG_IMAGE_POLICY
:
611 r
= parse_image_policy_argument(optarg
, &arg_image_policy
);
620 case ARG_CURSOR_FILE
:
621 arg_cursor_file
= optarg
;
624 case ARG_AFTER_CURSOR
:
625 arg_after_cursor
= optarg
;
628 case ARG_SHOW_CURSOR
:
629 arg_show_cursor
= true;
633 arg_action
= ACTION_PRINT_HEADER
;
637 arg_action
= ACTION_VERIFY
;
641 arg_action
= ACTION_DISK_USAGE
;
644 case ARG_VACUUM_SIZE
:
645 r
= parse_size(optarg
, 1024, &arg_vacuum_size
);
647 return log_error_errno(r
, "Failed to parse vacuum size: %s", optarg
);
649 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
652 case ARG_VACUUM_FILES
:
653 r
= safe_atou64(optarg
, &arg_vacuum_n_files
);
655 return log_error_errno(r
, "Failed to parse vacuum files: %s", optarg
);
657 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
660 case ARG_VACUUM_TIME
:
661 r
= parse_sec(optarg
, &arg_vacuum_time
);
663 return log_error_errno(r
, "Failed to parse vacuum time: %s", optarg
);
665 arg_action
= arg_action
== ACTION_ROTATE
? ACTION_ROTATE_AND_VACUUM
: ACTION_VACUUM
;
674 arg_action
= ACTION_SETUP_KEYS
;
678 r
= free_and_strdup(&arg_verify_key
, optarg
);
681 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
682 * in ps or htop output. */
683 memset(optarg
, 'x', strlen(optarg
));
685 arg_action
= ACTION_VERIFY
;
690 r
= parse_sec(optarg
, &arg_interval
);
691 if (r
< 0 || arg_interval
<= 0)
692 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
693 "Failed to parse sealing key change interval: %s", optarg
);
700 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
701 "Compiled without forward-secure sealing support.");
707 dots
= strstr(optarg
, "..");
709 _cleanup_free_
char *a
= NULL
;
713 a
= strndup(optarg
, dots
- optarg
);
717 from
= log_level_from_string(a
);
718 to
= log_level_from_string(dots
+ 2);
720 if (from
< 0 || to
< 0)
721 return log_error_errno(from
< 0 ? from
: to
,
722 "Failed to parse log level range %s", optarg
);
727 for (i
= from
; i
<= to
; i
++)
728 arg_priorities
|= 1 << i
;
730 for (i
= to
; i
<= from
; i
++)
731 arg_priorities
|= 1 << i
;
737 p
= log_level_from_string(optarg
);
739 return log_error_errno(p
, "Unknown log level %s", optarg
);
743 for (i
= 0; i
<= p
; i
++)
744 arg_priorities
|= 1 << i
;
754 _cleanup_free_
char *fac
= NULL
;
757 r
= extract_first_word(&p
, &fac
, ",", 0);
759 return log_error_errno(r
, "Failed to parse facilities: %s", optarg
);
763 if (streq(fac
, "help")) {
768 num
= log_facility_unshifted_from_string(fac
);
770 return log_error_errno(num
, "Bad --facility= argument \"%s\".", fac
);
772 if (set_ensure_put(&arg_facilities
, NULL
, INT_TO_PTR(num
)) < 0)
780 arg_pattern
= optarg
;
783 case ARG_CASE_SENSITIVE
:
785 r
= parse_boolean(optarg
);
787 return log_error_errno(r
, "Bad --case-sensitive= argument \"%s\": %m", optarg
);
788 arg_case
= r
? PATTERN_COMPILE_CASE_SENSITIVE
: PATTERN_COMPILE_CASE_INSENSITIVE
;
790 arg_case
= PATTERN_COMPILE_CASE_SENSITIVE
;
795 r
= parse_timestamp(optarg
, &arg_since
);
797 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
798 "Failed to parse timestamp: %s", optarg
);
799 arg_since_set
= true;
803 r
= parse_timestamp(optarg
, &arg_until
);
805 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
806 "Failed to parse timestamp: %s", optarg
);
807 arg_until_set
= true;
811 r
= strv_extend(&arg_syslog_identifier
, optarg
);
817 r
= strv_extend(&arg_exclude_identifier
, optarg
);
823 r
= strv_extend(&arg_system_units
, optarg
);
829 r
= strv_extend(&arg_user_units
, optarg
);
835 arg_action
= ACTION_LIST_FIELDS
;
840 arg_action
= ACTION_LIST_FIELD_NAMES
;
843 case ARG_NO_HOSTNAME
:
844 arg_no_hostname
= true;
851 case ARG_LIST_CATALOG
:
852 arg_action
= ACTION_LIST_CATALOG
;
855 case ARG_DUMP_CATALOG
:
856 arg_action
= ACTION_DUMP_CATALOG
;
859 case ARG_UPDATE_CATALOG
:
860 arg_action
= ACTION_UPDATE_CATALOG
;
872 arg_action
= ACTION_FLUSH
;
875 case ARG_SMART_RELINQUISH_VAR
: {
876 int root_mnt_id
, log_mnt_id
;
878 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
879 * if it's on the same mount as the root file system there's no point in
880 * relinquishing access and we can leave journald write to it until the very last
883 r
= path_get_mnt_id("/", &root_mnt_id
);
885 log_debug_errno(r
, "Failed to get root mount ID, ignoring: %m");
887 r
= path_get_mnt_id("/var/log/journal/", &log_mnt_id
);
889 log_debug_errno(r
, "Failed to get journal directory mount ID, ignoring: %m");
890 else if (root_mnt_id
== log_mnt_id
) {
891 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
894 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
900 case ARG_RELINQUISH_VAR
:
901 arg_action
= ACTION_RELINQUISH_VAR
;
905 arg_action
= arg_action
== ACTION_VACUUM
? ACTION_ROTATE_AND_VACUUM
: ACTION_ROTATE
;
909 arg_action
= ACTION_SYNC
;
912 case ARG_OUTPUT_FIELDS
: {
913 _cleanup_strv_free_
char **v
= NULL
;
915 v
= strv_split(optarg
, ",");
919 r
= set_put_strdupv(&arg_output_fields
, v
);
929 assert_not_reached();
933 arg_lines
= ARG_LINES_ALL
;
935 if (arg_follow
&& !arg_since_set
&& arg_lines
== ARG_LINES_DEFAULT
)
938 if (arg_follow
&& !arg_merge
&& !arg_boot
) {
940 arg_boot_id
= SD_ID128_NULL
;
944 if (!!arg_directory
+ !!arg_file
+ !!arg_machine
+ !!arg_root
+ !!arg_image
> 1)
945 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
946 "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
948 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
)
949 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
950 "--since= must be before --until=.");
952 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_cursor_file
+ !!arg_since_set
> 1)
953 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
954 "Please specify only one of --since=, --cursor=, --cursor-file=, and --after-cursor=.");
956 if (arg_follow
&& arg_reverse
)
957 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
958 "Please specify either --reverse or --follow, not both.");
960 if (arg_lines
>= 0 && arg_lines_oldest
&& (arg_reverse
|| arg_follow
))
961 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
962 "--lines=+N is unsupported when --reverse or --follow is specified.");
964 if (!IN_SET(arg_action
, ACTION_SHOW
, ACTION_DUMP_CATALOG
, ACTION_LIST_CATALOG
) && optind
< argc
)
965 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
966 "Extraneous arguments starting with '%s'",
969 if ((arg_boot
|| arg_action
== ACTION_LIST_BOOTS
) && arg_merge
)
970 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
971 "Using --boot or --list-boots with --merge is not supported.");
973 if (!strv_isempty(arg_system_units
) && arg_journal_type
== SD_JOURNAL_CURRENT_USER
) {
974 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
975 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
976 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
977 r
= strv_extend_strv(&arg_user_units
, arg_system_units
, true);
981 arg_system_units
= strv_free(arg_system_units
);
985 r
= pattern_compile_and_log(arg_pattern
, arg_case
, &arg_compiled_pattern
);
989 /* When --grep is used along with --lines without '+', i.e. when we start from the end of the
990 * journal, we don't know how many lines we can print. So we search backwards and count until
991 * enough lines have been printed or we hit the head.
992 * An exception is that --follow might set arg_lines, so let's not imply --reverse
993 * if that is specified. */
994 if (arg_lines_needs_seek_end() && !arg_follow
)
999 arg_journal_additional_open_flags
= SD_JOURNAL_ASSUME_IMMUTABLE
;
1004 static int run(int argc
, char *argv
[]) {
1005 _cleanup_(loop_device_unrefp
) LoopDevice
*loop_device
= NULL
;
1006 _cleanup_(umount_and_freep
) char *mounted_dir
= NULL
;
1009 setlocale(LC_ALL
, "");
1012 r
= parse_argv(argc
, argv
);
1016 char **args
= strv_skip(argv
, optind
);
1021 r
= mount_image_privately_interactively(
1024 DISSECT_IMAGE_GENERIC_ROOT
|
1025 DISSECT_IMAGE_REQUIRE_ROOT
|
1026 DISSECT_IMAGE_VALIDATE_OS
|
1027 DISSECT_IMAGE_RELAX_VAR_CHECK
|
1028 (arg_action
== ACTION_UPDATE_CATALOG
? DISSECT_IMAGE_FSCK
|DISSECT_IMAGE_GROWFS
: DISSECT_IMAGE_READ_ONLY
) |
1029 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY
,
1031 /* ret_dir_fd= */ NULL
,
1036 arg_root
= strdup(mounted_dir
);
1041 switch (arg_action
) {
1044 return action_show(args
);
1046 case ACTION_NEW_ID128
:
1047 return id128_print_new(ID128_PRINT_PRETTY
);
1049 case ACTION_SETUP_KEYS
:
1050 return action_setup_keys();
1052 case ACTION_LIST_CATALOG
:
1053 case ACTION_DUMP_CATALOG
:
1054 return action_list_catalog(args
);
1056 case ACTION_UPDATE_CATALOG
:
1057 return action_update_catalog();
1059 case ACTION_PRINT_HEADER
:
1060 return action_print_header();
1063 return action_verify();
1065 case ACTION_DISK_USAGE
:
1066 return action_disk_usage();
1068 case ACTION_LIST_BOOTS
:
1069 return action_list_boots();
1071 case ACTION_LIST_FIELDS
:
1072 return action_list_fields();
1074 case ACTION_LIST_FIELD_NAMES
:
1075 return action_list_field_names();
1077 case ACTION_LIST_NAMESPACES
:
1078 return action_list_namespaces();
1081 return action_flush_to_var();
1083 case ACTION_RELINQUISH_VAR
:
1084 return action_relinquish_var();
1087 return action_sync();
1090 return action_rotate();
1093 return action_vacuum();
1095 case ACTION_ROTATE_AND_VACUUM
:
1096 return action_rotate_and_vacuum();
1099 assert_not_reached();
1103 DEFINE_MAIN_FUNCTION_WITH_POSITIVE_SIGNAL(run
);