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