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