]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
systemctl: fix log message when glob patterns passed to disable command and friends
[thirdparty/systemd.git] / src / journal / journalctl.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
87d2c1ff 2
3f6fd1ba 3#include <getopt.h>
ade2db83 4
3f6fd1ba
LP
5#include "sd-journal.h"
6
d6b4d1c7 7#include "build.h"
7d50b32a 8#include "glob-util.h"
ff7dad48 9#include "id128-print.h"
ade2db83
YW
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"
8752c575 16#include "locale-util.h"
9556e79b 17#include "main-func.h"
cc171228 18#include "mount-util.h"
c0dfcb31 19#include "mountpoint-util.h"
614b022c 20#include "parse-argument.h"
294bf0c3 21#include "pretty-print.h"
2e64b27a 22#include "static-destruct.h"
5c828e66 23#include "string-table.h"
7ccbd1ae 24#include "syslog-util.h"
7560fffc 25
baed47c3 26#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
ec316d19 27
97e1cc8b
LP
28enum {
29 /* Special values for arg_lines */
30 ARG_LINES_DEFAULT = -2,
31 ARG_LINES_ALL = -1,
32};
33
ade2db83
YW
34JournalctlAction arg_action = ACTION_SHOW;
35OutputMode arg_output = OUTPUT_SHORT;
36JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
37PagerFlags arg_pager_flags = 0;
38bool arg_utc = false;
39bool arg_follow = false;
40bool arg_full = true;
41bool arg_all = false;
42int arg_lines = ARG_LINES_DEFAULT;
43bool arg_lines_oldest = false;
44bool arg_no_tail = false;
45bool arg_truncate_newline = false;
46bool arg_quiet = false;
47bool arg_merge = false;
48bool arg_boot = false;
49sd_id128_t arg_boot_id = {};
50int arg_boot_offset = 0;
51bool arg_dmesg = false;
52bool arg_no_hostname = false;
53const char *arg_cursor = NULL;
54const char *arg_cursor_file = NULL;
55const char *arg_after_cursor = NULL;
56bool arg_show_cursor = false;
57const char *arg_directory = NULL;
58char **arg_file = NULL;
59bool arg_file_stdin = false;
22f2b556 60int arg_priorities = 0;
ade2db83
YW
61Set *arg_facilities = NULL;
62char *arg_verify_key = NULL;
349cc4a5 63#if HAVE_GCRYPT
ade2db83
YW
64usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
65bool arg_force = false;
feb12d3e 66#endif
ade2db83
YW
67usec_t arg_since = 0;
68usec_t arg_until = 0;
69bool arg_since_set = false;
70bool arg_until_set = false;
71char **arg_syslog_identifier = NULL;
72char **arg_exclude_identifier = NULL;
73char **arg_system_units = NULL;
74char **arg_user_units = NULL;
75const char *arg_field = NULL;
76bool arg_catalog = false;
77bool arg_reverse = false;
78int arg_journal_type = 0;
79int arg_journal_additional_open_flags = 0;
80int arg_namespace_flags = 0;
81char *arg_root = NULL;
82char *arg_image = NULL;
83const char *arg_machine = NULL;
84const char *arg_namespace = NULL;
85uint64_t arg_vacuum_size = 0;
86uint64_t arg_vacuum_n_files = 0;
87usec_t arg_vacuum_time = 0;
88Set *arg_output_fields = NULL;
89const char *arg_pattern = NULL;
90pcre2_code *arg_compiled_pattern = NULL;
91PatternCompileCase arg_case = PATTERN_COMPILE_CASE_AUTO;
92static ImagePolicy *arg_image_policy = NULL;
6becf48c 93
2e64b27a
DDM
94STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep);
95STATIC_DESTRUCTOR_REGISTER(arg_facilities, set_freep);
96STATIC_DESTRUCTOR_REGISTER(arg_verify_key, freep);
97STATIC_DESTRUCTOR_REGISTER(arg_syslog_identifier, strv_freep);
25aa35d4 98STATIC_DESTRUCTOR_REGISTER(arg_exclude_identifier, strv_freep);
2e64b27a
DDM
99STATIC_DESTRUCTOR_REGISTER(arg_system_units, strv_freep);
100STATIC_DESTRUCTOR_REGISTER(arg_user_units, strv_freep);
101STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
102STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
c5da14cd 103STATIC_DESTRUCTOR_REGISTER(arg_output_fields, set_freep);
75db32dc 104STATIC_DESTRUCTOR_REGISTER(arg_compiled_pattern, pattern_freep);
84be0c71 105STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
2e64b27a 106
442e2def
LP
107static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
108 sd_id128_t id = SD_ID128_NULL;
109 int off = 0, r;
110
48904825 111 if (streq(x, "all")) {
112 *boot_id = SD_ID128_NULL;
113 *offset = 0;
114 return 0;
0d5765f7 115 } else if (strlen(x) >= SD_ID128_STRING_MAX - 1) {
442e2def
LP
116 char *t;
117
2f82562b 118 t = strndupa_safe(x, SD_ID128_STRING_MAX - 1);
442e2def
LP
119 r = sd_id128_from_string(t, &id);
120 if (r >= 0)
0d5765f7 121 x += SD_ID128_STRING_MAX - 1;
442e2def 122
4c701096 123 if (!IN_SET(*x, 0, '-', '+'))
442e2def
LP
124 return -EINVAL;
125
126 if (*x != 0) {
127 r = safe_atoi(x, &off);
128 if (r < 0)
129 return r;
130 }
131 } else {
132 r = safe_atoi(x, &off);
133 if (r < 0)
134 return r;
135 }
136
137 if (boot_id)
138 *boot_id = id;
139
140 if (offset)
141 *offset = off;
142
48904825 143 return 1;
442e2def
LP
144}
145
8d6791d2
MY
146static int parse_lines(const char *arg, bool graceful) {
147 const char *l;
148 int n, r;
149
150 assert(arg || graceful);
151
152 if (!arg)
153 goto default_noarg;
154
155 if (streq(arg, "all")) {
156 arg_lines = ARG_LINES_ALL;
157 return 1;
158 }
159
160 l = startswith(arg, "+");
161
162 r = safe_atoi(l ?: arg, &n);
163 if (r < 0 || n < 0) {
164 if (graceful)
165 goto default_noarg;
166
167 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse --lines='%s'.", arg);
168 }
169
170 arg_lines = n;
c8ccd444 171 arg_lines_oldest = l;
8d6791d2
MY
172
173 return 1;
174
175default_noarg:
176 arg_lines = 10;
7b5ff439 177 arg_lines_oldest = false;
8d6791d2
MY
178 return 0;
179}
180
196dedd5
ZJS
181static int help_facilities(void) {
182 if (!arg_quiet)
183 puts("Available facilities:");
184
185 for (int i = 0; i < LOG_NFACILITIES; i++) {
186 _cleanup_free_ char *t = NULL;
187
d4423350 188 if (log_facility_unshifted_to_string_alloc(i, &t) < 0)
196dedd5
ZJS
189 return log_oom();
190 puts(t);
191 }
192
193 return 0;
194}
195
37ec0fdd
LP
196static int help(void) {
197 _cleanup_free_ char *link = NULL;
198 int r;
0d43c694 199
384c2c32 200 pager_open(arg_pager_flags);
faf5077f 201
37ec0fdd
LP
202 r = terminal_urlify_man("journalctl", "1", &link);
203 if (r < 0)
204 return log_oom();
205
23d8c560
LP
206 printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
207 "%5$sQuery the journal.%6$s\n\n"
74962351 208 "%3$sSource Options:%4$s\n"
61c5f8a1
ZJS
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"
74962351
LP
212 " -m --merge Show entries from all available journals\n"
213 " -D --directory=PATH Show journal files from directory\n"
dde54b8a 214 " -i --file=PATH Show journal file\n"
84be0c71
LP
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"
74962351
LP
218 " --namespace=NAMESPACE Show journal data from specified journal namespace\n"
219 "\n%3$sFiltering Options:%4$s\n"
61c5f8a1
ZJS
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"
d9e15cbd 224 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
61c5f8a1 225 " -b --boot[=ID] Show current boot or the specified boot\n"
61c5f8a1
ZJS
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"
25aa35d4
SZ
229 " -T --exclude-identifier=STRING\n"
230 " Hide entries with the specified syslog identifier\n"
ad938537 231 " -p --priority=RANGE Show entries within the specified priority range\n"
196dedd5 232 " --facility=FACILITY... Show entries with the specified facilities\n"
fabf4dae 233 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
86b52a39 234 " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
74962351
LP
235 " -k --dmesg Show kernel message log from the current boot\n"
236 "\n%3$sOutput Control Options:%4$s\n"
61c5f8a1
ZJS
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"
8e044443
LP
240 " json, json-pretty, json-sse, json-seq, cat,\n"
241 " with-unit)\n"
61c5f8a1 242 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
8d6791d2 243 " -n --lines[=[+]INTEGER] Number of journal entries to show\n"
74962351
LP
244 " -r --reverse Show the newest entries first\n"
245 " --show-cursor Print the cursor after all the entries\n"
61c5f8a1
ZJS
246 " --utc Express time in Coordinated Universal Time (UTC)\n"
247 " -x --catalog Add message explanations where available\n"
74962351 248 " --no-hostname Suppress output of hostname field\n"
61c5f8a1
ZJS
249 " --no-full Ellipsize fields\n"
250 " -a --all Show all fields, including long and unprintable\n"
74962351
LP
251 " -f --follow Follow the journal\n"
252 " --no-tail Show all lines, even in follow mode\n"
61cecfa0 253 " --truncate-newline Truncate entries by first newline character\n"
61c5f8a1 254 " -q --quiet Do not show info messages and privilege warning\n"
74962351 255 "\n%3$sPager Control Options:%4$s\n"
61c5f8a1 256 " --no-pager Do not pipe output into a pager\n"
74962351
LP
257 " -e --pager-end Immediately jump to the end in the pager\n"
258 "\n%3$sForward Secure Sealing (FSS) Options:%4$s\n"
61c5f8a1
ZJS
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"
23d8c560 262 "\n%3$sCommands:%4$s\n"
61c5f8a1
ZJS
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"
74962351 267 " --list-boots Show terse information about recorded boots\n"
edd2b336 268 " --list-namespaces Show list of journal namespaces\n"
61c5f8a1
ZJS
269 " --disk-usage Show total disk usage of all journal files\n"
270 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
271 " --vacuum-files=INT Leave only the specified number of journal files\n"
272 " --vacuum-time=TIME Remove journal files older than specified time\n"
273 " --verify Verify journal file consistency\n"
274 " --sync Synchronize unwritten journal messages to disk\n"
c0dfcb31
LP
275 " --relinquish-var Stop logging to disk, log to temporary file system\n"
276 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
61c5f8a1
ZJS
277 " --flush Flush all journal data from /run into /var\n"
278 " --rotate Request immediate rotation of the journal files\n"
279 " --header Show journal header information\n"
280 " --list-catalog Show all message IDs in the catalog\n"
281 " --dump-catalog Show entries in the message catalog\n"
282 " --update-catalog Update the message catalog database\n"
61c5f8a1 283 " --setup-keys Generate a new FSS key pair\n"
bc556335
DDM
284 "\nSee the %2$s for details.\n",
285 program_invocation_short_name,
286 link,
287 ansi_underline(),
288 ansi_normal(),
289 ansi_highlight(),
290 ansi_normal());
37ec0fdd
LP
291
292 return 0;
0d43c694
LP
293}
294
295static int parse_argv(int argc, char *argv[]) {
296
297 enum {
298 ARG_VERSION = 0x100,
e91af489 299 ARG_NO_PAGER,
2b8f6883 300 ARG_NO_FULL,
55ee336c 301 ARG_NO_TAIL,
dca6219e 302 ARG_NEW_ID128,
8453f062 303 ARG_THIS_BOOT,
f1188074 304 ARG_LIST_BOOTS,
3f3a438f
ZJS
305 ARG_USER,
306 ARG_SYSTEM,
13cbf3a5 307 ARG_ROOT,
cc171228 308 ARG_IMAGE,
06e78680 309 ARG_IMAGE_POLICY,
7560fffc 310 ARG_HEADER,
196dedd5 311 ARG_FACILITY,
beec0085 312 ARG_SETUP_KEYS,
baed47c3 313 ARG_INTERVAL,
4da416aa 314 ARG_VERIFY,
a1a03e30 315 ARG_VERIFY_KEY,
cfbc22ab 316 ARG_DISK_USAGE,
248fc619 317 ARG_AFTER_CURSOR,
d9e15cbd 318 ARG_CURSOR_FILE,
248fc619 319 ARG_SHOW_CURSOR,
ffa7cd15 320 ARG_USER_UNIT,
d4205751 321 ARG_LIST_CATALOG,
54b7254c 322 ARG_DUMP_CATALOG,
3f3a438f 323 ARG_UPDATE_CATALOG,
b8547c10 324 ARG_FORCE,
61c5f8a1 325 ARG_CASE_SENSITIVE,
9fd29044 326 ARG_UTC,
94b65516 327 ARG_SYNC,
74055aa7 328 ARG_FLUSH,
c0dfcb31
LP
329 ARG_RELINQUISH_VAR,
330 ARG_SMART_RELINQUISH_VAR,
e3fdfb49 331 ARG_ROTATE,
61cecfa0 332 ARG_TRUNCATE_NEWLINE,
dbd2a83f 333 ARG_VACUUM_SIZE,
8580d1f7 334 ARG_VACUUM_FILES,
dbd2a83f 335 ARG_VACUUM_TIME,
991e274b 336 ARG_NO_HOSTNAME,
cc25a67e 337 ARG_OUTPUT_FIELDS,
6b25db87 338 ARG_NAMESPACE,
68f66a17 339 ARG_LIST_NAMESPACES,
0d43c694
LP
340 };
341
342 static const struct option options[] = {
c0dfcb31
LP
343 { "help", no_argument, NULL, 'h' },
344 { "version" , no_argument, NULL, ARG_VERSION },
345 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
346 { "pager-end", no_argument, NULL, 'e' },
347 { "follow", no_argument, NULL, 'f' },
348 { "force", no_argument, NULL, ARG_FORCE },
349 { "output", required_argument, NULL, 'o' },
350 { "all", no_argument, NULL, 'a' },
351 { "full", no_argument, NULL, 'l' },
352 { "no-full", no_argument, NULL, ARG_NO_FULL },
353 { "lines", optional_argument, NULL, 'n' },
61cecfa0 354 { "truncate-newline", no_argument, NULL, ARG_TRUNCATE_NEWLINE },
c0dfcb31
LP
355 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
356 { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, /* deprecated */
357 { "quiet", no_argument, NULL, 'q' },
358 { "merge", no_argument, NULL, 'm' },
359 { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */
360 { "boot", optional_argument, NULL, 'b' },
361 { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
362 { "dmesg", no_argument, NULL, 'k' },
363 { "system", no_argument, NULL, ARG_SYSTEM },
364 { "user", no_argument, NULL, ARG_USER },
365 { "directory", required_argument, NULL, 'D' },
dde54b8a 366 { "file", required_argument, NULL, 'i' },
c0dfcb31 367 { "root", required_argument, NULL, ARG_ROOT },
cc171228 368 { "image", required_argument, NULL, ARG_IMAGE },
06e78680 369 { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
c0dfcb31
LP
370 { "header", no_argument, NULL, ARG_HEADER },
371 { "identifier", required_argument, NULL, 't' },
25aa35d4 372 { "exclude-identifier", required_argument, NULL, 'T' },
c0dfcb31 373 { "priority", required_argument, NULL, 'p' },
196dedd5 374 { "facility", required_argument, NULL, ARG_FACILITY },
c0dfcb31
LP
375 { "grep", required_argument, NULL, 'g' },
376 { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE },
377 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
378 { "interval", required_argument, NULL, ARG_INTERVAL },
379 { "verify", no_argument, NULL, ARG_VERIFY },
380 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
381 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
382 { "cursor", required_argument, NULL, 'c' },
383 { "cursor-file", required_argument, NULL, ARG_CURSOR_FILE },
384 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
385 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
386 { "since", required_argument, NULL, 'S' },
387 { "until", required_argument, NULL, 'U' },
388 { "unit", required_argument, NULL, 'u' },
389 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
390 { "field", required_argument, NULL, 'F' },
391 { "fields", no_argument, NULL, 'N' },
392 { "catalog", no_argument, NULL, 'x' },
393 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
394 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
395 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
396 { "reverse", no_argument, NULL, 'r' },
397 { "machine", required_argument, NULL, 'M' },
398 { "utc", no_argument, NULL, ARG_UTC },
399 { "flush", no_argument, NULL, ARG_FLUSH },
400 { "relinquish-var", no_argument, NULL, ARG_RELINQUISH_VAR },
401 { "smart-relinquish-var", no_argument, NULL, ARG_SMART_RELINQUISH_VAR },
402 { "sync", no_argument, NULL, ARG_SYNC },
403 { "rotate", no_argument, NULL, ARG_ROTATE },
404 { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
405 { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
406 { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
407 { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
408 { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
6b25db87 409 { "namespace", required_argument, NULL, ARG_NAMESPACE },
68f66a17 410 { "list-namespaces", no_argument, NULL, ARG_LIST_NAMESPACES },
eb9da376 411 {}
0d43c694
LP
412 };
413
2100675e 414 int c, r;
0d43c694
LP
415
416 assert(argc >= 0);
417 assert(argv);
418
25aa35d4 419 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:g:c:S:U:t:T:u:NF:xrM:i:", options, NULL)) >= 0)
0d43c694
LP
420
421 switch (c) {
422
423 case 'h':
37ec0fdd 424 return help();
0d43c694
LP
425
426 case ARG_VERSION:
3f6fd1ba 427 return version();
0d43c694
LP
428
429 case ARG_NO_PAGER:
0221d68a 430 arg_pager_flags |= PAGER_DISABLE;
0d43c694
LP
431 break;
432
1b12a7b5 433 case 'e':
0221d68a 434 arg_pager_flags |= PAGER_JUMP_TO_END;
fe59e38b 435
97e1cc8b 436 if (arg_lines == ARG_LINES_DEFAULT)
fe59e38b
LP
437 arg_lines = 1000;
438
2dd9285b 439 arg_boot = true;
2dd9285b 440
1b12a7b5
HH
441 break;
442
0d43c694
LP
443 case 'f':
444 arg_follow = true;
445 break;
446
447 case 'o':
5c828e66
LP
448 if (streq(optarg, "help")) {
449 DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX);
450 return 0;
451 }
452
1705594f 453 arg_output = output_mode_from_string(optarg);
0491150b 454 if (arg_output < 0)
7211c853 455 return log_error_errno(arg_output, "Unknown output format '%s'.", optarg);
df50185b 456
8e044443 457 if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT))
edfb521a
ZJS
458 arg_quiet = true;
459
5a1355d8
FS
460 if (OUTPUT_MODE_IS_JSON(arg_output))
461 arg_json_format_flags = output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO;
faf20d4c
FS
462 else
463 arg_json_format_flags = JSON_FORMAT_OFF;
464
0d43c694
LP
465 break;
466
98a6e132 467 case 'l':
e3657ecd
ZJS
468 arg_full = true;
469 break;
470
2b8f6883
ZJS
471 case ARG_NO_FULL:
472 arg_full = false;
473 break;
474
0d43c694 475 case 'a':
cd4b13e0 476 arg_all = true;
0d43c694
LP
477 break;
478
2100675e 479 case 'n':
f2e2c93d 480 r = parse_lines(optarg ?: argv[optind], !optarg);
8d6791d2
MY
481 if (r < 0)
482 return r;
483 if (r > 0 && !optarg)
484 optind++;
1705594f 485
2100675e
LP
486 break;
487
e91af489
LP
488 case ARG_NO_TAIL:
489 arg_no_tail = true;
490 break;
491
61cecfa0 492 case ARG_TRUNCATE_NEWLINE:
493 arg_truncate_newline = true;
494 break;
495
39f7f5c1 496 case ARG_NEW_ID128:
7560fffc 497 arg_action = ACTION_NEW_ID128;
55ee336c
LP
498 break;
499
43673799
LP
500 case 'q':
501 arg_quiet = true;
490e567d 502 break;
43673799 503
9e8a535f
LP
504 case 'm':
505 arg_merge = true;
2bd3c38a
LP
506 break;
507
8453f062
ZJS
508 case ARG_THIS_BOOT:
509 arg_boot = true;
48904825 510 arg_boot_id = SD_ID128_NULL;
511 arg_boot_offset = 0;
8453f062
ZJS
512 break;
513
59cea26a 514 case 'b':
d121b396 515 arg_boot = true;
48904825 516 arg_boot_id = SD_ID128_NULL;
517 arg_boot_offset = 0;
6cebe83c 518
442e2def 519 if (optarg) {
909dea0c 520 r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
48904825 521 if (r < 0)
522 return log_error_errno(r, "Failed to parse boot descriptor '%s'", optarg);
523
524 arg_boot = r;
525
526 /* Hmm, no argument? Maybe the next
527 * word on the command line is
528 * supposed to be the argument? Let's
529 * see if there is one and is parsable
530 * as a boot descriptor... */
531 } else if (optind < argc) {
532 r = parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset);
533 if (r >= 0) {
534 arg_boot = r;
6cebe83c 535 optind++;
48904825 536 }
6cebe83c 537 }
59cea26a
LP
538 break;
539
f1188074
ZJS
540 case ARG_LIST_BOOTS:
541 arg_action = ACTION_LIST_BOOTS;
542 break;
543
99271804 544 case 'k':
d121b396 545 arg_boot = arg_dmesg = true;
99271804
ZJS
546 break;
547
3f3a438f
ZJS
548 case ARG_SYSTEM:
549 arg_journal_type |= SD_JOURNAL_SYSTEM;
550 break;
551
552 case ARG_USER:
553 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
554 break;
555
b6741478
LP
556 case 'M':
557 arg_machine = optarg;
558 break;
559
6b25db87
LP
560 case ARG_NAMESPACE:
561 if (streq(optarg, "*")) {
562 arg_namespace_flags = SD_JOURNAL_ALL_NAMESPACES;
563 arg_namespace = NULL;
564 } else if (startswith(optarg, "+")) {
565 arg_namespace_flags = SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE;
566 arg_namespace = optarg + 1;
567 } else if (isempty(optarg)) {
568 arg_namespace_flags = 0;
569 arg_namespace = NULL;
570 } else {
571 arg_namespace_flags = 0;
572 arg_namespace = optarg;
573 }
574
575 break;
576
68f66a17
FS
577 case ARG_LIST_NAMESPACES:
578 arg_action = ACTION_LIST_NAMESPACES;
579 break;
580
a963990f
LP
581 case 'D':
582 arg_directory = optarg;
583 break;
584
dde54b8a 585 case 'i':
5d1ce257
LP
586 if (streq(optarg, "-"))
587 /* An undocumented feature: we can read journal files from STDIN. We don't document
588 * this though, since after all we only support this for mmap-able, seekable files, and
7227dd81 589 * not for example pipes which are probably the primary use case for reading things from
5d1ce257
LP
590 * STDIN. To avoid confusion we hence don't document this feature. */
591 arg_file_stdin = true;
592 else {
544e146b 593 r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
5d1ce257
LP
594 if (r < 0)
595 return log_error_errno(r, "Failed to add paths: %m");
596 }
8d98da3f
ZJS
597 break;
598
13cbf3a5 599 case ARG_ROOT:
614b022c 600 r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root);
cc171228
LP
601 if (r < 0)
602 return r;
603 break;
604
605 case ARG_IMAGE:
614b022c 606 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
0f03c2a4
LP
607 if (r < 0)
608 return r;
13cbf3a5
ZJS
609 break;
610
06e78680
YW
611 case ARG_IMAGE_POLICY:
612 r = parse_image_policy_argument(optarg, &arg_image_policy);
613 if (r < 0)
614 return r;
615 break;
616
8f14c832
LP
617 case 'c':
618 arg_cursor = optarg;
619 break;
620
d9e15cbd
JS
621 case ARG_CURSOR_FILE:
622 arg_cursor_file = optarg;
623 break;
624
248fc619
ZJS
625 case ARG_AFTER_CURSOR:
626 arg_after_cursor = optarg;
627 break;
628
629 case ARG_SHOW_CURSOR:
630 arg_show_cursor = true;
631 break;
632
dca6219e 633 case ARG_HEADER:
7560fffc
LP
634 arg_action = ACTION_PRINT_HEADER;
635 break;
636
feb12d3e
LP
637 case ARG_VERIFY:
638 arg_action = ACTION_VERIFY;
639 break;
640
a1a03e30
LP
641 case ARG_DISK_USAGE:
642 arg_action = ACTION_DISK_USAGE;
643 break;
644
dbd2a83f
LP
645 case ARG_VACUUM_SIZE:
646 r = parse_size(optarg, 1024, &arg_vacuum_size);
0491150b
LP
647 if (r < 0)
648 return log_error_errno(r, "Failed to parse vacuum size: %s", optarg);
dbd2a83f 649
8df64fd0 650 arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
dbd2a83f
LP
651 break;
652
8580d1f7
LP
653 case ARG_VACUUM_FILES:
654 r = safe_atou64(optarg, &arg_vacuum_n_files);
0491150b
LP
655 if (r < 0)
656 return log_error_errno(r, "Failed to parse vacuum files: %s", optarg);
8580d1f7 657
8df64fd0 658 arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
8580d1f7
LP
659 break;
660
dbd2a83f
LP
661 case ARG_VACUUM_TIME:
662 r = parse_sec(optarg, &arg_vacuum_time);
0491150b
LP
663 if (r < 0)
664 return log_error_errno(r, "Failed to parse vacuum time: %s", optarg);
dbd2a83f 665
8df64fd0 666 arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
dbd2a83f
LP
667 break;
668
349cc4a5 669#if HAVE_GCRYPT
b8547c10
SL
670 case ARG_FORCE:
671 arg_force = true;
672 break;
673
7560fffc
LP
674 case ARG_SETUP_KEYS:
675 arg_action = ACTION_SETUP_KEYS;
dca6219e
LP
676 break;
677
baed47c3 678 case ARG_VERIFY_KEY:
e50412ef
ZJS
679 r = free_and_strdup(&arg_verify_key, optarg);
680 if (r < 0)
681 return r;
309c6b19 682 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
1075122f
ZJS
683 * in ps or htop output. */
684 memset(optarg, 'x', strlen(optarg));
e50412ef 685
0491150b 686 arg_action = ACTION_VERIFY;
e50412ef 687 arg_merge = false;
4da416aa
LP
688 break;
689
baed47c3 690 case ARG_INTERVAL:
7f602784 691 r = parse_sec(optarg, &arg_interval);
0491150b
LP
692 if (r < 0 || arg_interval <= 0)
693 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
694 "Failed to parse sealing key change interval: %s", optarg);
14d10188 695 break;
feb12d3e
LP
696#else
697 case ARG_SETUP_KEYS:
698 case ARG_VERIFY_KEY:
699 case ARG_INTERVAL:
b8547c10 700 case ARG_FORCE:
0491150b
LP
701 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
702 "Compiled without forward-secure sealing support.");
feb12d3e 703#endif
14d10188 704
941e990d
LP
705 case 'p': {
706 const char *dots;
707
708 dots = strstr(optarg, "..");
709 if (dots) {
e7238caf 710 _cleanup_free_ char *a = NULL;
941e990d
LP
711 int from, to, i;
712
713 /* a range */
714 a = strndup(optarg, dots - optarg);
715 if (!a)
716 return log_oom();
717
718 from = log_level_from_string(a);
719 to = log_level_from_string(dots + 2);
941e990d 720
0491150b 721 if (from < 0 || to < 0)
7211c853 722 return log_error_errno(from < 0 ? from : to,
0491150b 723 "Failed to parse log level range %s", optarg);
941e990d
LP
724
725 arg_priorities = 0;
726
727 if (from < to) {
728 for (i = from; i <= to; i++)
729 arg_priorities |= 1 << i;
730 } else {
731 for (i = to; i <= from; i++)
732 arg_priorities |= 1 << i;
733 }
734
735 } else {
736 int p, i;
737
738 p = log_level_from_string(optarg);
0491150b 739 if (p < 0)
7211c853 740 return log_error_errno(p, "Unknown log level %s", optarg);
941e990d
LP
741
742 arg_priorities = 0;
743
744 for (i = 0; i <= p; i++)
745 arg_priorities |= 1 << i;
746 }
747
748 break;
749 }
750
196dedd5
ZJS
751 case ARG_FACILITY: {
752 const char *p;
753
754 for (p = optarg;;) {
755 _cleanup_free_ char *fac = NULL;
756 int num;
757
758 r = extract_first_word(&p, &fac, ",", 0);
759 if (r < 0)
760 return log_error_errno(r, "Failed to parse facilities: %s", optarg);
761 if (r == 0)
762 break;
763
764 if (streq(fac, "help")) {
765 help_facilities();
766 return 0;
767 }
768
769 num = log_facility_unshifted_from_string(fac);
770 if (num < 0)
7211c853 771 return log_error_errno(num, "Bad --facility= argument \"%s\".", fac);
196dedd5 772
de7fef4b 773 if (set_ensure_put(&arg_facilities, NULL, INT_TO_PTR(num)) < 0)
196dedd5
ZJS
774 return log_oom();
775 }
776
777 break;
778 }
779
61c5f8a1
ZJS
780 case 'g':
781 arg_pattern = optarg;
6becf48c 782 break;
6becf48c 783
61c5f8a1
ZJS
784 case ARG_CASE_SENSITIVE:
785 if (optarg) {
786 r = parse_boolean(optarg);
787 if (r < 0)
788 return log_error_errno(r, "Bad --case-sensitive= argument \"%s\": %m", optarg);
75db32dc 789 arg_case = r ? PATTERN_COMPILE_CASE_SENSITIVE : PATTERN_COMPILE_CASE_INSENSITIVE;
61c5f8a1 790 } else
75db32dc 791 arg_case = PATTERN_COMPILE_CASE_SENSITIVE;
61c5f8a1
ZJS
792
793 break;
6becf48c 794
66f52924 795 case 'S':
cfbc22ab 796 r = parse_timestamp(optarg, &arg_since);
0491150b
LP
797 if (r < 0)
798 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
799 "Failed to parse timestamp: %s", optarg);
cfbc22ab
LP
800 arg_since_set = true;
801 break;
802
66f52924 803 case 'U':
cfbc22ab 804 r = parse_timestamp(optarg, &arg_until);
0491150b
LP
805 if (r < 0)
806 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
807 "Failed to parse timestamp: %s", optarg);
cfbc22ab
LP
808 arg_until_set = true;
809 break;
810
73083640
HH
811 case 't':
812 r = strv_extend(&arg_syslog_identifier, optarg);
813 if (r < 0)
814 return log_oom();
815 break;
816
25aa35d4
SZ
817 case 'T':
818 r = strv_extend(&arg_exclude_identifier, optarg);
819 if (r < 0)
820 return log_oom();
821 break;
822
7199aa96 823 case 'u':
b9e40524
HH
824 r = strv_extend(&arg_system_units, optarg);
825 if (r < 0)
826 return log_oom();
ffa7cd15
DW
827 break;
828
7199aa96 829 case ARG_USER_UNIT:
b9e40524
HH
830 r = strv_extend(&arg_user_units, optarg);
831 if (r < 0)
832 return log_oom();
c3f60ec5
LP
833 break;
834
15119c16 835 case 'F':
69e714f3 836 arg_action = ACTION_LIST_FIELDS;
15119c16
LP
837 arg_field = optarg;
838 break;
839
69e714f3
LP
840 case 'N':
841 arg_action = ACTION_LIST_FIELD_NAMES;
842 break;
843
991e274b
LP
844 case ARG_NO_HOSTNAME:
845 arg_no_hostname = true;
846 break;
847
d4205751
LP
848 case 'x':
849 arg_catalog = true;
850 break;
851
852 case ARG_LIST_CATALOG:
853 arg_action = ACTION_LIST_CATALOG;
854 break;
855
54b7254c
ZJS
856 case ARG_DUMP_CATALOG:
857 arg_action = ACTION_DUMP_CATALOG;
858 break;
859
d4205751
LP
860 case ARG_UPDATE_CATALOG:
861 arg_action = ACTION_UPDATE_CATALOG;
862 break;
863
d89d6c86
LN
864 case 'r':
865 arg_reverse = true;
866 break;
867
9fd29044
JS
868 case ARG_UTC:
869 arg_utc = true;
870 break;
871
74055aa7
LP
872 case ARG_FLUSH:
873 arg_action = ACTION_FLUSH;
874 break;
875
c0dfcb31
LP
876 case ARG_SMART_RELINQUISH_VAR: {
877 int root_mnt_id, log_mnt_id;
878
879 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
880 * if it's on the same mount as the root file system there's no point in
881 * relinquishing access and we can leave journald write to it until the very last
882 * moment. */
883
884 r = path_get_mnt_id("/", &root_mnt_id);
885 if (r < 0)
886 log_debug_errno(r, "Failed to get root mount ID, ignoring: %m");
887 else {
888 r = path_get_mnt_id("/var/log/journal/", &log_mnt_id);
889 if (r < 0)
890 log_debug_errno(r, "Failed to get journal directory mount ID, ignoring: %m");
891 else if (root_mnt_id == log_mnt_id) {
892 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
893 return 0;
894 } else
895 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
896 }
897
898 _fallthrough_;
899 }
900
901 case ARG_RELINQUISH_VAR:
902 arg_action = ACTION_RELINQUISH_VAR;
903 break;
904
e3fdfb49 905 case ARG_ROTATE:
8df64fd0 906 arg_action = arg_action == ACTION_VACUUM ? ACTION_ROTATE_AND_VACUUM : ACTION_ROTATE;
e3fdfb49
EV
907 break;
908
94b65516
LP
909 case ARG_SYNC:
910 arg_action = ACTION_SYNC;
911 break;
912
cc25a67e
LK
913 case ARG_OUTPUT_FIELDS: {
914 _cleanup_strv_free_ char **v = NULL;
915
916 v = strv_split(optarg, ",");
917 if (!v)
918 return log_oom();
919
c5da14cd
LP
920 r = set_put_strdupv(&arg_output_fields, v);
921 if (r < 0)
922 return log_oom();
923
cc25a67e
LK
924 break;
925 }
eb9da376 926 case '?':
0d43c694 927 return -EINVAL;
eb9da376
LP
928
929 default:
04499a70 930 assert_not_reached();
0d43c694 931 }
0d43c694 932
3f2203f6
YW
933 if (arg_no_tail)
934 arg_lines = ARG_LINES_ALL;
935
936 if (arg_follow && !arg_since_set && arg_lines == ARG_LINES_DEFAULT)
e91af489
LP
937 arg_lines = 10;
938
e47622a6
FS
939 if (arg_follow && !arg_merge && !arg_boot) {
940 arg_boot = true;
941 arg_boot_id = SD_ID128_NULL;
942 arg_boot_offset = 0;
943 }
944
821bf13b 945 if (!!arg_directory + !!arg_file + arg_file_stdin + !!arg_machine + !!arg_root + !!arg_image > 1)
d7a0f1f4
FS
946 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
947 "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
8d98da3f 948
d7a0f1f4
FS
949 if (arg_since_set && arg_until_set && arg_since > arg_until)
950 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
951 "--since= must be before --until=.");
cfbc22ab 952
159d1e26 953 if (!!arg_cursor + !!arg_after_cursor + !!arg_cursor_file + !!arg_since_set > 1)
d7a0f1f4 954 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
159d1e26 955 "Please specify only one of --since=, --cursor=, --cursor-file=, and --after-cursor=.");
cfbc22ab 956
d7a0f1f4
FS
957 if (arg_follow && arg_reverse)
958 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
8d6791d2
MY
959 "Please specify either --reverse or --follow, not both.");
960
961 if (arg_lines >= 0 && arg_lines_oldest && (arg_reverse || arg_follow))
962 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
963 "--lines=+N is unsupported when --reverse or --follow is specified.");
d89d6c86 964
d7a0f1f4
FS
965 if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc)
966 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
967 "Extraneous arguments starting with '%s'",
968 argv[optind]);
0b6b7c20 969
d7a0f1f4
FS
970 if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge)
971 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
972 "Using --boot or --list-boots with --merge is not supported.");
596a2329 973
e79d0b59 974 if (!strv_isempty(arg_system_units) && arg_journal_type == SD_JOURNAL_CURRENT_USER) {
52051dd8
LP
975 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
976 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
977 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
978 r = strv_extend_strv(&arg_user_units, arg_system_units, true);
979 if (r < 0)
e50412ef 980 return r;
52051dd8
LP
981
982 arg_system_units = strv_free(arg_system_units);
983 }
984
61c5f8a1 985 if (arg_pattern) {
75db32dc 986 r = pattern_compile_and_log(arg_pattern, arg_case, &arg_compiled_pattern);
61c5f8a1
ZJS
987 if (r < 0)
988 return r;
db469196 989
8d6791d2
MY
990 /* When --grep is used along with --lines without '+', i.e. when we start from the end of the
991 * journal, we don't know how many lines we can print. So we search backwards and count until
992 * enough lines have been printed or we hit the head.
c673fd52
MY
993 * An exception is that --follow might set arg_lines, so let's not imply --reverse
994 * if that is specified. */
8d6791d2 995 if (arg_lines_needs_seek_end() && !arg_follow)
db469196 996 arg_reverse = true;
61c5f8a1 997 }
61c5f8a1 998
f7f062bf
YW
999 if (!arg_follow)
1000 arg_journal_additional_open_flags = SD_JOURNAL_ASSUME_IMMUTABLE;
1001
0d43c694
LP
1002 return 1;
1003}
1004
ade2db83
YW
1005static int run(int argc, char *argv[]) {
1006 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
1007 _cleanup_(umount_and_freep) char *mounted_dir = NULL;
c3f60ec5 1008 int r;
ea18a4b5 1009
ade2db83
YW
1010 setlocale(LC_ALL, "");
1011 log_setup();
ea18a4b5 1012
ade2db83
YW
1013 r = parse_argv(argc, argv);
1014 if (r <= 0)
1015 return r;
ea18a4b5 1016
ade2db83 1017 char **args = strv_skip(argv, optind);
ea18a4b5 1018
ade2db83
YW
1019 if (arg_image) {
1020 assert(!arg_root);
ea18a4b5 1021
ade2db83
YW
1022 r = mount_image_privately_interactively(
1023 arg_image,
1024 arg_image_policy,
1025 DISSECT_IMAGE_GENERIC_ROOT |
1026 DISSECT_IMAGE_REQUIRE_ROOT |
1027 DISSECT_IMAGE_VALIDATE_OS |
1028 DISSECT_IMAGE_RELAX_VAR_CHECK |
1029 (arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS : DISSECT_IMAGE_READ_ONLY) |
1030 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
1031 &mounted_dir,
1032 /* ret_dir_fd= */ NULL,
1033 &loop_device);
b9e40524
HH
1034 if (r < 0)
1035 return r;
ea18a4b5 1036
ade2db83
YW
1037 arg_root = strdup(mounted_dir);
1038 if (!arg_root)
1039 return log_oom();
b9e40524 1040 }
c3f60ec5 1041
ade2db83 1042 switch (arg_action) {
ea18a4b5 1043
ade2db83
YW
1044 case ACTION_SHOW:
1045 return action_show(args);
ea18a4b5 1046
ade2db83
YW
1047 case ACTION_NEW_ID128:
1048 return id128_print_new(ID128_PRINT_PRETTY);
c3f60ec5 1049
ade2db83
YW
1050 case ACTION_SETUP_KEYS:
1051 return action_setup_keys();
ea18a4b5 1052
ade2db83
YW
1053 case ACTION_LIST_CATALOG:
1054 case ACTION_DUMP_CATALOG:
1055 return action_list_catalog(args);
b9e40524 1056
ade2db83
YW
1057 case ACTION_UPDATE_CATALOG:
1058 return action_update_catalog();
b9e40524 1059
ade2db83
YW
1060 case ACTION_PRINT_HEADER:
1061 return action_print_header();
c3f60ec5 1062
ade2db83
YW
1063 case ACTION_VERIFY:
1064 return action_verify();
ea18a4b5 1065
ade2db83
YW
1066 case ACTION_DISK_USAGE:
1067 return action_disk_usage();
cd34b3c6 1068
ade2db83
YW
1069 case ACTION_LIST_BOOTS:
1070 return action_list_boots();
c3f60ec5 1071
ade2db83
YW
1072 case ACTION_LIST_FIELDS:
1073 return action_list_fields();
941e990d 1074
ade2db83
YW
1075 case ACTION_LIST_FIELD_NAMES:
1076 return action_list_field_names();
941e990d 1077
ade2db83
YW
1078 case ACTION_LIST_NAMESPACES:
1079 return action_list_namespaces();
941e990d 1080
ade2db83
YW
1081 case ACTION_FLUSH:
1082 return action_flush_to_var();
941e990d 1083
ade2db83
YW
1084 case ACTION_RELINQUISH_VAR:
1085 return action_relinquish_var();
cd34b3c6 1086
ade2db83
YW
1087 case ACTION_SYNC:
1088 return action_sync();
941e990d 1089
ade2db83
YW
1090 case ACTION_ROTATE:
1091 return action_rotate();
196dedd5 1092
ade2db83
YW
1093 case ACTION_VACUUM:
1094 return action_vacuum();
196dedd5 1095
ade2db83
YW
1096 case ACTION_ROTATE_AND_VACUUM:
1097 return action_rotate_and_vacuum();
196dedd5 1098
ade2db83
YW
1099 default:
1100 assert_not_reached();
196dedd5 1101 }
87d2c1ff 1102}
9556e79b 1103
64347b97 1104DEFINE_MAIN_FUNCTION_WITH_POSITIVE_SIGNAL(run);