]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
man/systemd.mount: tmpfs automatically gains After=swap.target dep
[thirdparty/systemd.git] / src / journal / journalctl.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
87d2c1ff 2
3f6fd1ba 3#include <errno.h>
87d2c1ff 4#include <fcntl.h>
ea18a4b5 5#include <fnmatch.h>
3f6fd1ba
LP
6#include <getopt.h>
7#include <linux/fs.h>
3f6fd1ba 8#include <signal.h>
87d2c1ff 9#include <stddef.h>
3fbf9cbb 10#include <stdio.h>
3fbf9cbb 11#include <stdlib.h>
74055aa7 12#include <sys/inotify.h>
3f6fd1ba
LP
13#include <sys/stat.h>
14#include <unistd.h>
87d2c1ff 15
74055aa7 16#include "sd-bus.h"
8bebb09c 17#include "sd-device.h"
3f6fd1ba
LP
18#include "sd-journal.h"
19
f8eeeaf9 20#include "acl-util.h"
b5efdb8a 21#include "alloc-util.h"
d6b4d1c7 22#include "build.h"
3f6fd1ba 23#include "bus-error.h"
daecc5b9 24#include "bus-locator.h"
3f6fd1ba
LP
25#include "bus-util.h"
26#include "catalog.h"
f461a28d 27#include "chase.h"
c8b3094d 28#include "chattr-util.h"
28db6fbf 29#include "constants.h"
67458536 30#include "devnum-util.h"
cc171228 31#include "dissect-image.h"
3ffd4af2 32#include "fd-util.h"
68fee104 33#include "fileio.h"
5a1355d8 34#include "format-table.h"
aa892669 35#include "format-util.h"
f4f15635 36#include "fs-util.h"
3f6fd1ba 37#include "fsprg.h"
7d50b32a 38#include "glob-util.h"
3f6fd1ba 39#include "hostname-util.h"
ff7dad48 40#include "id128-print.h"
c004493c 41#include "io-util.h"
7560fffc 42#include "journal-def.h"
3f6fd1ba 43#include "journal-internal.h"
4f37cbd9 44#include "journal-util.h"
dbd2a83f 45#include "journal-vacuum.h"
3f6fd1ba 46#include "journal-verify.h"
8752c575 47#include "locale-util.h"
3f6fd1ba
LP
48#include "log.h"
49#include "logs-show.h"
9556e79b 50#include "main-func.h"
0a970718 51#include "memory-util.h"
2485b7e2 52#include "memstream-util.h"
72d95a18 53#include "missing_sched.h"
74055aa7 54#include "mkdir.h"
cc171228 55#include "mount-util.h"
c0dfcb31 56#include "mountpoint-util.h"
d8b4d14d 57#include "nulstr-util.h"
3f6fd1ba 58#include "pager.h"
614b022c 59#include "parse-argument.h"
6bedfcbb 60#include "parse-util.h"
3f6fd1ba 61#include "path-util.h"
e30c1d01 62#include "pcre2-util.h"
294bf0c3 63#include "pretty-print.h"
f1b82359 64#include "qrcode-util.h"
9bff1410 65#include "random-util.h"
78f22b97 66#include "rlimit-util.h"
3f6fd1ba
LP
67#include "set.h"
68#include "sigbus.h"
24d633e4 69#include "signal-util.h"
2e64b27a 70#include "static-destruct.h"
9bff1410 71#include "stdio-util.h"
5c828e66 72#include "string-table.h"
3f6fd1ba 73#include "strv.h"
7ccbd1ae 74#include "syslog-util.h"
288a74cc 75#include "terminal-util.h"
e4de7287 76#include "tmpfile-util.h"
3f6fd1ba 77#include "unit-name.h"
b1d4f8e1 78#include "user-util.h"
4f413af2 79#include "varlink.h"
7560fffc 80
baed47c3 81#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
ec316d19
PP
82#define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
83
97e1cc8b
LP
84enum {
85 /* Special values for arg_lines */
86 ARG_LINES_DEFAULT = -2,
87 ARG_LINES_ALL = -1,
88};
89
df50185b 90static OutputMode arg_output = OUTPUT_SHORT;
5a1355d8 91static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
9fd29044 92static bool arg_utc = false;
72f59706 93static bool arg_follow = false;
2b8f6883 94static bool arg_full = true;
cd4b13e0 95static bool arg_all = false;
0221d68a 96static PagerFlags arg_pager_flags = 0;
97e1cc8b 97static int arg_lines = ARG_LINES_DEFAULT;
f2e2c93d 98static bool arg_lines_oldest = false;
e91af489 99static bool arg_no_tail = false;
61cecfa0 100static bool arg_truncate_newline = false;
43673799 101static bool arg_quiet = false;
9e8a535f 102static bool arg_merge = false;
d121b396 103static bool arg_boot = false;
442e2def
LP
104static sd_id128_t arg_boot_id = {};
105static int arg_boot_offset = 0;
99271804 106static bool arg_dmesg = false;
991e274b 107static bool arg_no_hostname = false;
8f14c832 108static const char *arg_cursor = NULL;
d9e15cbd 109static const char *arg_cursor_file = NULL;
248fc619
ZJS
110static const char *arg_after_cursor = NULL;
111static bool arg_show_cursor = false;
a963990f 112static const char *arg_directory = NULL;
8d98da3f 113static char **arg_file = NULL;
5d1ce257 114static bool arg_file_stdin = false;
941e990d 115static int arg_priorities = 0xFF;
196dedd5 116static Set *arg_facilities = NULL;
6bae9b2a 117static char *arg_verify_key = NULL;
349cc4a5 118#if HAVE_GCRYPT
baed47c3 119static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
b8547c10 120static bool arg_force = false;
feb12d3e 121#endif
4f0165fd 122static usec_t arg_since = 0, arg_until = 0;
cfbc22ab 123static bool arg_since_set = false, arg_until_set = false;
73083640 124static char **arg_syslog_identifier = NULL;
b9e40524
HH
125static char **arg_system_units = NULL;
126static char **arg_user_units = NULL;
3c1668da 127static const char *arg_field = NULL;
d4205751 128static bool arg_catalog = false;
d89d6c86 129static bool arg_reverse = false;
3f3a438f 130static int arg_journal_type = 0;
6b25db87 131static int arg_namespace_flags = 0;
0f03c2a4 132static char *arg_root = NULL;
cc171228 133static char *arg_image = NULL;
b6741478 134static const char *arg_machine = NULL;
6b25db87 135static const char *arg_namespace = NULL;
8580d1f7
LP
136static uint64_t arg_vacuum_size = 0;
137static uint64_t arg_vacuum_n_files = 0;
138static usec_t arg_vacuum_time = 0;
c5da14cd 139static Set *arg_output_fields = NULL;
61c5f8a1
ZJS
140static const char *arg_pattern = NULL;
141static pcre2_code *arg_compiled_pattern = NULL;
75db32dc 142static PatternCompileCase arg_case = PATTERN_COMPILE_CASE_AUTO;
84be0c71 143ImagePolicy *arg_image_policy = NULL;
6becf48c 144
2e64b27a
DDM
145STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep);
146STATIC_DESTRUCTOR_REGISTER(arg_facilities, set_freep);
147STATIC_DESTRUCTOR_REGISTER(arg_verify_key, freep);
148STATIC_DESTRUCTOR_REGISTER(arg_syslog_identifier, strv_freep);
149STATIC_DESTRUCTOR_REGISTER(arg_system_units, strv_freep);
150STATIC_DESTRUCTOR_REGISTER(arg_user_units, strv_freep);
151STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
152STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
c5da14cd 153STATIC_DESTRUCTOR_REGISTER(arg_output_fields, set_freep);
75db32dc 154STATIC_DESTRUCTOR_REGISTER(arg_compiled_pattern, pattern_freep);
84be0c71 155STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
2e64b27a 156
7560fffc
LP
157static enum {
158 ACTION_SHOW,
159 ACTION_NEW_ID128,
160 ACTION_PRINT_HEADER,
beec0085 161 ACTION_SETUP_KEYS,
a1a03e30
LP
162 ACTION_VERIFY,
163 ACTION_DISK_USAGE,
d4205751 164 ACTION_LIST_CATALOG,
54b7254c 165 ACTION_DUMP_CATALOG,
f1188074
ZJS
166 ACTION_UPDATE_CATALOG,
167 ACTION_LIST_BOOTS,
74055aa7 168 ACTION_FLUSH,
c0dfcb31 169 ACTION_RELINQUISH_VAR,
a020b3b3 170 ACTION_SYNC,
e3fdfb49 171 ACTION_ROTATE,
dbd2a83f 172 ACTION_VACUUM,
8df64fd0 173 ACTION_ROTATE_AND_VACUUM,
69e714f3
LP
174 ACTION_LIST_FIELDS,
175 ACTION_LIST_FIELD_NAMES,
7560fffc
LP
176} arg_action = ACTION_SHOW;
177
795ab08f 178static int add_matches_for_device(sd_journal *j, const char *devpath) {
8bebb09c
YW
179 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
180 sd_device *d = NULL;
795ab08f 181 struct stat st;
e5ca27b7 182 int r;
795ab08f
MS
183
184 assert(j);
185 assert(devpath);
186
d7a0f1f4
FS
187 if (!path_startswith(devpath, "/dev/"))
188 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
189 "Devpath does not start with /dev/");
795ab08f 190
e5ca27b7
LP
191 if (stat(devpath, &st) < 0)
192 return log_error_errno(errno, "Couldn't stat file: %m");
795ab08f 193
a1130022 194 r = sd_device_new_from_stat_rdev(&device, &st);
e5ca27b7 195 if (r < 0)
67458536 196 return log_error_errno(r, "Failed to get device from devnum " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(st.st_rdev));
795ab08f 197
8bebb09c 198 for (d = device; d; ) {
795ab08f
MS
199 _cleanup_free_ char *match = NULL;
200 const char *subsys, *sysname, *devnode;
8bebb09c 201 sd_device *parent;
795ab08f 202
8bebb09c
YW
203 r = sd_device_get_subsystem(d, &subsys);
204 if (r < 0)
205 goto get_parent;
795ab08f 206
8bebb09c
YW
207 r = sd_device_get_sysname(d, &sysname);
208 if (r < 0)
209 goto get_parent;
795ab08f 210
605405c6 211 match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname);
795ab08f
MS
212 if (!match)
213 return log_oom();
214
215 r = sd_journal_add_match(j, match, 0);
216 if (r < 0)
217 return log_error_errno(r, "Failed to add match: %m");
218
8bebb09c 219 if (sd_device_get_devname(d, &devnode) >= 0) {
795ab08f
MS
220 _cleanup_free_ char *match1 = NULL;
221
222 r = stat(devnode, &st);
223 if (r < 0)
224 return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode);
225
67458536 226 r = asprintf(&match1, "_KERNEL_DEVICE=%c" DEVNUM_FORMAT_STR, S_ISBLK(st.st_mode) ? 'b' : 'c', DEVNUM_FORMAT_VAL(st.st_rdev));
795ab08f
MS
227 if (r < 0)
228 return log_oom();
229
230 r = sd_journal_add_match(j, match1, 0);
231 if (r < 0)
232 return log_error_errno(r, "Failed to add match: %m");
233 }
234
8bebb09c
YW
235get_parent:
236 if (sd_device_get_parent(d, &parent) < 0)
237 break;
238
239 d = parent;
795ab08f
MS
240 }
241
485fd9a7
MS
242 r = add_match_this_boot(j, arg_machine);
243 if (r < 0)
244 return log_error_errno(r, "Failed to add match for the current boot: %m");
245
795ab08f
MS
246 return 0;
247}
248
5ab99e07
LP
249static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
250
251 if (arg_utc)
7b3eb5c9 252 return format_timestamp_style(buf, l, t, TIMESTAMP_UTC);
5ab99e07
LP
253
254 return format_timestamp(buf, l, t);
255}
256
442e2def
LP
257static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
258 sd_id128_t id = SD_ID128_NULL;
259 int off = 0, r;
260
48904825 261 if (streq(x, "all")) {
262 *boot_id = SD_ID128_NULL;
263 *offset = 0;
264 return 0;
0d5765f7 265 } else if (strlen(x) >= SD_ID128_STRING_MAX - 1) {
442e2def
LP
266 char *t;
267
2f82562b 268 t = strndupa_safe(x, SD_ID128_STRING_MAX - 1);
442e2def
LP
269 r = sd_id128_from_string(t, &id);
270 if (r >= 0)
0d5765f7 271 x += SD_ID128_STRING_MAX - 1;
442e2def 272
4c701096 273 if (!IN_SET(*x, 0, '-', '+'))
442e2def
LP
274 return -EINVAL;
275
276 if (*x != 0) {
277 r = safe_atoi(x, &off);
278 if (r < 0)
279 return r;
280 }
281 } else {
282 r = safe_atoi(x, &off);
283 if (r < 0)
284 return r;
285 }
286
287 if (boot_id)
288 *boot_id = id;
289
290 if (offset)
291 *offset = off;
292
48904825 293 return 1;
442e2def
LP
294}
295
8d6791d2
MY
296static int parse_lines(const char *arg, bool graceful) {
297 const char *l;
298 int n, r;
299
300 assert(arg || graceful);
301
302 if (!arg)
303 goto default_noarg;
304
305 if (streq(arg, "all")) {
306 arg_lines = ARG_LINES_ALL;
307 return 1;
308 }
309
310 l = startswith(arg, "+");
311
312 r = safe_atoi(l ?: arg, &n);
313 if (r < 0 || n < 0) {
314 if (graceful)
315 goto default_noarg;
316
317 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse --lines='%s'.", arg);
318 }
319
320 arg_lines = n;
c8ccd444 321 arg_lines_oldest = l;
8d6791d2
MY
322
323 return 1;
324
325default_noarg:
326 arg_lines = 10;
7b5ff439 327 arg_lines_oldest = false;
8d6791d2
MY
328 return 0;
329}
330
331static bool arg_lines_needs_seek_end(void) {
332 return arg_lines >= 0 && !arg_lines_oldest;
333}
334
196dedd5
ZJS
335static int help_facilities(void) {
336 if (!arg_quiet)
337 puts("Available facilities:");
338
339 for (int i = 0; i < LOG_NFACILITIES; i++) {
340 _cleanup_free_ char *t = NULL;
341
342 if (log_facility_unshifted_to_string_alloc(i, &t))
343 return log_oom();
344 puts(t);
345 }
346
347 return 0;
348}
349
37ec0fdd
LP
350static int help(void) {
351 _cleanup_free_ char *link = NULL;
352 int r;
0d43c694 353
384c2c32 354 pager_open(arg_pager_flags);
faf5077f 355
37ec0fdd
LP
356 r = terminal_urlify_man("journalctl", "1", &link);
357 if (r < 0)
358 return log_oom();
359
23d8c560
LP
360 printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
361 "%5$sQuery the journal.%6$s\n\n"
74962351 362 "%3$sSource Options:%4$s\n"
61c5f8a1
ZJS
363 " --system Show the system journal\n"
364 " --user Show the user journal for the current user\n"
365 " -M --machine=CONTAINER Operate on local container\n"
74962351
LP
366 " -m --merge Show entries from all available journals\n"
367 " -D --directory=PATH Show journal files from directory\n"
dde54b8a 368 " -i --file=PATH Show journal file\n"
84be0c71
LP
369 " --root=PATH Operate on an alternate filesystem root\n"
370 " --image=PATH Operate on disk image as filesystem root\n"
371 " --image-policy=POLICY Specify disk image dissection policy\n"
74962351
LP
372 " --namespace=NAMESPACE Show journal data from specified journal namespace\n"
373 "\n%3$sFiltering Options:%4$s\n"
61c5f8a1
ZJS
374 " -S --since=DATE Show entries not older than the specified date\n"
375 " -U --until=DATE Show entries not newer than the specified date\n"
376 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
377 " --after-cursor=CURSOR Show entries after the specified cursor\n"
d9e15cbd 378 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
61c5f8a1 379 " -b --boot[=ID] Show current boot or the specified boot\n"
61c5f8a1
ZJS
380 " -u --unit=UNIT Show logs from the specified unit\n"
381 " --user-unit=UNIT Show logs from the specified user unit\n"
382 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
383 " -p --priority=RANGE Show entries with the specified priority\n"
196dedd5 384 " --facility=FACILITY... Show entries with the specified facilities\n"
fabf4dae 385 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
86b52a39 386 " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
74962351
LP
387 " -k --dmesg Show kernel message log from the current boot\n"
388 "\n%3$sOutput Control Options:%4$s\n"
61c5f8a1
ZJS
389 " -o --output=STRING Change journal output mode (short, short-precise,\n"
390 " short-iso, short-iso-precise, short-full,\n"
391 " short-monotonic, short-unix, verbose, export,\n"
8e044443
LP
392 " json, json-pretty, json-sse, json-seq, cat,\n"
393 " with-unit)\n"
61c5f8a1 394 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
8d6791d2 395 " -n --lines[=[+]INTEGER] Number of journal entries to show\n"
74962351
LP
396 " -r --reverse Show the newest entries first\n"
397 " --show-cursor Print the cursor after all the entries\n"
61c5f8a1
ZJS
398 " --utc Express time in Coordinated Universal Time (UTC)\n"
399 " -x --catalog Add message explanations where available\n"
74962351 400 " --no-hostname Suppress output of hostname field\n"
61c5f8a1
ZJS
401 " --no-full Ellipsize fields\n"
402 " -a --all Show all fields, including long and unprintable\n"
74962351
LP
403 " -f --follow Follow the journal\n"
404 " --no-tail Show all lines, even in follow mode\n"
61cecfa0 405 " --truncate-newline Truncate entries by first newline character\n"
61c5f8a1 406 " -q --quiet Do not show info messages and privilege warning\n"
74962351 407 "\n%3$sPager Control Options:%4$s\n"
61c5f8a1 408 " --no-pager Do not pipe output into a pager\n"
74962351
LP
409 " -e --pager-end Immediately jump to the end in the pager\n"
410 "\n%3$sForward Secure Sealing (FSS) Options:%4$s\n"
61c5f8a1
ZJS
411 " --interval=TIME Time interval for changing the FSS sealing key\n"
412 " --verify-key=KEY Specify FSS verification key\n"
413 " --force Override of the FSS key pair with --setup-keys\n"
23d8c560 414 "\n%3$sCommands:%4$s\n"
61c5f8a1
ZJS
415 " -h --help Show this help text\n"
416 " --version Show package version\n"
417 " -N --fields List all field names currently used\n"
418 " -F --field=FIELD List all values that a specified field takes\n"
74962351 419 " --list-boots Show terse information about recorded boots\n"
61c5f8a1
ZJS
420 " --disk-usage Show total disk usage of all journal files\n"
421 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
422 " --vacuum-files=INT Leave only the specified number of journal files\n"
423 " --vacuum-time=TIME Remove journal files older than specified time\n"
424 " --verify Verify journal file consistency\n"
425 " --sync Synchronize unwritten journal messages to disk\n"
c0dfcb31
LP
426 " --relinquish-var Stop logging to disk, log to temporary file system\n"
427 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
61c5f8a1
ZJS
428 " --flush Flush all journal data from /run into /var\n"
429 " --rotate Request immediate rotation of the journal files\n"
430 " --header Show journal header information\n"
431 " --list-catalog Show all message IDs in the catalog\n"
432 " --dump-catalog Show entries in the message catalog\n"
433 " --update-catalog Update the message catalog database\n"
61c5f8a1 434 " --setup-keys Generate a new FSS key pair\n"
bc556335
DDM
435 "\nSee the %2$s for details.\n",
436 program_invocation_short_name,
437 link,
438 ansi_underline(),
439 ansi_normal(),
440 ansi_highlight(),
441 ansi_normal());
37ec0fdd
LP
442
443 return 0;
0d43c694
LP
444}
445
446static int parse_argv(int argc, char *argv[]) {
447
448 enum {
449 ARG_VERSION = 0x100,
e91af489 450 ARG_NO_PAGER,
2b8f6883 451 ARG_NO_FULL,
55ee336c 452 ARG_NO_TAIL,
dca6219e 453 ARG_NEW_ID128,
8453f062 454 ARG_THIS_BOOT,
f1188074 455 ARG_LIST_BOOTS,
3f3a438f
ZJS
456 ARG_USER,
457 ARG_SYSTEM,
13cbf3a5 458 ARG_ROOT,
cc171228 459 ARG_IMAGE,
06e78680 460 ARG_IMAGE_POLICY,
7560fffc 461 ARG_HEADER,
196dedd5 462 ARG_FACILITY,
beec0085 463 ARG_SETUP_KEYS,
baed47c3 464 ARG_INTERVAL,
4da416aa 465 ARG_VERIFY,
a1a03e30 466 ARG_VERIFY_KEY,
cfbc22ab 467 ARG_DISK_USAGE,
248fc619 468 ARG_AFTER_CURSOR,
d9e15cbd 469 ARG_CURSOR_FILE,
248fc619 470 ARG_SHOW_CURSOR,
ffa7cd15 471 ARG_USER_UNIT,
d4205751 472 ARG_LIST_CATALOG,
54b7254c 473 ARG_DUMP_CATALOG,
3f3a438f 474 ARG_UPDATE_CATALOG,
b8547c10 475 ARG_FORCE,
61c5f8a1 476 ARG_CASE_SENSITIVE,
9fd29044 477 ARG_UTC,
94b65516 478 ARG_SYNC,
74055aa7 479 ARG_FLUSH,
c0dfcb31
LP
480 ARG_RELINQUISH_VAR,
481 ARG_SMART_RELINQUISH_VAR,
e3fdfb49 482 ARG_ROTATE,
61cecfa0 483 ARG_TRUNCATE_NEWLINE,
dbd2a83f 484 ARG_VACUUM_SIZE,
8580d1f7 485 ARG_VACUUM_FILES,
dbd2a83f 486 ARG_VACUUM_TIME,
991e274b 487 ARG_NO_HOSTNAME,
cc25a67e 488 ARG_OUTPUT_FIELDS,
6b25db87 489 ARG_NAMESPACE,
0d43c694
LP
490 };
491
492 static const struct option options[] = {
c0dfcb31
LP
493 { "help", no_argument, NULL, 'h' },
494 { "version" , no_argument, NULL, ARG_VERSION },
495 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
496 { "pager-end", no_argument, NULL, 'e' },
497 { "follow", no_argument, NULL, 'f' },
498 { "force", no_argument, NULL, ARG_FORCE },
499 { "output", required_argument, NULL, 'o' },
500 { "all", no_argument, NULL, 'a' },
501 { "full", no_argument, NULL, 'l' },
502 { "no-full", no_argument, NULL, ARG_NO_FULL },
503 { "lines", optional_argument, NULL, 'n' },
61cecfa0 504 { "truncate-newline", no_argument, NULL, ARG_TRUNCATE_NEWLINE },
c0dfcb31
LP
505 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
506 { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, /* deprecated */
507 { "quiet", no_argument, NULL, 'q' },
508 { "merge", no_argument, NULL, 'm' },
509 { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */
510 { "boot", optional_argument, NULL, 'b' },
511 { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
512 { "dmesg", no_argument, NULL, 'k' },
513 { "system", no_argument, NULL, ARG_SYSTEM },
514 { "user", no_argument, NULL, ARG_USER },
515 { "directory", required_argument, NULL, 'D' },
dde54b8a 516 { "file", required_argument, NULL, 'i' },
c0dfcb31 517 { "root", required_argument, NULL, ARG_ROOT },
cc171228 518 { "image", required_argument, NULL, ARG_IMAGE },
06e78680 519 { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
c0dfcb31
LP
520 { "header", no_argument, NULL, ARG_HEADER },
521 { "identifier", required_argument, NULL, 't' },
522 { "priority", required_argument, NULL, 'p' },
196dedd5 523 { "facility", required_argument, NULL, ARG_FACILITY },
c0dfcb31
LP
524 { "grep", required_argument, NULL, 'g' },
525 { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE },
526 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
527 { "interval", required_argument, NULL, ARG_INTERVAL },
528 { "verify", no_argument, NULL, ARG_VERIFY },
529 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
530 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
531 { "cursor", required_argument, NULL, 'c' },
532 { "cursor-file", required_argument, NULL, ARG_CURSOR_FILE },
533 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
534 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
535 { "since", required_argument, NULL, 'S' },
536 { "until", required_argument, NULL, 'U' },
537 { "unit", required_argument, NULL, 'u' },
538 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
539 { "field", required_argument, NULL, 'F' },
540 { "fields", no_argument, NULL, 'N' },
541 { "catalog", no_argument, NULL, 'x' },
542 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
543 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
544 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
545 { "reverse", no_argument, NULL, 'r' },
546 { "machine", required_argument, NULL, 'M' },
547 { "utc", no_argument, NULL, ARG_UTC },
548 { "flush", no_argument, NULL, ARG_FLUSH },
549 { "relinquish-var", no_argument, NULL, ARG_RELINQUISH_VAR },
550 { "smart-relinquish-var", no_argument, NULL, ARG_SMART_RELINQUISH_VAR },
551 { "sync", no_argument, NULL, ARG_SYNC },
552 { "rotate", no_argument, NULL, ARG_ROTATE },
553 { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
554 { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
555 { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
556 { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
557 { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
6b25db87 558 { "namespace", required_argument, NULL, ARG_NAMESPACE },
eb9da376 559 {}
0d43c694
LP
560 };
561
2100675e 562 int c, r;
0d43c694
LP
563
564 assert(argc >= 0);
565 assert(argv);
566
dde54b8a 567 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:g:c:S:U:t:u:NF:xrM:i:", options, NULL)) >= 0)
0d43c694
LP
568
569 switch (c) {
570
571 case 'h':
37ec0fdd 572 return help();
0d43c694
LP
573
574 case ARG_VERSION:
3f6fd1ba 575 return version();
0d43c694
LP
576
577 case ARG_NO_PAGER:
0221d68a 578 arg_pager_flags |= PAGER_DISABLE;
0d43c694
LP
579 break;
580
1b12a7b5 581 case 'e':
0221d68a 582 arg_pager_flags |= PAGER_JUMP_TO_END;
fe59e38b 583
97e1cc8b 584 if (arg_lines == ARG_LINES_DEFAULT)
fe59e38b
LP
585 arg_lines = 1000;
586
2dd9285b 587 arg_boot = true;
2dd9285b 588
1b12a7b5
HH
589 break;
590
0d43c694
LP
591 case 'f':
592 arg_follow = true;
593 break;
594
595 case 'o':
5c828e66
LP
596 if (streq(optarg, "help")) {
597 DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX);
598 return 0;
599 }
600
1705594f 601 arg_output = output_mode_from_string(optarg);
0491150b 602 if (arg_output < 0)
7211c853 603 return log_error_errno(arg_output, "Unknown output format '%s'.", optarg);
df50185b 604
8e044443 605 if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT))
edfb521a
ZJS
606 arg_quiet = true;
607
5a1355d8
FS
608 if (OUTPUT_MODE_IS_JSON(arg_output))
609 arg_json_format_flags = output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO;
faf20d4c
FS
610 else
611 arg_json_format_flags = JSON_FORMAT_OFF;
612
0d43c694
LP
613 break;
614
98a6e132 615 case 'l':
e3657ecd
ZJS
616 arg_full = true;
617 break;
618
2b8f6883
ZJS
619 case ARG_NO_FULL:
620 arg_full = false;
621 break;
622
0d43c694 623 case 'a':
cd4b13e0 624 arg_all = true;
0d43c694
LP
625 break;
626
2100675e 627 case 'n':
f2e2c93d 628 r = parse_lines(optarg ?: argv[optind], !optarg);
8d6791d2
MY
629 if (r < 0)
630 return r;
631 if (r > 0 && !optarg)
632 optind++;
1705594f 633
2100675e
LP
634 break;
635
e91af489
LP
636 case ARG_NO_TAIL:
637 arg_no_tail = true;
638 break;
639
61cecfa0 640 case ARG_TRUNCATE_NEWLINE:
641 arg_truncate_newline = true;
642 break;
643
39f7f5c1 644 case ARG_NEW_ID128:
7560fffc 645 arg_action = ACTION_NEW_ID128;
55ee336c
LP
646 break;
647
43673799
LP
648 case 'q':
649 arg_quiet = true;
490e567d 650 break;
43673799 651
9e8a535f
LP
652 case 'm':
653 arg_merge = true;
2bd3c38a
LP
654 break;
655
8453f062
ZJS
656 case ARG_THIS_BOOT:
657 arg_boot = true;
48904825 658 arg_boot_id = SD_ID128_NULL;
659 arg_boot_offset = 0;
8453f062
ZJS
660 break;
661
59cea26a 662 case 'b':
d121b396 663 arg_boot = true;
48904825 664 arg_boot_id = SD_ID128_NULL;
665 arg_boot_offset = 0;
6cebe83c 666
442e2def 667 if (optarg) {
909dea0c 668 r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
48904825 669 if (r < 0)
670 return log_error_errno(r, "Failed to parse boot descriptor '%s'", optarg);
671
672 arg_boot = r;
673
674 /* Hmm, no argument? Maybe the next
675 * word on the command line is
676 * supposed to be the argument? Let's
677 * see if there is one and is parsable
678 * as a boot descriptor... */
679 } else if (optind < argc) {
680 r = parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset);
681 if (r >= 0) {
682 arg_boot = r;
6cebe83c 683 optind++;
48904825 684 }
6cebe83c 685 }
59cea26a
LP
686 break;
687
f1188074
ZJS
688 case ARG_LIST_BOOTS:
689 arg_action = ACTION_LIST_BOOTS;
690 break;
691
99271804 692 case 'k':
d121b396 693 arg_boot = arg_dmesg = true;
99271804
ZJS
694 break;
695
3f3a438f
ZJS
696 case ARG_SYSTEM:
697 arg_journal_type |= SD_JOURNAL_SYSTEM;
698 break;
699
700 case ARG_USER:
701 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
702 break;
703
b6741478
LP
704 case 'M':
705 arg_machine = optarg;
706 break;
707
6b25db87
LP
708 case ARG_NAMESPACE:
709 if (streq(optarg, "*")) {
710 arg_namespace_flags = SD_JOURNAL_ALL_NAMESPACES;
711 arg_namespace = NULL;
712 } else if (startswith(optarg, "+")) {
713 arg_namespace_flags = SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE;
714 arg_namespace = optarg + 1;
715 } else if (isempty(optarg)) {
716 arg_namespace_flags = 0;
717 arg_namespace = NULL;
718 } else {
719 arg_namespace_flags = 0;
720 arg_namespace = optarg;
721 }
722
723 break;
724
a963990f
LP
725 case 'D':
726 arg_directory = optarg;
727 break;
728
dde54b8a 729 case 'i':
5d1ce257
LP
730 if (streq(optarg, "-"))
731 /* An undocumented feature: we can read journal files from STDIN. We don't document
732 * this though, since after all we only support this for mmap-able, seekable files, and
7227dd81 733 * not for example pipes which are probably the primary use case for reading things from
5d1ce257
LP
734 * STDIN. To avoid confusion we hence don't document this feature. */
735 arg_file_stdin = true;
736 else {
544e146b 737 r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
5d1ce257
LP
738 if (r < 0)
739 return log_error_errno(r, "Failed to add paths: %m");
740 }
8d98da3f
ZJS
741 break;
742
13cbf3a5 743 case ARG_ROOT:
614b022c 744 r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root);
cc171228
LP
745 if (r < 0)
746 return r;
747 break;
748
749 case ARG_IMAGE:
614b022c 750 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
0f03c2a4
LP
751 if (r < 0)
752 return r;
13cbf3a5
ZJS
753 break;
754
06e78680
YW
755 case ARG_IMAGE_POLICY:
756 r = parse_image_policy_argument(optarg, &arg_image_policy);
757 if (r < 0)
758 return r;
759 break;
760
8f14c832
LP
761 case 'c':
762 arg_cursor = optarg;
763 break;
764
d9e15cbd
JS
765 case ARG_CURSOR_FILE:
766 arg_cursor_file = optarg;
767 break;
768
248fc619
ZJS
769 case ARG_AFTER_CURSOR:
770 arg_after_cursor = optarg;
771 break;
772
773 case ARG_SHOW_CURSOR:
774 arg_show_cursor = true;
775 break;
776
dca6219e 777 case ARG_HEADER:
7560fffc
LP
778 arg_action = ACTION_PRINT_HEADER;
779 break;
780
feb12d3e
LP
781 case ARG_VERIFY:
782 arg_action = ACTION_VERIFY;
783 break;
784
a1a03e30
LP
785 case ARG_DISK_USAGE:
786 arg_action = ACTION_DISK_USAGE;
787 break;
788
dbd2a83f
LP
789 case ARG_VACUUM_SIZE:
790 r = parse_size(optarg, 1024, &arg_vacuum_size);
0491150b
LP
791 if (r < 0)
792 return log_error_errno(r, "Failed to parse vacuum size: %s", optarg);
dbd2a83f 793
8df64fd0 794 arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
dbd2a83f
LP
795 break;
796
8580d1f7
LP
797 case ARG_VACUUM_FILES:
798 r = safe_atou64(optarg, &arg_vacuum_n_files);
0491150b
LP
799 if (r < 0)
800 return log_error_errno(r, "Failed to parse vacuum files: %s", optarg);
8580d1f7 801
8df64fd0 802 arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
8580d1f7
LP
803 break;
804
dbd2a83f
LP
805 case ARG_VACUUM_TIME:
806 r = parse_sec(optarg, &arg_vacuum_time);
0491150b
LP
807 if (r < 0)
808 return log_error_errno(r, "Failed to parse vacuum time: %s", optarg);
dbd2a83f 809
8df64fd0 810 arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
dbd2a83f
LP
811 break;
812
349cc4a5 813#if HAVE_GCRYPT
b8547c10
SL
814 case ARG_FORCE:
815 arg_force = true;
816 break;
817
7560fffc
LP
818 case ARG_SETUP_KEYS:
819 arg_action = ACTION_SETUP_KEYS;
dca6219e
LP
820 break;
821
baed47c3 822 case ARG_VERIFY_KEY:
e50412ef
ZJS
823 r = free_and_strdup(&arg_verify_key, optarg);
824 if (r < 0)
825 return r;
309c6b19 826 /* Use memset not explicit_bzero() or similar so this doesn't look confusing
1075122f
ZJS
827 * in ps or htop output. */
828 memset(optarg, 'x', strlen(optarg));
e50412ef 829
0491150b 830 arg_action = ACTION_VERIFY;
e50412ef 831 arg_merge = false;
4da416aa
LP
832 break;
833
baed47c3 834 case ARG_INTERVAL:
7f602784 835 r = parse_sec(optarg, &arg_interval);
0491150b
LP
836 if (r < 0 || arg_interval <= 0)
837 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
838 "Failed to parse sealing key change interval: %s", optarg);
14d10188 839 break;
feb12d3e
LP
840#else
841 case ARG_SETUP_KEYS:
842 case ARG_VERIFY_KEY:
843 case ARG_INTERVAL:
b8547c10 844 case ARG_FORCE:
0491150b
LP
845 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
846 "Compiled without forward-secure sealing support.");
feb12d3e 847#endif
14d10188 848
941e990d
LP
849 case 'p': {
850 const char *dots;
851
852 dots = strstr(optarg, "..");
853 if (dots) {
e7238caf 854 _cleanup_free_ char *a = NULL;
941e990d
LP
855 int from, to, i;
856
857 /* a range */
858 a = strndup(optarg, dots - optarg);
859 if (!a)
860 return log_oom();
861
862 from = log_level_from_string(a);
863 to = log_level_from_string(dots + 2);
941e990d 864
0491150b 865 if (from < 0 || to < 0)
7211c853 866 return log_error_errno(from < 0 ? from : to,
0491150b 867 "Failed to parse log level range %s", optarg);
941e990d
LP
868
869 arg_priorities = 0;
870
871 if (from < to) {
872 for (i = from; i <= to; i++)
873 arg_priorities |= 1 << i;
874 } else {
875 for (i = to; i <= from; i++)
876 arg_priorities |= 1 << i;
877 }
878
879 } else {
880 int p, i;
881
882 p = log_level_from_string(optarg);
0491150b 883 if (p < 0)
7211c853 884 return log_error_errno(p, "Unknown log level %s", optarg);
941e990d
LP
885
886 arg_priorities = 0;
887
888 for (i = 0; i <= p; i++)
889 arg_priorities |= 1 << i;
890 }
891
892 break;
893 }
894
196dedd5
ZJS
895 case ARG_FACILITY: {
896 const char *p;
897
898 for (p = optarg;;) {
899 _cleanup_free_ char *fac = NULL;
900 int num;
901
902 r = extract_first_word(&p, &fac, ",", 0);
903 if (r < 0)
904 return log_error_errno(r, "Failed to parse facilities: %s", optarg);
905 if (r == 0)
906 break;
907
908 if (streq(fac, "help")) {
909 help_facilities();
910 return 0;
911 }
912
913 num = log_facility_unshifted_from_string(fac);
914 if (num < 0)
7211c853 915 return log_error_errno(num, "Bad --facility= argument \"%s\".", fac);
196dedd5 916
de7fef4b 917 if (set_ensure_put(&arg_facilities, NULL, INT_TO_PTR(num)) < 0)
196dedd5
ZJS
918 return log_oom();
919 }
920
921 break;
922 }
923
61c5f8a1
ZJS
924 case 'g':
925 arg_pattern = optarg;
6becf48c 926 break;
6becf48c 927
61c5f8a1
ZJS
928 case ARG_CASE_SENSITIVE:
929 if (optarg) {
930 r = parse_boolean(optarg);
931 if (r < 0)
932 return log_error_errno(r, "Bad --case-sensitive= argument \"%s\": %m", optarg);
75db32dc 933 arg_case = r ? PATTERN_COMPILE_CASE_SENSITIVE : PATTERN_COMPILE_CASE_INSENSITIVE;
61c5f8a1 934 } else
75db32dc 935 arg_case = PATTERN_COMPILE_CASE_SENSITIVE;
61c5f8a1
ZJS
936
937 break;
6becf48c 938
66f52924 939 case 'S':
cfbc22ab 940 r = parse_timestamp(optarg, &arg_since);
0491150b
LP
941 if (r < 0)
942 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
943 "Failed to parse timestamp: %s", optarg);
cfbc22ab
LP
944 arg_since_set = true;
945 break;
946
66f52924 947 case 'U':
cfbc22ab 948 r = parse_timestamp(optarg, &arg_until);
0491150b
LP
949 if (r < 0)
950 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
951 "Failed to parse timestamp: %s", optarg);
cfbc22ab
LP
952 arg_until_set = true;
953 break;
954
73083640
HH
955 case 't':
956 r = strv_extend(&arg_syslog_identifier, optarg);
957 if (r < 0)
958 return log_oom();
959 break;
960
7199aa96 961 case 'u':
b9e40524
HH
962 r = strv_extend(&arg_system_units, optarg);
963 if (r < 0)
964 return log_oom();
ffa7cd15
DW
965 break;
966
7199aa96 967 case ARG_USER_UNIT:
b9e40524
HH
968 r = strv_extend(&arg_user_units, optarg);
969 if (r < 0)
970 return log_oom();
c3f60ec5
LP
971 break;
972
15119c16 973 case 'F':
69e714f3 974 arg_action = ACTION_LIST_FIELDS;
15119c16
LP
975 arg_field = optarg;
976 break;
977
69e714f3
LP
978 case 'N':
979 arg_action = ACTION_LIST_FIELD_NAMES;
980 break;
981
991e274b
LP
982 case ARG_NO_HOSTNAME:
983 arg_no_hostname = true;
984 break;
985
d4205751
LP
986 case 'x':
987 arg_catalog = true;
988 break;
989
990 case ARG_LIST_CATALOG:
991 arg_action = ACTION_LIST_CATALOG;
992 break;
993
54b7254c
ZJS
994 case ARG_DUMP_CATALOG:
995 arg_action = ACTION_DUMP_CATALOG;
996 break;
997
d4205751
LP
998 case ARG_UPDATE_CATALOG:
999 arg_action = ACTION_UPDATE_CATALOG;
1000 break;
1001
d89d6c86
LN
1002 case 'r':
1003 arg_reverse = true;
1004 break;
1005
9fd29044
JS
1006 case ARG_UTC:
1007 arg_utc = true;
1008 break;
1009
74055aa7
LP
1010 case ARG_FLUSH:
1011 arg_action = ACTION_FLUSH;
1012 break;
1013
c0dfcb31
LP
1014 case ARG_SMART_RELINQUISH_VAR: {
1015 int root_mnt_id, log_mnt_id;
1016
1017 /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown:
1018 * if it's on the same mount as the root file system there's no point in
1019 * relinquishing access and we can leave journald write to it until the very last
1020 * moment. */
1021
1022 r = path_get_mnt_id("/", &root_mnt_id);
1023 if (r < 0)
1024 log_debug_errno(r, "Failed to get root mount ID, ignoring: %m");
1025 else {
1026 r = path_get_mnt_id("/var/log/journal/", &log_mnt_id);
1027 if (r < 0)
1028 log_debug_errno(r, "Failed to get journal directory mount ID, ignoring: %m");
1029 else if (root_mnt_id == log_mnt_id) {
1030 log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var.");
1031 return 0;
1032 } else
1033 log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it.");
1034 }
1035
1036 _fallthrough_;
1037 }
1038
1039 case ARG_RELINQUISH_VAR:
1040 arg_action = ACTION_RELINQUISH_VAR;
1041 break;
1042
e3fdfb49 1043 case ARG_ROTATE:
8df64fd0 1044 arg_action = arg_action == ACTION_VACUUM ? ACTION_ROTATE_AND_VACUUM : ACTION_ROTATE;
e3fdfb49
EV
1045 break;
1046
94b65516
LP
1047 case ARG_SYNC:
1048 arg_action = ACTION_SYNC;
1049 break;
1050
cc25a67e
LK
1051 case ARG_OUTPUT_FIELDS: {
1052 _cleanup_strv_free_ char **v = NULL;
1053
1054 v = strv_split(optarg, ",");
1055 if (!v)
1056 return log_oom();
1057
c5da14cd
LP
1058 r = set_put_strdupv(&arg_output_fields, v);
1059 if (r < 0)
1060 return log_oom();
1061
cc25a67e
LK
1062 break;
1063 }
eb9da376 1064 case '?':
0d43c694 1065 return -EINVAL;
eb9da376
LP
1066
1067 default:
04499a70 1068 assert_not_reached();
0d43c694 1069 }
0d43c694 1070
3f2203f6
YW
1071 if (arg_no_tail)
1072 arg_lines = ARG_LINES_ALL;
1073
1074 if (arg_follow && !arg_since_set && arg_lines == ARG_LINES_DEFAULT)
e91af489
LP
1075 arg_lines = 10;
1076
e47622a6
FS
1077 if (arg_follow && !arg_merge && !arg_boot) {
1078 arg_boot = true;
1079 arg_boot_id = SD_ID128_NULL;
1080 arg_boot_offset = 0;
1081 }
1082
d7a0f1f4
FS
1083 if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root + !!arg_image > 1)
1084 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1085 "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
8d98da3f 1086
d7a0f1f4
FS
1087 if (arg_since_set && arg_until_set && arg_since > arg_until)
1088 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1089 "--since= must be before --until=.");
cfbc22ab 1090
d7a0f1f4
FS
1091 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1)
1092 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
74962351 1093 "Please specify only one of --since=, --cursor=, and --after-cursor=.");
cfbc22ab 1094
d7a0f1f4
FS
1095 if (arg_follow && arg_reverse)
1096 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
8d6791d2
MY
1097 "Please specify either --reverse or --follow, not both.");
1098
1099 if (arg_lines >= 0 && arg_lines_oldest && (arg_reverse || arg_follow))
1100 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1101 "--lines=+N is unsupported when --reverse or --follow is specified.");
d89d6c86 1102
d7a0f1f4
FS
1103 if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc)
1104 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1105 "Extraneous arguments starting with '%s'",
1106 argv[optind]);
0b6b7c20 1107
d7a0f1f4
FS
1108 if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge)
1109 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1110 "Using --boot or --list-boots with --merge is not supported.");
596a2329 1111
e79d0b59 1112 if (!strv_isempty(arg_system_units) && arg_journal_type == SD_JOURNAL_CURRENT_USER) {
52051dd8
LP
1113 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
1114 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
1115 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
1116 r = strv_extend_strv(&arg_user_units, arg_system_units, true);
1117 if (r < 0)
e50412ef 1118 return r;
52051dd8
LP
1119
1120 arg_system_units = strv_free(arg_system_units);
1121 }
1122
61c5f8a1 1123 if (arg_pattern) {
75db32dc 1124 r = pattern_compile_and_log(arg_pattern, arg_case, &arg_compiled_pattern);
61c5f8a1
ZJS
1125 if (r < 0)
1126 return r;
db469196 1127
8d6791d2
MY
1128 /* When --grep is used along with --lines without '+', i.e. when we start from the end of the
1129 * journal, we don't know how many lines we can print. So we search backwards and count until
1130 * enough lines have been printed or we hit the head.
c673fd52
MY
1131 * An exception is that --follow might set arg_lines, so let's not imply --reverse
1132 * if that is specified. */
8d6791d2 1133 if (arg_lines_needs_seek_end() && !arg_follow)
db469196 1134 arg_reverse = true;
61c5f8a1 1135 }
61c5f8a1 1136
0d43c694
LP
1137 return 1;
1138}
1139
a963990f 1140static int add_matches(sd_journal *j, char **args) {
4e602943 1141 bool have_term = false;
59cea26a 1142
a963990f 1143 assert(j);
59cea26a 1144
a963990f 1145 STRV_FOREACH(i, args) {
52aeb63c 1146 int r;
59cea26a 1147
4e602943
ZJS
1148 if (streq(*i, "+")) {
1149 if (!have_term)
1150 break;
cbdca852 1151 r = sd_journal_add_disjunction(j);
4e602943
ZJS
1152 have_term = false;
1153
1154 } else if (path_is_absolute(*i)) {
e1873695 1155 _cleanup_free_ char *p = NULL, *t = NULL, *t2 = NULL, *interpreter = NULL;
a963990f 1156 struct stat st;
e5124088 1157
f461a28d 1158 r = chase(*i, NULL, CHASE_TRAIL_SLASH, &p, NULL);
e1873695
LP
1159 if (r < 0)
1160 return log_error_errno(r, "Couldn't canonicalize path: %m");
e5124088 1161
e1873695 1162 if (lstat(p, &st) < 0)
4a62c710 1163 return log_error_errno(errno, "Couldn't stat file: %m");
e5124088 1164
68fee104 1165 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
e1873695 1166 if (executable_is_script(p, &interpreter) > 0) {
c2b2df60 1167 _cleanup_free_ char *comm = NULL;
68fee104 1168
72d95a18
LP
1169 r = path_extract_filename(p, &comm);
1170 if (r < 0)
1171 return log_error_errno(r, "Failed to extract filename of '%s': %m", p);
68fee104 1172
72d95a18 1173 t = strjoin("_COMM=", strshorten(comm, TASK_COMM_LEN-1));
795ab08f
MS
1174 if (!t)
1175 return log_oom();
68fee104
ZJS
1176
1177 /* Append _EXE only if the interpreter is not a link.
73e231ab 1178 Otherwise, it might be outdated often. */
795ab08f 1179 if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) {
b910cc72 1180 t2 = strjoin("_EXE=", interpreter);
68fee104
ZJS
1181 if (!t2)
1182 return log_oom();
1183 }
795ab08f 1184 } else {
b910cc72 1185 t = strjoin("_EXE=", p);
795ab08f
MS
1186 if (!t)
1187 return log_oom();
1188 }
1189
1190 r = sd_journal_add_match(j, t, 0);
1191
1192 if (r >=0 && t2)
1193 r = sd_journal_add_match(j, t2, 0);
1194
1195 } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
e1873695 1196 r = add_matches_for_device(j, p);
795ab08f
MS
1197 if (r < 0)
1198 return r;
baaa35ad
ZJS
1199 } else
1200 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1201 "File is neither a device node, nor regular file, nor executable: %s",
1202 *i);
e5124088 1203
4e602943 1204 have_term = true;
4e602943 1205 } else {
cbdca852 1206 r = sd_journal_add_match(j, *i, 0);
4e602943
ZJS
1207 have_term = true;
1208 }
e5124088 1209
23bbb0de
MS
1210 if (r < 0)
1211 return log_error_errno(r, "Failed to add match '%s': %m", *i);
de7b95cd
LP
1212 }
1213
baaa35ad
ZJS
1214 if (!strv_isempty(args) && !have_term)
1215 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1216 "\"+\" can only be used between terms");
4e602943 1217
a963990f
LP
1218 return 0;
1219}
1220
ea7061e4 1221static int list_boots(sd_journal *j) {
5a1355d8 1222 _cleanup_(table_unrefp) Table *table = NULL;
e44f0606
YW
1223 _cleanup_free_ BootId *boots = NULL;
1224 size_t n_boots;
1225 int r;
ea7061e4
JJ
1226
1227 assert(j);
1228
8081939d 1229 r = journal_get_boots(j, &boots, &n_boots);
e44f0606
YW
1230 if (r < 0)
1231 return log_error_errno(r, "Failed to determine boots: %m");
1232 if (r == 0)
1233 return 0;
ea7061e4 1234
8e4b9a25 1235 table = table_new("idx", "boot id", "first entry", "last entry");
5a1355d8
FS
1236 if (!table)
1237 return log_oom();
f1188074 1238
5a1355d8
FS
1239 if (arg_full)
1240 table_set_width(table, 0);
f1188074 1241
8e4b9a25
FS
1242 r = table_set_json_field_name(table, 0, "index");
1243 if (r < 0)
1244 return log_error_errno(r, "Failed to set JSON field name of column 0: %m");
1245
f01aafd2
FS
1246 (void) table_set_sort(table, (size_t) 0);
1247 (void) table_set_reverse(table, 0, arg_reverse);
1248
e44f0606 1249 FOREACH_ARRAY(i, boots, n_boots) {
5a1355d8 1250 r = table_add_many(table,
e44f0606 1251 TABLE_INT, (int)(i - boots) - (int) n_boots + 1,
5a1355d8 1252 TABLE_SET_ALIGN_PERCENT, 100,
e44f0606
YW
1253 TABLE_ID128, i->id,
1254 TABLE_TIMESTAMP, i->first_usec,
1255 TABLE_TIMESTAMP, i->last_usec);
5a1355d8
FS
1256 if (r < 0)
1257 return table_log_add_error(r);
d121b396 1258 }
a963990f 1259
5a1355d8
FS
1260 r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, !arg_quiet);
1261 if (r < 0)
1262 return table_log_print_error(r);
1263
a331b5e6
JJ
1264 return 0;
1265}
1266
1267static int add_boot(sd_journal *j) {
442e2def 1268 int r;
a331b5e6
JJ
1269
1270 assert(j);
1271
d121b396 1272 if (!arg_boot)
a331b5e6
JJ
1273 return 0;
1274
592855c3
ZJS
1275 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1276 * We can do this only when we logs are coming from the current machine,
1277 * so take the slow path if log location is specified. */
3bbaff3e 1278 if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) &&
0a175093 1279 !arg_directory && !arg_file && !arg_root)
b6741478 1280 return add_match_this_boot(j, arg_machine);
a331b5e6 1281
e44f0606 1282 if (sd_id128_is_null(arg_boot_id)) {
f5257fac 1283 r = journal_find_boot_by_offset(j, arg_boot_offset, &arg_boot_id);
e44f0606
YW
1284 if (r < 0)
1285 return log_error_errno(r, "Failed to find journal entry from the specified boot offset (%+i): %m",
1286 arg_boot_offset);
1287 if (r == 0)
1288 return log_error_errno(SYNTHETIC_ERRNO(ENODATA),
1289 "No journal boot entry found from the specified boot offset (%+i).",
1290 arg_boot_offset);
1291 } else {
f5257fac 1292 r = journal_find_boot_by_id(j, arg_boot_id);
e44f0606
YW
1293 if (r < 0)
1294 return log_error_errno(r, "Failed to find journal entry from the specified boot ID (%s): %m",
1295 SD_ID128_TO_STRING(arg_boot_id));
1296 if (r == 0)
1297 return log_error_errno(SYNTHETIC_ERRNO(ENODATA),
1298 "No journal boot entry found from the specified boot ID (%s).",
1299 SD_ID128_TO_STRING(arg_boot_id));
a331b5e6
JJ
1300 }
1301
e44f0606 1302 r = add_match_boot_id(j, arg_boot_id);
23bbb0de
MS
1303 if (r < 0)
1304 return log_error_errno(r, "Failed to add match: %m");
a331b5e6
JJ
1305
1306 r = sd_journal_add_conjunction(j);
1307 if (r < 0)
b56d608e 1308 return log_error_errno(r, "Failed to add conjunction: %m");
a331b5e6
JJ
1309
1310 return 0;
a963990f
LP
1311}
1312
99271804
ZJS
1313static int add_dmesg(sd_journal *j) {
1314 int r;
1315 assert(j);
1316
1317 if (!arg_dmesg)
1318 return 0;
1319
fbd0b64f
LP
1320 r = sd_journal_add_match(j, "_TRANSPORT=kernel",
1321 STRLEN("_TRANSPORT=kernel"));
23bbb0de
MS
1322 if (r < 0)
1323 return log_error_errno(r, "Failed to add match: %m");
99271804
ZJS
1324
1325 r = sd_journal_add_conjunction(j);
1326 if (r < 0)
b56d608e 1327 return log_error_errno(r, "Failed to add conjunction: %m");
99271804
ZJS
1328
1329 return 0;
1330}
1331
b56d608e
LP
1332static int get_possible_units(
1333 sd_journal *j,
1334 const char *fields,
1335 char **patterns,
1336 Set **units) {
1337
c2b2df60 1338 _cleanup_set_free_free_ Set *found = NULL;
c3f60ec5 1339 int r;
ea18a4b5 1340
d5099efc 1341 found = set_new(&string_hash_ops);
ea18a4b5 1342 if (!found)
b56d608e 1343 return -ENOMEM;
ea18a4b5
ZJS
1344
1345 NULSTR_FOREACH(field, fields) {
1346 const void *data;
1347 size_t size;
1348
1349 r = sd_journal_query_unique(j, field);
1350 if (r < 0)
1351 return r;
1352
1353 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
de010b0b 1354 char *eq;
ea18a4b5
ZJS
1355 size_t prefix;
1356 _cleanup_free_ char *u = NULL;
1357
1358 eq = memchr(data, '=', size);
1359 if (eq)
1360 prefix = eq - (char*) data + 1;
1361 else
1362 prefix = 0;
1363
1364 u = strndup((char*) data + prefix, size - prefix);
1365 if (!u)
b56d608e 1366 return -ENOMEM;
ea18a4b5
ZJS
1367
1368 STRV_FOREACH(pattern, patterns)
1369 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1370 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1371
1372 r = set_consume(found, u);
1373 u = NULL;
1374 if (r < 0 && r != -EEXIST)
1375 return r;
1376
1377 break;
1378 }
1379 }
1380 }
1381
1cc6c93a
YW
1382 *units = TAKE_PTR(found);
1383
ea18a4b5
ZJS
1384 return 0;
1385}
1386
1387/* This list is supposed to return the superset of unit names
1388 * possibly matched by rules added with add_matches_for_unit... */
1389#define SYSTEM_UNITS \
1390 "_SYSTEMD_UNIT\0" \
1391 "COREDUMP_UNIT\0" \
1392 "UNIT\0" \
1393 "OBJECT_SYSTEMD_UNIT\0" \
1394 "_SYSTEMD_SLICE\0"
1395
1396/* ... and add_matches_for_user_unit */
1397#define USER_UNITS \
1398 "_SYSTEMD_USER_UNIT\0" \
1399 "USER_UNIT\0" \
1400 "COREDUMP_USER_UNIT\0" \
0e4a4f56
AP
1401 "OBJECT_SYSTEMD_USER_UNIT\0" \
1402 "_SYSTEMD_USER_SLICE\0"
ea18a4b5
ZJS
1403
1404static int add_units(sd_journal *j) {
1405 _cleanup_strv_free_ char **patterns = NULL;
1406 int r, count = 0;
c3f60ec5
LP
1407
1408 assert(j);
1409
b9e40524 1410 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1411 _cleanup_free_ char *u = NULL;
1412
37cbc1d5 1413 r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN), &u);
7410616c
LP
1414 if (r < 0)
1415 return r;
ea18a4b5
ZJS
1416
1417 if (string_is_glob(u)) {
1418 r = strv_push(&patterns, u);
1419 if (r < 0)
1420 return r;
1421 u = NULL;
1422 } else {
1423 r = add_matches_for_unit(j, u);
1424 if (r < 0)
1425 return r;
1426 r = sd_journal_add_disjunction(j);
1427 if (r < 0)
1428 return r;
313cefa1 1429 count++;
ea18a4b5
ZJS
1430 }
1431 }
1432
1433 if (!strv_isempty(patterns)) {
1434 _cleanup_set_free_free_ Set *units = NULL;
ea18a4b5
ZJS
1435 char *u;
1436
1437 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1438 if (r < 0)
1439 return r;
ea18a4b5 1440
90e74a66 1441 SET_FOREACH(u, units) {
ea18a4b5
ZJS
1442 r = add_matches_for_unit(j, u);
1443 if (r < 0)
1444 return r;
1445 r = sd_journal_add_disjunction(j);
1446 if (r < 0)
1447 return r;
313cefa1 1448 count++;
ea18a4b5 1449 }
b9e40524 1450 }
c3f60ec5 1451
97b11eed 1452 patterns = strv_free(patterns);
ea18a4b5 1453
b9e40524 1454 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1455 _cleanup_free_ char *u = NULL;
1456
37cbc1d5 1457 r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN), &u);
7410616c
LP
1458 if (r < 0)
1459 return r;
c3f60ec5 1460
ea18a4b5
ZJS
1461 if (string_is_glob(u)) {
1462 r = strv_push(&patterns, u);
1463 if (r < 0)
1464 return r;
1465 u = NULL;
1466 } else {
1467 r = add_matches_for_user_unit(j, u, getuid());
1468 if (r < 0)
1469 return r;
1470 r = sd_journal_add_disjunction(j);
1471 if (r < 0)
1472 return r;
313cefa1 1473 count++;
ea18a4b5
ZJS
1474 }
1475 }
1476
1477 if (!strv_isempty(patterns)) {
1478 _cleanup_set_free_free_ Set *units = NULL;
ea18a4b5 1479 char *u;
b9e40524 1480
ea18a4b5 1481 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1482 if (r < 0)
1483 return r;
1484
90e74a66 1485 SET_FOREACH(u, units) {
ea18a4b5
ZJS
1486 r = add_matches_for_user_unit(j, u, getuid());
1487 if (r < 0)
1488 return r;
1489 r = sd_journal_add_disjunction(j);
1490 if (r < 0)
1491 return r;
313cefa1 1492 count++;
ea18a4b5 1493 }
b9e40524 1494 }
c3f60ec5 1495
ea18a4b5
ZJS
1496 /* Complain if the user request matches but nothing whatsoever was
1497 * found, since otherwise everything would be matched. */
1498 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1499 return -ENODATA;
1500
cd34b3c6
HH
1501 r = sd_journal_add_conjunction(j);
1502 if (r < 0)
1503 return r;
1504
c3f60ec5
LP
1505 return 0;
1506}
1507
941e990d
LP
1508static int add_priorities(sd_journal *j) {
1509 char match[] = "PRIORITY=0";
1510 int i, r;
941e990d
LP
1511 assert(j);
1512
1513 if (arg_priorities == 0xFF)
1514 return 0;
1515
1516 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1517 if (arg_priorities & (1 << i)) {
1518 match[sizeof(match)-2] = '0' + i;
1519
941e990d 1520 r = sd_journal_add_match(j, match, strlen(match));
23bbb0de
MS
1521 if (r < 0)
1522 return log_error_errno(r, "Failed to add match: %m");
941e990d
LP
1523 }
1524
cd34b3c6
HH
1525 r = sd_journal_add_conjunction(j);
1526 if (r < 0)
b56d608e 1527 return log_error_errno(r, "Failed to add conjunction: %m");
cd34b3c6 1528
941e990d
LP
1529 return 0;
1530}
1531
196dedd5
ZJS
1532static int add_facilities(sd_journal *j) {
1533 void *p;
196dedd5
ZJS
1534 int r;
1535
90e74a66 1536 SET_FOREACH(p, arg_facilities) {
196dedd5
ZJS
1537 char match[STRLEN("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
1538
1539 xsprintf(match, "SYSLOG_FACILITY=%d", PTR_TO_INT(p));
1540
1541 r = sd_journal_add_match(j, match, strlen(match));
1542 if (r < 0)
1543 return log_error_errno(r, "Failed to add match: %m");
1544 }
1545
1546 return 0;
1547}
1548
73083640
HH
1549static int add_syslog_identifier(sd_journal *j) {
1550 int r;
73083640
HH
1551
1552 assert(j);
1553
1554 STRV_FOREACH(i, arg_syslog_identifier) {
6d946490 1555 _cleanup_free_ char *u = NULL;
73083640 1556
6d946490
YW
1557 u = strjoin("SYSLOG_IDENTIFIER=", *i);
1558 if (!u)
1559 return -ENOMEM;
73083640
HH
1560 r = sd_journal_add_match(j, u, 0);
1561 if (r < 0)
1562 return r;
1563 r = sd_journal_add_disjunction(j);
1564 if (r < 0)
1565 return r;
1566 }
1567
1568 r = sd_journal_add_conjunction(j);
1569 if (r < 0)
1570 return r;
1571
1572 return 0;
1573}
1574
7b6c92e6 1575#if HAVE_GCRYPT
f1b82359
ZJS
1576static int format_journal_url(
1577 const void *seed,
1578 size_t seed_size,
1579 uint64_t start,
1580 uint64_t interval,
1581 const char *hn,
1582 sd_id128_t machine,
1583 bool full,
1584 char **ret_url) {
2485b7e2
YW
1585
1586 _cleanup_(memstream_done) MemStream m = {};
1587 FILE *f;
f1b82359
ZJS
1588
1589 assert(seed);
1590 assert(seed_size > 0);
1591
2485b7e2 1592 f = memstream_init(&m);
f1b82359
ZJS
1593 if (!f)
1594 return -ENOMEM;
1595
1596 if (full)
1597 fputs("fss://", f);
1598
1599 for (size_t i = 0; i < seed_size; i++) {
1600 if (i > 0 && i % 3 == 0)
1601 fputc('-', f);
1602 fprintf(f, "%02x", ((uint8_t*) seed)[i]);
1603 }
1604
1605 fprintf(f, "/%"PRIx64"-%"PRIx64, start, interval);
1606
1607 if (full) {
1608 fprintf(f, "?machine=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(machine));
1609 if (hn)
1610 fprintf(f, ";hostname=%s", hn);
1611 }
1612
2485b7e2 1613 return memstream_finalize(&m, ret_url, NULL);
f1b82359 1614}
7b6c92e6 1615#endif
f1b82359 1616
7560fffc 1617static int setup_keys(void) {
349cc4a5 1618#if HAVE_GCRYPT
da012db0 1619 size_t mpk_size, seed_size, state_size;
9bff1410
LP
1620 _cleanup_(unlink_and_freep) char *k = NULL;
1621 _cleanup_free_ char *p = NULL;
7560fffc 1622 uint8_t *mpk, *seed, *state;
254d1313 1623 _cleanup_close_ int fd = -EBADF;
7560fffc 1624 sd_id128_t machine, boot;
b98e3866 1625 struct stat st;
9bff1410
LP
1626 uint64_t n;
1627 int r;
b98e3866
SL
1628
1629 r = stat("/var/log/journal", &st);
4c701096 1630 if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR))
4a62c710 1631 return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
b98e3866
SL
1632
1633 if (r < 0 || !S_ISDIR(st.st_mode)) {
1634 log_error("%s is not a directory, must be using persistent logging for FSS.",
1635 "/var/log/journal");
1636 return r < 0 ? -errno : -ENOTDIR;
1637 }
7560fffc
LP
1638
1639 r = sd_id128_get_machine(&machine);
23bbb0de
MS
1640 if (r < 0)
1641 return log_error_errno(r, "Failed to get machine ID: %m");
7560fffc
LP
1642
1643 r = sd_id128_get_boot(&boot);
23bbb0de
MS
1644 if (r < 0)
1645 return log_error_errno(r, "Failed to get boot ID: %m");
7560fffc 1646
baed47c3 1647 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1648 SD_ID128_FORMAT_VAL(machine)) < 0)
1649 return log_oom();
1650
faf9da01
ZJS
1651 if (arg_force) {
1652 r = unlink(p);
9bff1410
LP
1653 if (r < 0 && errno != ENOENT)
1654 return log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
1655 } else if (access(p, F_OK) >= 0)
1656 return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
1657 "Sealing key file %s exists already. Use --force to recreate.", p);
7560fffc 1658
baed47c3 1659 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
9bff1410
LP
1660 SD_ID128_FORMAT_VAL(machine)) < 0)
1661 return log_oom();
7560fffc
LP
1662
1663 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
698cec65 1664 mpk = alloca_safe(mpk_size);
7560fffc
LP
1665
1666 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
698cec65 1667 seed = alloca_safe(seed_size);
7560fffc
LP
1668
1669 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
698cec65 1670 state = alloca_safe(state_size);
7560fffc 1671
7560fffc 1672 log_info("Generating seed...");
87cb1ab6 1673 r = crypto_random_bytes(seed, seed_size);
9bff1410
LP
1674 if (r < 0)
1675 return log_error_errno(r, "Failed to acquire random seed: %m");
7560fffc
LP
1676
1677 log_info("Generating key pair...");
1678 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1679
baed47c3 1680 log_info("Generating sealing key...");
7560fffc
LP
1681 FSPRG_GenState0(state, mpk, seed, seed_size);
1682
baed47c3
LP
1683 assert(arg_interval > 0);
1684
7560fffc 1685 n = now(CLOCK_REALTIME);
baed47c3 1686 n /= arg_interval;
7560fffc 1687
03e334a1 1688 safe_close(fd);
646853bd 1689 fd = mkostemp_safe(k);
9bff1410
LP
1690 if (fd < 0)
1691 return log_error_errno(fd, "Failed to open %s: %m", k);
7560fffc 1692
c1631ee1
LP
1693 r = chattr_secret(fd, CHATTR_WARN_UNSUPPORTED_FLAGS);
1694 if (r < 0)
1695 log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING,
1696 r, "Failed to set file attributes on '%s', ignoring: %m", k);
f982e6f7 1697
41ab8c67 1698 struct FSSHeader h = {
9bff1410 1699 .signature = { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' },
41ab8c67
LP
1700 .machine_id = machine,
1701 .boot_id = boot,
1702 .header_size = htole64(sizeof(h)),
1703 .start_usec = htole64(n * arg_interval),
1704 .interval_usec = htole64(arg_interval),
1705 .fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR),
1706 .fsprg_state_size = htole64(state_size),
1707 };
1708
e22c60a9 1709 r = loop_write(fd, &h, sizeof(h));
9bff1410
LP
1710 if (r < 0)
1711 return log_error_errno(r, "Failed to write header: %m");
7560fffc 1712
e22c60a9 1713 r = loop_write(fd, state, state_size);
9bff1410
LP
1714 if (r < 0)
1715 return log_error_errno(r, "Failed to write state: %m");
7560fffc 1716
9bff1410
LP
1717 if (rename(k, p) < 0)
1718 return log_error_errno(errno, "Failed to link file: %m");
1719
1720 k = mfree(k);
7560fffc 1721
f1b82359
ZJS
1722 _cleanup_free_ char *hn = NULL, *key = NULL;
1723
1724 r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, false, &key);
1725 if (r < 0)
1726 return r;
da012db0 1727
8481248b 1728 if (on_tty()) {
da012db0
ZJS
1729 hn = gethostname_malloc();
1730 if (hn)
1731 hostname_cleanup(hn);
1732
7560fffc 1733 fprintf(stderr,
da012db0 1734 "\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR ".\n"
7560fffc 1735 "\n"
da012db0
ZJS
1736 "The %ssecret sealing key%s has been written to the following local file.\n"
1737 "This key file is automatically updated when the sealing key is advanced.\n"
1738 "It should not be used on multiple hosts.\n"
7560fffc
LP
1739 "\n"
1740 "\t%s\n"
1741 "\n"
da012db0
ZJS
1742 "The sealing key is automatically changed every %s.\n"
1743 "\n"
54f8c958 1744 "Please write down the following %ssecret verification key%s. It should be stored\n"
da012db0 1745 "in a safe location and should not be saved locally on disk.\n"
54f8c958 1746 "\n\t%s",
d7a0f1f4
FS
1747 strempty(hn), hn ? "/" : "",
1748 SD_ID128_FORMAT_VAL(machine),
54f8c958 1749 ansi_highlight(), ansi_normal(),
9ea78383 1750 p,
5291f26d 1751 FORMAT_TIMESPAN(arg_interval, 0),
54f8c958 1752 ansi_highlight(), ansi_normal(),
9ea78383 1753 ansi_highlight_red());
7560fffc
LP
1754 fflush(stderr);
1755 }
da012db0 1756
f1b82359 1757 puts(key);
baed47c3 1758
8481248b 1759 if (on_tty()) {
da012db0 1760 fprintf(stderr, "%s", ansi_normal());
349cc4a5 1761#if HAVE_QRENCODE
f1b82359
ZJS
1762 _cleanup_free_ char *url = NULL;
1763 r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, true, &url);
1764 if (r < 0)
1765 return r;
1766
1767 (void) print_qrcode(stderr,
1768 "To transfer the verification key to your phone scan the QR code below",
1769 url);
f6a971bc 1770#endif
baed47c3 1771 }
7560fffc 1772
9bff1410 1773 return 0;
7560fffc 1774#else
baaa35ad
ZJS
1775 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1776 "Forward-secure sealing not available.");
7560fffc
LP
1777#endif
1778}
1779
43deb1a8 1780static int verify(sd_journal *j, bool verbose) {
beec0085 1781 int r = 0;
beec0085
LP
1782 JournalFile *f;
1783
1784 assert(j);
1785
cedb42bb
LP
1786 log_show_color(true);
1787
90e74a66 1788 ORDERED_HASHMAP_FOREACH(f, j->files) {
beec0085 1789 int k;
a7f7d1bd 1790 usec_t first = 0, validated = 0, last = 0;
beec0085 1791
349cc4a5 1792#if HAVE_GCRYPT
feb12d3e 1793 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1794 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1795#endif
4da416aa 1796
43deb1a8 1797 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, verbose);
fed66db0 1798 if (k == -EINVAL)
baed47c3 1799 /* If the key was invalid give up right-away. */
56e81f7c 1800 return k;
fed66db0
YW
1801 else if (k < 0)
1802 r = log_warning_errno(k, "FAIL: %s (%m)", f->path);
1803 else {
5291f26d 1804 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
43deb1a8 1805 log_full(verbose ? LOG_INFO : LOG_DEBUG, "PASS: %s", f->path);
6c7be122 1806
c0ca7aee 1807 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1808 if (validated > 0) {
43deb1a8
DB
1809 log_full(verbose ? LOG_INFO : LOG_DEBUG,
1810 "=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1811 format_timestamp_maybe_utc(a, sizeof(a), first),
1812 format_timestamp_maybe_utc(b, sizeof(b), validated),
5291f26d 1813 FORMAT_TIMESPAN(last > validated ? last - validated : 0, 0));
2a7b539a 1814 } else if (last > 0)
43deb1a8
DB
1815 log_full(verbose ? LOG_INFO : LOG_DEBUG,
1816 "=> No sealing yet, %s of entries not sealed.",
5291f26d 1817 FORMAT_TIMESPAN(last - first, 0));
c0ca7aee 1818 else
43deb1a8
DB
1819 log_full(verbose ? LOG_INFO : LOG_DEBUG,
1820 "=> No sealing yet, no entries in file.");
c0ca7aee 1821 }
6c7be122 1822 }
beec0085
LP
1823 }
1824
1825 return r;
1826}
1827
4f413af2
LP
1828static int simple_varlink_call(const char *option, const char *method) {
1829 _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
6b25db87 1830 const char *error, *fn;
74055aa7
LP
1831 int r;
1832
4f413af2
LP
1833 if (arg_machine)
1834 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not supported in conjunction with --machine=.", option);
74055aa7 1835
6b25db87
LP
1836 fn = arg_namespace ?
1837 strjoina("/run/systemd/journal.", arg_namespace, "/io.systemd.journal") :
1838 "/run/systemd/journal/io.systemd.journal";
1839
1840 r = varlink_connect_address(&link, fn);
94b65516 1841 if (r < 0)
6b25db87 1842 return log_error_errno(r, "Failed to connect to %s: %m", fn);
77740b59
ZJS
1843
1844 (void) varlink_set_description(link, "journal");
0bd3c210 1845 (void) varlink_set_relative_timeout(link, USEC_INFINITY);
74055aa7 1846
4f413af2
LP
1847 r = varlink_call(link, method, NULL, NULL, &error, NULL);
1848 if (r < 0)
17087340
YW
1849 return log_error_errno(r, "Failed to execute varlink call: %m");
1850 if (error)
1851 return log_error_errno(SYNTHETIC_ERRNO(ENOANO),
1852 "Failed to execute varlink call: %s", error);
74055aa7 1853
4f413af2 1854 return 0;
74055aa7
LP
1855}
1856
4f413af2 1857static int flush_to_var(void) {
f6fca35e
FB
1858 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1859 return 0; /* Already flushed, no need to contact journald */
1860 if (errno != ENOENT)
1861 return log_error_errno(errno, "Unable to check for existence of /run/systemd/journal/flushed: %m");
1862
4f413af2 1863 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
94b65516
LP
1864}
1865
c0dfcb31 1866static int relinquish_var(void) {
f2083c71 1867 return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
c0dfcb31
LP
1868}
1869
dbd6e31c 1870static int rotate(void) {
4f413af2 1871 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
dbd6e31c
LP
1872}
1873
1874static int sync_journal(void) {
4f413af2 1875 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
dbd6e31c
LP
1876}
1877
2ce9a07b
YW
1878static int action_list_fields(sd_journal *j) {
1879 const void *data;
1880 size_t size;
1881 int r, n_shown = 0;
1882
1883 assert(arg_field);
1884
1885 r = sd_journal_set_data_threshold(j, 0);
1886 if (r < 0)
1887 return log_error_errno(r, "Failed to unset data size threshold: %m");
1888
1889 r = sd_journal_query_unique(j, arg_field);
1890 if (r < 0)
1891 return log_error_errno(r, "Failed to query unique data objects: %m");
1892
1893 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1894 const void *eq;
1895
1896 if (arg_lines >= 0 && n_shown >= arg_lines)
1897 break;
1898
1899 eq = memchr(data, '=', size);
1900 if (eq)
1901 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1902 else
1903 printf("%.*s\n", (int) size, (const char*) data);
1904
1905 n_shown++;
1906 }
1907
1908 return 0;
1909}
1910
8c12d358
YW
1911static int update_cursor(sd_journal *j) {
1912 _cleanup_free_ char *cursor = NULL;
1913 int r;
1914
1915 assert(j);
1916
1917 if (!arg_show_cursor && !arg_cursor_file)
1918 return 0;
1919
1920 r = sd_journal_get_cursor(j, &cursor);
1921 if (r == -EADDRNOTAVAIL)
1922 return 0;
1923 if (r < 0)
1924 return log_error_errno(r, "Failed to get cursor: %m");
1925
1926 if (arg_show_cursor)
1927 printf("-- cursor: %s\n", cursor);
1928
1929 if (arg_cursor_file) {
1930 r = write_string_file(arg_cursor_file, cursor, WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_ATOMIC);
1931 if (r < 0)
1932 return log_error_errno(r, "Failed to write new cursor to %s: %m", arg_cursor_file);
1933 }
1934
1935 return 0;
1936}
1937
e4c4a9db
YW
1938typedef struct Context {
1939 sd_journal *journal;
1940 bool need_seek;
1941 bool since_seeked;
1942 bool ellipsized;
1943 bool previous_boot_id_valid;
1944 sd_id128_t previous_boot_id;
1945 sd_id128_t previous_boot_id_output;
1946 dual_timestamp previous_ts_output;
1947} Context;
1948
1949static int show(Context *c) {
1950 sd_journal *j;
1951 int r, n_shown = 0;
1952
1953 assert(c);
1954
1955 j = ASSERT_PTR(c->journal);
1956
1957 while (arg_lines < 0 || n_shown < arg_lines || arg_follow) {
1958 int flags;
1959 size_t highlight[2] = {};
1960
1961 if (c->need_seek) {
80ec3db5 1962 r = sd_journal_step_one(j, !arg_reverse);
e4c4a9db
YW
1963 if (r < 0)
1964 return log_error_errno(r, "Failed to iterate through journal: %m");
1965 if (r == 0)
1966 break;
1967 }
1968
1969 if (arg_until_set && !arg_reverse && (arg_lines < 0 || arg_since_set)) {
1970 /* If --lines= is set, we usually rely on the n_shown to tell us
1971 * when to stop. However, if --since= is set too, we may end up
1972 * having less than --lines= to output. In this case let's also
1973 * check if the entry is in range. */
1974
1975 usec_t usec;
1976
1977 r = sd_journal_get_realtime_usec(j, &usec);
1978 if (r < 0)
1979 return log_error_errno(r, "Failed to determine timestamp: %m");
1980 if (usec > arg_until)
1981 break;
1982 }
1983
1984 if (arg_since_set && (arg_reverse || !c->since_seeked)) {
1985 usec_t usec;
1986
1987 r = sd_journal_get_realtime_usec(j, &usec);
1988 if (r < 0)
1989 return log_error_errno(r, "Failed to determine timestamp: %m");
1990
1991 if (usec < arg_since) {
1992 if (arg_reverse)
1993 break; /* Reached the earliest entry */
1994
1995 /* arg_lines >= 0 (!since_seeked):
1996 * We jumped arg_lines back and it seems to be too much */
1997 r = sd_journal_seek_realtime_usec(j, arg_since);
1998 if (r < 0)
1999 return log_error_errno(r, "Failed to seek to date: %m");
2000 c->since_seeked = true;
2001
2002 c->need_seek = true;
2003 continue;
2004 }
2005 c->since_seeked = true; /* We're surely within the range of --since now */
2006 }
2007
2008 if (!arg_merge && !arg_quiet) {
2009 sd_id128_t boot_id;
2010
2011 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2012 if (r >= 0) {
2013 if (c->previous_boot_id_valid &&
2014 !sd_id128_equal(boot_id, c->previous_boot_id))
2015 printf("%s-- Boot "SD_ID128_FORMAT_STR" --%s\n",
2016 ansi_highlight(), SD_ID128_FORMAT_VAL(boot_id), ansi_normal());
2017
2018 c->previous_boot_id = boot_id;
2019 c->previous_boot_id_valid = true;
2020 }
2021 }
2022
2023 if (arg_compiled_pattern) {
2024 const void *message;
2025 size_t len;
2026
2027 r = sd_journal_get_data(j, "MESSAGE", &message, &len);
2028 if (r < 0) {
2029 if (r == -ENOENT) {
2030 c->need_seek = true;
2031 continue;
2032 }
2033
2034 return log_error_errno(r, "Failed to get MESSAGE field: %m");
2035 }
2036
2037 assert_se(message = startswith(message, "MESSAGE="));
2038
2039 r = pattern_matches_and_log(arg_compiled_pattern, message,
2040 len - strlen("MESSAGE="), highlight);
2041 if (r < 0)
2042 return r;
2043 if (r == 0) {
2044 c->need_seek = true;
2045 continue;
2046 }
2047 }
2048
2049 flags =
2050 arg_all * OUTPUT_SHOW_ALL |
2051 arg_full * OUTPUT_FULL_WIDTH |
2052 colors_enabled() * OUTPUT_COLOR |
2053 arg_catalog * OUTPUT_CATALOG |
2054 arg_utc * OUTPUT_UTC |
61cecfa0 2055 arg_truncate_newline * OUTPUT_TRUNCATE_NEWLINE |
e4c4a9db
YW
2056 arg_no_hostname * OUTPUT_NO_HOSTNAME;
2057
2058 r = show_journal_entry(stdout, j, arg_output, 0, flags,
2059 arg_output_fields, highlight, &c->ellipsized,
2060 &c->previous_ts_output, &c->previous_boot_id_output);
2061 c->need_seek = true;
2062 if (r == -EADDRNOTAVAIL)
2063 break;
2064 if (r < 0)
2065 return r;
2066
2067 n_shown++;
2068
2069 /* If journalctl take a long time to process messages, and during that time journal file
2070 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2071 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2072 * in the "following" case. By periodically calling sd_journal_process() during the processing
2073 * loop we shrink the window of time a client instance has open file descriptors for rotated
2074 * (deleted) journal files. */
2075 if ((n_shown % PROCESS_INOTIFY_INTERVAL) == 0) {
2076 r = sd_journal_process(j);
2077 if (r < 0)
2078 return log_error_errno(r, "Failed to process inotify events: %m");
2079 }
2080 }
2081
2082 return n_shown;
2083}
2084
713342d9
YW
2085static int show_and_fflush(Context *c, sd_event_source *s) {
2086 int r;
2087
2088 assert(c);
2089 assert(s);
2090
2091 r = show(c);
2092 if (r < 0)
2093 return sd_event_exit(sd_event_source_get_event(s), r);
2094
2095 fflush(stdout);
2096 return 0;
2097}
2098
2099static int on_journal_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
2100 Context *c = ASSERT_PTR(userdata);
2101 int r;
2102
2103 assert(s);
2104
2105 r = sd_journal_process(c->journal);
2106 if (r < 0) {
2107 log_error_errno(r, "Failed to process journal events: %m");
2108 return sd_event_exit(sd_event_source_get_event(s), r);
2109 }
2110
2111 return show_and_fflush(c, s);
2112}
2113
2114static int on_first_event(sd_event_source *s, void *userdata) {
2115 return show_and_fflush(userdata, s);
2116}
2117
24d633e4
YW
2118static int on_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
2119 assert(s);
2120 assert(si);
2121 assert(IN_SET(si->ssi_signo, SIGTERM, SIGINT));
2122
2123 return sd_event_exit(sd_event_source_get_event(s), si->ssi_signo);
2124}
2125
713342d9
YW
2126static int setup_event(Context *c, int fd, sd_event **ret) {
2127 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
2128 int r;
2129
2130 assert(arg_follow);
2131 assert(c);
2132 assert(fd >= 0);
2133 assert(ret);
2134
2135 r = sd_event_default(&e);
2136 if (r < 0)
2137 return log_error_errno(r, "Failed to allocate sd_event object: %m");
2138
24d633e4
YW
2139 (void) sd_event_add_signal(e, NULL, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, on_signal, NULL);
2140 (void) sd_event_add_signal(e, NULL, SIGINT | SD_EVENT_SIGNAL_PROCMASK, on_signal, NULL);
2141
713342d9
YW
2142 r = sd_event_add_io(e, NULL, fd, EPOLLIN, &on_journal_event, c);
2143 if (r < 0)
2144 return log_error_errno(r, "Failed to add io event source for journal: %m");
2145
9050632e
LP
2146 /* Also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that, i.e. when it is closed. */
2147 r = sd_event_add_io(e, NULL, STDOUT_FILENO, EPOLLHUP|EPOLLERR, NULL, INT_TO_PTR(-ECANCELED));
2148 if (r == -EPERM)
2149 /* Installing an epoll watch on a regular file doesn't work and fails with EPERM. Which is
2150 * totally OK, handle it gracefully. epoll_ctl() documents EPERM as the error returned when
2151 * the specified fd doesn't support epoll, hence it's safe to check for that. */
2152 log_debug_errno(r, "Unable to install EPOLLHUP watch on stderr, not watching for hangups.");
2153 else if (r < 0)
2154 return log_error_errno(r, "Failed to add io event source for stdout: %m");
713342d9
YW
2155
2156 if (arg_lines != 0 || arg_since_set) {
2157 r = sd_event_add_defer(e, NULL, on_first_event, c);
2158 if (r < 0)
2159 return log_error_errno(r, "Failed to add defer event source: %m");
2160 }
2161
2162 *ret = TAKE_PTR(e);
2163 return 0;
2164}
2165
9556e79b 2166static int run(int argc, char *argv[]) {
4207a557 2167 bool need_seek = false, since_seeked = false, after_cursor = false;
cc171228 2168 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
a4b3e942 2169 _cleanup_(umount_and_freep) char *mounted_dir = NULL;
4afd3348 2170 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
4207a557
FS
2171 _cleanup_free_ char *cursor_from_file = NULL;
2172 const char *cursor = NULL;
e4c4a9db 2173 int n_shown, r, poll_fd = -EBADF;
a963990f 2174
a9cdc94f 2175 setlocale(LC_ALL, "");
d2acb93d 2176 log_setup();
a963990f 2177
1abaf488
LP
2178 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2179 * split up into many files. */
2180 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
2181
a963990f
LP
2182 r = parse_argv(argc, argv);
2183 if (r <= 0)
9556e79b 2184 return r;
a963990f 2185
cc171228
LP
2186 if (arg_image) {
2187 assert(!arg_root);
2188
2189 r = mount_image_privately_interactively(
2190 arg_image,
84be0c71 2191 arg_image_policy,
4b5de5dd
LP
2192 DISSECT_IMAGE_GENERIC_ROOT |
2193 DISSECT_IMAGE_REQUIRE_ROOT |
2194 DISSECT_IMAGE_VALIDATE_OS |
2195 DISSECT_IMAGE_RELAX_VAR_CHECK |
c65f854a 2196 (arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS : DISSECT_IMAGE_READ_ONLY),
a4b3e942 2197 &mounted_dir,
a133d2c3 2198 /* ret_dir_fd= */ NULL,
e330f97a 2199 &loop_device);
cc171228
LP
2200 if (r < 0)
2201 return r;
2202
a4b3e942 2203 arg_root = strdup(mounted_dir);
cc171228
LP
2204 if (!arg_root)
2205 return log_oom();
2206 }
2207
ed757c0c 2208 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 2209 sigbus_install();
ed757c0c 2210
a020b3b3 2211 switch (arg_action) {
94b65516 2212
a020b3b3 2213 case ACTION_NEW_ID128:
9556e79b 2214 return id128_print_new(ID128_PRINT_PRETTY);
e3fdfb49 2215
a020b3b3 2216 case ACTION_SETUP_KEYS:
9556e79b 2217 return setup_keys();
844ec79b 2218
a020b3b3
LP
2219 case ACTION_LIST_CATALOG:
2220 case ACTION_DUMP_CATALOG:
2221 case ACTION_UPDATE_CATALOG: {
c2b2df60 2222 _cleanup_free_ char *database = NULL;
0c6ea3a4 2223
fba84e12 2224 database = path_join(arg_root, secure_getenv("SYSTEMD_CATALOG") ?: CATALOG_DATABASE);
9556e79b
YW
2225 if (!database)
2226 return log_oom();
13cbf3a5 2227
844ec79b 2228 if (arg_action == ACTION_UPDATE_CATALOG) {
fba84e12
LP
2229 const char *e;
2230
2231 e = secure_getenv("SYSTEMD_CATALOG_SOURCES");
2232
2233 r = catalog_update(
2234 database,
2235 arg_root,
2236 e ? (const char* const*) STRV_MAKE(e) : catalog_file_dirs);
844ec79b 2237 if (r < 0)
9556e79b 2238 return log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
2239 } else {
2240 bool oneline = arg_action == ACTION_LIST_CATALOG;
2241
384c2c32 2242 pager_open(arg_pager_flags);
a020b3b3 2243
844ec79b 2244 if (optind < argc)
a020b3b3 2245 r = catalog_list_items(stdout, database, oneline, argv + optind);
844ec79b 2246 else
13cbf3a5 2247 r = catalog_list(stdout, database, oneline);
844ec79b 2248 if (r < 0)
9556e79b 2249 return log_error_errno(r, "Failed to list catalog: %m");
844ec79b 2250 }
d4205751 2251
9556e79b 2252 return 0;
d4205751
LP
2253 }
2254
a020b3b3 2255 case ACTION_FLUSH:
9556e79b 2256 return flush_to_var();
a020b3b3 2257
c0dfcb31 2258 case ACTION_RELINQUISH_VAR:
9556e79b 2259 return relinquish_var();
c0dfcb31 2260
a020b3b3 2261 case ACTION_SYNC:
9556e79b 2262 return sync_journal();
a020b3b3
LP
2263
2264 case ACTION_ROTATE:
9556e79b 2265 return rotate();
a020b3b3
LP
2266
2267 case ACTION_SHOW:
2268 case ACTION_PRINT_HEADER:
2269 case ACTION_VERIFY:
2270 case ACTION_DISK_USAGE:
2271 case ACTION_LIST_BOOTS:
2272 case ACTION_VACUUM:
8df64fd0 2273 case ACTION_ROTATE_AND_VACUUM:
69e714f3
LP
2274 case ACTION_LIST_FIELDS:
2275 case ACTION_LIST_FIELD_NAMES:
a020b3b3
LP
2276 /* These ones require access to the journal files, continue below. */
2277 break;
2278
2279 default:
04499a70 2280 assert_not_reached();
a020b3b3
LP
2281 }
2282
a963990f 2283 if (arg_directory)
3f3a438f 2284 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
0a175093
ZJS
2285 else if (arg_root)
2286 r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
33ff7464
LP
2287 else if (arg_file_stdin)
2288 r = sd_journal_open_files_fd(&j, (int[]) { STDIN_FILENO }, 1, 0);
2289 else if (arg_file)
8d98da3f 2290 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
2ec1fb31
YW
2291 else if (arg_machine)
2292 r = journal_open_machine(&j, arg_machine);
2293 else
6b25db87
LP
2294 r = sd_journal_open_namespace(
2295 &j,
2296 arg_namespace,
2297 (arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY) |
2298 arg_namespace_flags | arg_journal_type);
9556e79b
YW
2299 if (r < 0)
2300 return log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
a963990f 2301
e79d0b59
ZJS
2302 r = journal_access_check_and_warn(j, arg_quiet,
2303 !(arg_journal_type == SD_JOURNAL_CURRENT_USER || arg_user_units));
6fe391c5 2304 if (r < 0)
9556e79b 2305 return r;
6fe391c5 2306
a020b3b3 2307 switch (arg_action) {
beec0085 2308
a020b3b3
LP
2309 case ACTION_NEW_ID128:
2310 case ACTION_SETUP_KEYS:
2311 case ACTION_LIST_CATALOG:
2312 case ACTION_DUMP_CATALOG:
2313 case ACTION_UPDATE_CATALOG:
2314 case ACTION_FLUSH:
2315 case ACTION_SYNC:
2316 case ACTION_ROTATE:
04499a70 2317 assert_not_reached();
a020b3b3
LP
2318
2319 case ACTION_PRINT_HEADER:
dca6219e 2320 journal_print_header(j);
9556e79b 2321 return 0;
dca6219e 2322
a020b3b3 2323 case ACTION_VERIFY:
9556e79b 2324 return verify(j, !arg_quiet);
a020b3b3
LP
2325
2326 case ACTION_DISK_USAGE: {
39883f62 2327 uint64_t bytes = 0;
a1a03e30
LP
2328
2329 r = sd_journal_get_usage(j, &bytes);
2330 if (r < 0)
9556e79b 2331 return r;
a1a03e30 2332
8da830bc 2333 printf("Archived and active journals take up %s in the file system.\n",
2b59bf51 2334 FORMAT_BYTES(bytes));
9556e79b
YW
2335
2336 return 0;
a1a03e30
LP
2337 }
2338
a020b3b3 2339 case ACTION_LIST_BOOTS:
9556e79b 2340 return list_boots(j);
a020b3b3 2341
8df64fd0
LP
2342 case ACTION_ROTATE_AND_VACUUM:
2343
2344 r = rotate();
2345 if (r < 0)
9556e79b 2346 return r;
8df64fd0
LP
2347
2348 _fallthrough_;
2349
a020b3b3 2350 case ACTION_VACUUM: {
dbd2a83f 2351 Directory *d;
9556e79b 2352 int ret = 0;
dbd2a83f 2353
90e74a66 2354 HASHMAP_FOREACH(d, j->directories_by_path) {
9556e79b
YW
2355 r = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, !arg_quiet);
2356 if (r < 0) {
2357 log_error_errno(r, "Failed to vacuum %s: %m", d->path);
2358 if (ret >= 0)
2359 ret = r;
2360 }
dbd2a83f
LP
2361 }
2362
9556e79b 2363 return ret;
dbd2a83f
LP
2364 }
2365
69e714f3
LP
2366 case ACTION_LIST_FIELD_NAMES: {
2367 const char *field;
2368
9556e79b 2369 SD_JOURNAL_FOREACH_FIELD(j, field)
69e714f3 2370 printf("%s\n", field);
69e714f3 2371
9556e79b 2372 return 0;
69e714f3
LP
2373 }
2374
a020b3b3 2375 case ACTION_SHOW:
69e714f3 2376 case ACTION_LIST_FIELDS:
a020b3b3
LP
2377 break;
2378
2379 default:
04499a70 2380 assert_not_reached();
f1188074
ZJS
2381 }
2382
0f1a9a83
JS
2383 if (arg_boot_offset != 0 &&
2384 sd_journal_has_runtime_files(j) > 0 &&
2385 sd_journal_has_persistent_files(j) == 0) {
493097ee 2386 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
9556e79b
YW
2387
2388 if (arg_action == ACTION_SHOW && arg_compiled_pattern)
2389 return -ENOENT;
2390
2391 return 0;
0f1a9a83 2392 }
a331b5e6
JJ
2393 /* add_boot() must be called first!
2394 * It may need to seek the journal to find parent boot IDs. */
2395 r = add_boot(j);
a963990f 2396 if (r < 0)
9556e79b 2397 return r;
a963990f 2398
99271804
ZJS
2399 r = add_dmesg(j);
2400 if (r < 0)
9556e79b 2401 return r;
99271804 2402
b9e40524 2403 r = add_units(j);
9556e79b
YW
2404 if (r < 0)
2405 return log_error_errno(r, "Failed to add filter for units: %m");
c3f60ec5 2406
73083640 2407 r = add_syslog_identifier(j);
9556e79b
YW
2408 if (r < 0)
2409 return log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
73083640 2410
cd34b3c6 2411 r = add_priorities(j);
b56d608e 2412 if (r < 0)
9556e79b 2413 return r;
a963990f 2414
196dedd5
ZJS
2415 r = add_facilities(j);
2416 if (r < 0)
9556e79b 2417 return r;
196dedd5 2418
cd34b3c6 2419 r = add_matches(j, argv + optind);
b56d608e 2420 if (r < 0)
9556e79b 2421 return r;
941e990d 2422
f1d34068 2423 if (DEBUG_LOGGING) {
c2b2df60 2424 _cleanup_free_ char *filter = NULL;
4ad16808
ZJS
2425
2426 filter = journal_make_match_string(j);
b56d608e
LP
2427 if (!filter)
2428 return log_oom();
2429
4ad16808
ZJS
2430 log_debug("Journal filter: %s", filter);
2431 }
67e04a48 2432
2ce9a07b
YW
2433 if (arg_action == ACTION_LIST_FIELDS)
2434 return action_list_fields(j);
15119c16 2435
8d98da3f
ZJS
2436 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2437 if (arg_follow) {
2a1e0f22
LP
2438 poll_fd = sd_journal_get_fd(j);
2439 if (poll_fd == -EMFILE) {
5238e957 2440 log_warning_errno(poll_fd, "Insufficient watch descriptors available. Reverting to -n.");
321ed364 2441 arg_follow = false;
9556e79b
YW
2442 } else if (poll_fd == -EMEDIUMTYPE)
2443 return log_error_errno(poll_fd, "The --follow switch is not supported in conjunction with reading from STDIN.");
2444 else if (poll_fd < 0)
2445 return log_error_errno(poll_fd, "Failed to get journal fd: %m");
8d98da3f
ZJS
2446 }
2447
d9e15cbd 2448 if (arg_cursor || arg_after_cursor || arg_cursor_file) {
4207a557 2449 cursor = arg_cursor ?: arg_after_cursor;
d9e15cbd
JS
2450
2451 if (arg_cursor_file) {
2452 r = read_one_line_file(arg_cursor_file, &cursor_from_file);
9556e79b
YW
2453 if (r < 0 && r != -ENOENT)
2454 return log_error_errno(r, "Failed to read cursor file %s: %m", arg_cursor_file);
d9e15cbd
JS
2455
2456 if (r > 0) {
2457 cursor = cursor_from_file;
2458 after_cursor = true;
2459 }
2460 } else
d7a0f1f4 2461 after_cursor = arg_after_cursor;
4207a557 2462 }
d9e15cbd 2463
4207a557
FS
2464 if (cursor) {
2465 r = sd_journal_seek_cursor(j, cursor);
2466 if (r < 0)
2467 return log_error_errno(r, "Failed to seek to cursor: %m");
9556e79b 2468
4207a557
FS
2469 r = sd_journal_step_one(j, !arg_reverse);
2470 if (r < 0)
2471 return log_error_errno(r, "Failed to iterate through journal: %m");
2472
2473 if (after_cursor && r > 0) {
2474 /* With --after-cursor=/--cursor-file= we want to skip the first entry only if it's
2475 * the entry the cursor is pointing at, otherwise, if some journal filters are used,
2476 * we might skip the first entry of the filter match, which leads to unexpectedly
2477 * missing journal entries. */
2478 int k;
2479
2480 k = sd_journal_test_cursor(j, cursor);
2481 if (k < 0)
2482 return log_error_errno(k, "Failed to test cursor against current entry: %m");
2483 if (k > 0)
2484 /* Current entry matches the one our cursor is pointing at, so let's try
2485 * to advance the next entry. */
2486 r = sd_journal_step_one(j, !arg_reverse);
08984293 2487 }
248fc619 2488
4207a557 2489 if (r == 0) {
248fc619 2490 /* We couldn't find the next entry after the cursor. */
8ee8e536
WD
2491 if (arg_follow)
2492 need_seek = true;
2493 else
2494 arg_lines = 0;
2495 }
8d6791d2
MY
2496 } else if (arg_until_set && (arg_reverse || arg_lines_needs_seek_end())) {
2497 /* If both --until and any of --reverse and --lines=N is specified, things get
81fb5375
MY
2498 * a little tricky. We seek to the place of --until first. If only --reverse or
2499 * --reverse and --lines is specified, we search backwards and let the output
2500 * counter handle --lines for us. If only --lines is used, we just jump backwards
2501 * arg_lines and search afterwards from there. */
2502
d89d6c86 2503 r = sd_journal_seek_realtime_usec(j, arg_until);
9556e79b
YW
2504 if (r < 0)
2505 return log_error_errno(r, "Failed to seek to date: %m");
2506
81fb5375
MY
2507 if (arg_reverse)
2508 r = sd_journal_previous(j);
8d6791d2 2509 else /* arg_lines_needs_seek_end */
81fb5375 2510 r = sd_journal_previous_skip(j, arg_lines);
d89d6c86 2511
23b39216 2512 } else if (arg_reverse) {
2100675e 2513 r = sd_journal_seek_tail(j);
9556e79b
YW
2514 if (r < 0)
2515 return log_error_errno(r, "Failed to seek to tail: %m");
2100675e 2516
23b39216 2517 r = sd_journal_previous(j);
8f14c832 2518
8d6791d2 2519 } else if (arg_lines_needs_seek_end()) {
d89d6c86 2520 r = sd_journal_seek_tail(j);
9556e79b
YW
2521 if (r < 0)
2522 return log_error_errno(r, "Failed to seek to tail: %m");
d89d6c86 2523
23b39216 2524 r = sd_journal_previous_skip(j, arg_lines);
d89d6c86 2525
f5826951
MY
2526 } else if (arg_since_set) {
2527 /* This is placed after arg_reverse and arg_lines. If --since is used without
2528 * both, we seek to the place of --since and search afterwards from there.
2529 * If used with --reverse or --lines, we seek to the tail first and check if
2530 * the entry is within the range of --since later. */
2531
2532 r = sd_journal_seek_realtime_usec(j, arg_since);
2533 if (r < 0)
2534 return log_error_errno(r, "Failed to seek to date: %m");
2535 since_seeked = true;
2536
2537 r = sd_journal_next(j);
2538
2100675e
LP
2539 } else {
2540 r = sd_journal_seek_head(j);
9556e79b
YW
2541 if (r < 0)
2542 return log_error_errno(r, "Failed to seek to head: %m");
6f003b43
LP
2543
2544 r = sd_journal_next(j);
2545 }
9556e79b
YW
2546 if (r < 0)
2547 return log_error_errno(r, "Failed to iterate through journal: %m");
5f42943c
LK
2548 if (r == 0)
2549 need_seek = true;
87d2c1ff 2550
faf5077f 2551 if (!arg_follow)
384c2c32 2552 pager_open(arg_pager_flags);
0d43c694 2553
a2d7654f 2554 if (!arg_quiet && (arg_lines != 0 || arg_follow) && DEBUG_LOGGING) {
cfbc22ab
LP
2555 usec_t start, end;
2556 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
2557
2558 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
9556e79b
YW
2559 if (r < 0)
2560 return log_error_errno(r, "Failed to get cutoff: %m");
cfbc22ab
LP
2561 if (r > 0) {
2562 if (arg_follow)
b91ae210 2563 printf("-- Journal begins at %s. --\n",
5ab99e07 2564 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2565 else
b91ae210 2566 printf("-- Journal begins at %s, ends at %s. --\n",
5ab99e07
LP
2567 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2568 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2569 }
2570 }
2571
e4c4a9db
YW
2572 Context c = {
2573 .journal = j,
2574 .need_seek = need_seek,
2575 .since_seeked = since_seeked,
2576 };
6becf48c 2577
e4c4a9db 2578 if (arg_follow) {
713342d9 2579 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
24d633e4 2580 int sig;
6becf48c 2581
713342d9 2582 assert(poll_fd >= 0);
6becf48c 2583
713342d9
YW
2584 r = setup_event(&c, poll_fd, &e);
2585 if (r < 0)
2586 return r;
87d2c1ff 2587
24d633e4
YW
2588 r = sd_event_loop(e);
2589 if (r < 0)
2590 return r;
2591 sig = r;
2592
2593 /* unref signal event sources. */
2594 e = sd_event_unref(e);
2595
2596 r = update_cursor(j);
2597 if (r < 0)
2598 return r;
2599
2600 /* re-send the original signal. */
2601 assert(SIGNAL_VALID(sig));
2602 if (raise(sig) < 0)
2603 log_error("Failed to raise the original signal SIG%s, ignoring: %m", signal_to_string(sig));
2604
2605 return 0;
e4c4a9db 2606 }
50f20cfd 2607
e4c4a9db
YW
2608 r = show(&c);
2609 if (r < 0)
2610 return r;
2611 n_shown = r;
67e04a48 2612
e4c4a9db
YW
2613 if (n_shown == 0 && !arg_quiet)
2614 printf("-- No entries --\n");
87d2c1ff 2615
8c12d358
YW
2616 r = update_cursor(j);
2617 if (r < 0)
2618 return r;
3ac9cac7 2619
9556e79b 2620 if (arg_compiled_pattern && n_shown == 0)
6cda6774
FS
2621 /* --grep was used, no error was thrown, but the pattern didn't
2622 * match anything. Let's mimic grep's behavior here and return
2623 * a non-zero exit code, so journalctl --grep can be used
2624 * in scripts and such */
9556e79b 2625 return -ENOENT;
6becf48c 2626
9556e79b 2627 return 0;
87d2c1ff 2628}
9556e79b
YW
2629
2630DEFINE_MAIN_FUNCTION(run);