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