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