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