]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
Use sd_event_source_disable_unref()
[thirdparty/systemd.git] / src / journal / journalctl.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
87d2c1ff 2
3f6fd1ba 3#include <errno.h>
87d2c1ff 4#include <fcntl.h>
ea18a4b5 5#include <fnmatch.h>
3f6fd1ba
LP
6#include <getopt.h>
7#include <linux/fs.h>
8#include <locale.h>
9#include <poll.h>
10#include <signal.h>
87d2c1ff 11#include <stddef.h>
3fbf9cbb 12#include <stdio.h>
3fbf9cbb 13#include <stdlib.h>
3f6fd1ba 14#include <string.h>
74055aa7 15#include <sys/inotify.h>
3f6fd1ba
LP
16#include <sys/stat.h>
17#include <unistd.h>
87d2c1ff 18
6becf48c
ZJS
19#if HAVE_PCRE2
20# define PCRE2_CODE_UNIT_WIDTH 8
21# include <pcre2.h>
22#endif
23
74055aa7 24#include "sd-bus.h"
8bebb09c 25#include "sd-device.h"
3f6fd1ba
LP
26#include "sd-journal.h"
27
f8eeeaf9 28#include "acl-util.h"
b5efdb8a 29#include "alloc-util.h"
3f6fd1ba
LP
30#include "bus-error.h"
31#include "bus-util.h"
32#include "catalog.h"
c8b3094d 33#include "chattr-util.h"
1abaf488 34#include "def.h"
8bebb09c 35#include "device-private.h"
3ffd4af2 36#include "fd-util.h"
68fee104 37#include "fileio.h"
f4f15635 38#include "fs-util.h"
3f6fd1ba 39#include "fsprg.h"
7d50b32a 40#include "glob-util.h"
3f6fd1ba 41#include "hostname-util.h"
ff7dad48 42#include "id128-print.h"
c004493c 43#include "io-util.h"
7560fffc 44#include "journal-def.h"
3f6fd1ba 45#include "journal-internal.h"
f6a971bc 46#include "journal-qrcode.h"
4f37cbd9 47#include "journal-util.h"
dbd2a83f 48#include "journal-vacuum.h"
3f6fd1ba 49#include "journal-verify.h"
8752c575 50#include "locale-util.h"
3f6fd1ba
LP
51#include "log.h"
52#include "logs-show.h"
0a970718 53#include "memory-util.h"
74055aa7 54#include "mkdir.h"
c0dfcb31 55#include "mountpoint-util.h"
d8b4d14d 56#include "nulstr-util.h"
3f6fd1ba 57#include "pager.h"
6bedfcbb 58#include "parse-util.h"
3f6fd1ba 59#include "path-util.h"
294bf0c3 60#include "pretty-print.h"
78f22b97 61#include "rlimit-util.h"
3f6fd1ba
LP
62#include "set.h"
63#include "sigbus.h"
5c828e66 64#include "string-table.h"
3f6fd1ba 65#include "strv.h"
7ccbd1ae 66#include "syslog-util.h"
288a74cc 67#include "terminal-util.h"
e4de7287 68#include "tmpfile-util.h"
3f6fd1ba 69#include "unit-name.h"
b1d4f8e1 70#include "user-util.h"
4f413af2 71#include "varlink.h"
7560fffc 72
baed47c3 73#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
250d54b5 74
ec316d19
PP
75#define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
76
6becf48c
ZJS
77#if HAVE_PCRE2
78DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free);
61c5f8a1 79DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free);
6becf48c
ZJS
80
81static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) {
82 int errorcode, r;
83 PCRE2_SIZE erroroffset;
84 pcre2_code *p;
85
86 p = pcre2_compile((PCRE2_SPTR8) pattern,
87 PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
88 if (!p) {
89 unsigned char buf[LINE_MAX];
90
91 r = pcre2_get_error_message(errorcode, buf, sizeof buf);
92
baaa35ad
ZJS
93 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
94 "Bad pattern \"%s\": %s", pattern,
95 r < 0 ? "unknown error" : (char *)buf);
6becf48c
ZJS
96 }
97
98 *out = p;
99 return 0;
100}
101
102#endif
103
97e1cc8b
LP
104enum {
105 /* Special values for arg_lines */
106 ARG_LINES_DEFAULT = -2,
107 ARG_LINES_ALL = -1,
108};
109
df50185b 110static OutputMode arg_output = OUTPUT_SHORT;
9fd29044 111static bool arg_utc = false;
72f59706 112static bool arg_follow = false;
2b8f6883 113static bool arg_full = true;
cd4b13e0 114static bool arg_all = false;
0221d68a 115static PagerFlags arg_pager_flags = 0;
97e1cc8b 116static int arg_lines = ARG_LINES_DEFAULT;
e91af489 117static bool arg_no_tail = false;
43673799 118static bool arg_quiet = false;
9e8a535f 119static bool arg_merge = false;
d121b396 120static bool arg_boot = false;
442e2def
LP
121static sd_id128_t arg_boot_id = {};
122static int arg_boot_offset = 0;
99271804 123static bool arg_dmesg = false;
991e274b 124static bool arg_no_hostname = false;
8f14c832 125static const char *arg_cursor = NULL;
d9e15cbd 126static const char *arg_cursor_file = NULL;
248fc619
ZJS
127static const char *arg_after_cursor = NULL;
128static bool arg_show_cursor = false;
a963990f 129static const char *arg_directory = NULL;
8d98da3f 130static char **arg_file = NULL;
5d1ce257 131static bool arg_file_stdin = false;
941e990d 132static int arg_priorities = 0xFF;
6bae9b2a 133static char *arg_verify_key = NULL;
349cc4a5 134#if HAVE_GCRYPT
baed47c3 135static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
b8547c10 136static bool arg_force = false;
feb12d3e 137#endif
cfbc22ab
LP
138static usec_t arg_since, arg_until;
139static bool arg_since_set = false, arg_until_set = false;
73083640 140static char **arg_syslog_identifier = NULL;
b9e40524
HH
141static char **arg_system_units = NULL;
142static char **arg_user_units = NULL;
3c1668da 143static const char *arg_field = NULL;
d4205751 144static bool arg_catalog = false;
d89d6c86 145static bool arg_reverse = false;
3f3a438f 146static int arg_journal_type = 0;
0f03c2a4 147static char *arg_root = NULL;
b6741478 148static const char *arg_machine = NULL;
8580d1f7
LP
149static uint64_t arg_vacuum_size = 0;
150static uint64_t arg_vacuum_n_files = 0;
151static usec_t arg_vacuum_time = 0;
cc25a67e 152static char **arg_output_fields = NULL;
50f20cfd 153
6becf48c 154#if HAVE_PCRE2
61c5f8a1
ZJS
155static const char *arg_pattern = NULL;
156static pcre2_code *arg_compiled_pattern = NULL;
157static int arg_case_sensitive = -1; /* -1 means be smart */
6becf48c
ZJS
158#endif
159
7560fffc
LP
160static enum {
161 ACTION_SHOW,
162 ACTION_NEW_ID128,
163 ACTION_PRINT_HEADER,
beec0085 164 ACTION_SETUP_KEYS,
a1a03e30
LP
165 ACTION_VERIFY,
166 ACTION_DISK_USAGE,
d4205751 167 ACTION_LIST_CATALOG,
54b7254c 168 ACTION_DUMP_CATALOG,
f1188074
ZJS
169 ACTION_UPDATE_CATALOG,
170 ACTION_LIST_BOOTS,
74055aa7 171 ACTION_FLUSH,
c0dfcb31 172 ACTION_RELINQUISH_VAR,
a020b3b3 173 ACTION_SYNC,
e3fdfb49 174 ACTION_ROTATE,
dbd2a83f 175 ACTION_VACUUM,
8df64fd0 176 ACTION_ROTATE_AND_VACUUM,
69e714f3
LP
177 ACTION_LIST_FIELDS,
178 ACTION_LIST_FIELD_NAMES,
7560fffc
LP
179} arg_action = ACTION_SHOW;
180
45bc27b6 181typedef struct BootId {
a331b5e6 182 sd_id128_t id;
f1188074
ZJS
183 uint64_t first;
184 uint64_t last;
45bc27b6
LP
185 LIST_FIELDS(struct BootId, boot_list);
186} BootId;
a331b5e6 187
795ab08f 188static int add_matches_for_device(sd_journal *j, const char *devpath) {
8bebb09c
YW
189 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
190 sd_device *d = NULL;
795ab08f 191 struct stat st;
e5ca27b7 192 int r;
795ab08f
MS
193
194 assert(j);
195 assert(devpath);
196
197 if (!path_startswith(devpath, "/dev/")) {
198 log_error("Devpath does not start with /dev/");
199 return -EINVAL;
200 }
201
e5ca27b7
LP
202 if (stat(devpath, &st) < 0)
203 return log_error_errno(errno, "Couldn't stat file: %m");
795ab08f 204
8bebb09c 205 r = device_new_from_stat_rdev(&device, &st);
e5ca27b7 206 if (r < 0)
8bebb09c 207 return log_error_errno(r, "Failed to get device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
795ab08f 208
8bebb09c 209 for (d = device; d; ) {
795ab08f
MS
210 _cleanup_free_ char *match = NULL;
211 const char *subsys, *sysname, *devnode;
8bebb09c 212 sd_device *parent;
795ab08f 213
8bebb09c
YW
214 r = sd_device_get_subsystem(d, &subsys);
215 if (r < 0)
216 goto get_parent;
795ab08f 217
8bebb09c
YW
218 r = sd_device_get_sysname(d, &sysname);
219 if (r < 0)
220 goto get_parent;
795ab08f 221
605405c6 222 match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname);
795ab08f
MS
223 if (!match)
224 return log_oom();
225
226 r = sd_journal_add_match(j, match, 0);
227 if (r < 0)
228 return log_error_errno(r, "Failed to add match: %m");
229
8bebb09c 230 if (sd_device_get_devname(d, &devnode) >= 0) {
795ab08f
MS
231 _cleanup_free_ char *match1 = NULL;
232
233 r = stat(devnode, &st);
234 if (r < 0)
235 return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode);
236
237 r = asprintf(&match1, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st.st_mode) ? 'b' : 'c', major(st.st_rdev), minor(st.st_rdev));
238 if (r < 0)
239 return log_oom();
240
241 r = sd_journal_add_match(j, match1, 0);
242 if (r < 0)
243 return log_error_errno(r, "Failed to add match: %m");
244 }
245
8bebb09c
YW
246get_parent:
247 if (sd_device_get_parent(d, &parent) < 0)
248 break;
249
250 d = parent;
795ab08f
MS
251 }
252
485fd9a7
MS
253 r = add_match_this_boot(j, arg_machine);
254 if (r < 0)
255 return log_error_errno(r, "Failed to add match for the current boot: %m");
256
795ab08f
MS
257 return 0;
258}
259
5ab99e07
LP
260static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
261
262 if (arg_utc)
263 return format_timestamp_utc(buf, l, t);
264
265 return format_timestamp(buf, l, t);
266}
267
442e2def
LP
268static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
269 sd_id128_t id = SD_ID128_NULL;
270 int off = 0, r;
271
48904825 272 if (streq(x, "all")) {
273 *boot_id = SD_ID128_NULL;
274 *offset = 0;
275 return 0;
276 } else if (strlen(x) >= 32) {
442e2def
LP
277 char *t;
278
279 t = strndupa(x, 32);
280 r = sd_id128_from_string(t, &id);
281 if (r >= 0)
282 x += 32;
283
4c701096 284 if (!IN_SET(*x, 0, '-', '+'))
442e2def
LP
285 return -EINVAL;
286
287 if (*x != 0) {
288 r = safe_atoi(x, &off);
289 if (r < 0)
290 return r;
291 }
292 } else {
293 r = safe_atoi(x, &off);
294 if (r < 0)
295 return r;
296 }
297
298 if (boot_id)
299 *boot_id = id;
300
301 if (offset)
302 *offset = off;
303
48904825 304 return 1;
442e2def
LP
305}
306
37ec0fdd
LP
307static int help(void) {
308 _cleanup_free_ char *link = NULL;
309 int r;
0d43c694 310
0221d68a 311 (void) pager_open(arg_pager_flags);
faf5077f 312
37ec0fdd
LP
313 r = terminal_urlify_man("journalctl", "1", &link);
314 if (r < 0)
315 return log_oom();
316
cd4b13e0 317 printf("%s [OPTIONS...] [MATCHES...]\n\n"
15119c16 318 "Query the journal.\n\n"
94b65516 319 "Options:\n"
61c5f8a1
ZJS
320 " --system Show the system journal\n"
321 " --user Show the user journal for the current user\n"
322 " -M --machine=CONTAINER Operate on local container\n"
323 " -S --since=DATE Show entries not older than the specified date\n"
324 " -U --until=DATE Show entries not newer than the specified date\n"
325 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
326 " --after-cursor=CURSOR Show entries after the specified cursor\n"
327 " --show-cursor Print the cursor after all the entries\n"
d9e15cbd 328 " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n"
61c5f8a1
ZJS
329 " -b --boot[=ID] Show current boot or the specified boot\n"
330 " --list-boots Show terse information about recorded boots\n"
331 " -k --dmesg Show kernel message log from the current boot\n"
332 " -u --unit=UNIT Show logs from the specified unit\n"
333 " --user-unit=UNIT Show logs from the specified user unit\n"
334 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
335 " -p --priority=RANGE Show entries with the specified priority\n"
fabf4dae 336 " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n"
61c5f8a1
ZJS
337 " --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n"
338 " -e --pager-end Immediately jump to the end in the pager\n"
339 " -f --follow Follow the journal\n"
340 " -n --lines[=INTEGER] Number of journal entries to show\n"
341 " --no-tail Show all lines, even in follow mode\n"
342 " -r --reverse Show the newest entries first\n"
343 " -o --output=STRING Change journal output mode (short, short-precise,\n"
344 " short-iso, short-iso-precise, short-full,\n"
345 " short-monotonic, short-unix, verbose, export,\n"
8e044443
LP
346 " json, json-pretty, json-sse, json-seq, cat,\n"
347 " with-unit)\n"
61c5f8a1
ZJS
348 " --output-fields=LIST Select fields to print in verbose/export/json modes\n"
349 " --utc Express time in Coordinated Universal Time (UTC)\n"
350 " -x --catalog Add message explanations where available\n"
351 " --no-full Ellipsize fields\n"
352 " -a --all Show all fields, including long and unprintable\n"
353 " -q --quiet Do not show info messages and privilege warning\n"
354 " --no-pager Do not pipe output into a pager\n"
355 " --no-hostname Suppress output of hostname field\n"
356 " -m --merge Show entries from all available journals\n"
357 " -D --directory=PATH Show journal files from directory\n"
358 " --file=PATH Show journal file\n"
359 " --root=ROOT Operate on files below a root directory\n"
61c5f8a1
ZJS
360 " --interval=TIME Time interval for changing the FSS sealing key\n"
361 " --verify-key=KEY Specify FSS verification key\n"
362 " --force Override of the FSS key pair with --setup-keys\n"
15119c16 363 "\nCommands:\n"
61c5f8a1
ZJS
364 " -h --help Show this help text\n"
365 " --version Show package version\n"
366 " -N --fields List all field names currently used\n"
367 " -F --field=FIELD List all values that a specified field takes\n"
368 " --disk-usage Show total disk usage of all journal files\n"
369 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
370 " --vacuum-files=INT Leave only the specified number of journal files\n"
371 " --vacuum-time=TIME Remove journal files older than specified time\n"
372 " --verify Verify journal file consistency\n"
373 " --sync Synchronize unwritten journal messages to disk\n"
c0dfcb31
LP
374 " --relinquish-var Stop logging to disk, log to temporary file system\n"
375 " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n"
61c5f8a1
ZJS
376 " --flush Flush all journal data from /run into /var\n"
377 " --rotate Request immediate rotation of the journal files\n"
378 " --header Show journal header information\n"
379 " --list-catalog Show all message IDs in the catalog\n"
380 " --dump-catalog Show entries in the message catalog\n"
381 " --update-catalog Update the message catalog database\n"
61c5f8a1 382 " --setup-keys Generate a new FSS key pair\n"
37ec0fdd
LP
383 "\nSee the %s for details.\n"
384 , program_invocation_short_name
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;
1075122f
ZJS
755 /* Use memset not string_erase so this doesn't look confusing
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:
6becf48c
ZJS
846 return log_error("Compiled without pattern matching support");
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
62570f6f 1088 r = chase_symlinks(*i, NULL, CHASE_TRAIL_SLASH, &p);
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
1103 t = strappend("_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)) {
68fee104
ZJS
1110 t2 = strappend("_EXE=", interpreter);
1111 if (!t2)
1112 return log_oom();
1113 }
795ab08f 1114 } else {
e1873695 1115 t = strappend("_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) {
1427 const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r);
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" \
1541 "OBJECT_SYSTEMD_USER_UNIT\0"
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) {
1681 char *u;
1682
63c372cb 1683 u = strjoina("SYSLOG_IDENTIFIER=", *i);
73083640
HH
1684 r = sd_journal_add_match(j, u, 0);
1685 if (r < 0)
1686 return r;
1687 r = sd_journal_add_disjunction(j);
1688 if (r < 0)
1689 return r;
1690 }
1691
1692 r = sd_journal_add_conjunction(j);
1693 if (r < 0)
1694 return r;
1695
1696 return 0;
1697}
1698
7560fffc 1699static int setup_keys(void) {
349cc4a5 1700#if HAVE_GCRYPT
7560fffc
LP
1701 size_t mpk_size, seed_size, state_size, i;
1702 uint8_t *mpk, *seed, *state;
11689d2a 1703 int fd = -1, r;
7560fffc
LP
1704 sd_id128_t machine, boot;
1705 char *p = NULL, *k = NULL;
baed47c3 1706 struct FSSHeader h;
14d10188 1707 uint64_t n;
b98e3866
SL
1708 struct stat st;
1709
1710 r = stat("/var/log/journal", &st);
4c701096 1711 if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR))
4a62c710 1712 return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
b98e3866
SL
1713
1714 if (r < 0 || !S_ISDIR(st.st_mode)) {
1715 log_error("%s is not a directory, must be using persistent logging for FSS.",
1716 "/var/log/journal");
1717 return r < 0 ? -errno : -ENOTDIR;
1718 }
7560fffc
LP
1719
1720 r = sd_id128_get_machine(&machine);
23bbb0de
MS
1721 if (r < 0)
1722 return log_error_errno(r, "Failed to get machine ID: %m");
7560fffc
LP
1723
1724 r = sd_id128_get_boot(&boot);
23bbb0de
MS
1725 if (r < 0)
1726 return log_error_errno(r, "Failed to get boot ID: %m");
7560fffc 1727
baed47c3 1728 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1729 SD_ID128_FORMAT_VAL(machine)) < 0)
1730 return log_oom();
1731
faf9da01
ZJS
1732 if (arg_force) {
1733 r = unlink(p);
1734 if (r < 0 && errno != ENOENT) {
1735 r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
b8547c10
SL
1736 goto finish;
1737 }
faf9da01
ZJS
1738 } else if (access(p, F_OK) >= 0) {
1739 log_error("Sealing key file %s exists already. Use --force to recreate.", p);
1740 r = -EEXIST;
1741 goto finish;
7560fffc
LP
1742 }
1743
baed47c3 1744 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1745 SD_ID128_FORMAT_VAL(machine)) < 0) {
1746 r = log_oom();
1747 goto finish;
1748 }
1749
1750 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1751 mpk = alloca(mpk_size);
1752
1753 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1754 seed = alloca(seed_size);
1755
1756 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1757 state = alloca(state_size);
1758
1759 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1760 if (fd < 0) {
76ef789d 1761 r = log_error_errno(errno, "Failed to open /dev/random: %m");
7560fffc
LP
1762 goto finish;
1763 }
1764
1765 log_info("Generating seed...");
a6dcc7e5
ZJS
1766 r = loop_read_exact(fd, seed, seed_size, true);
1767 if (r < 0) {
1768 log_error_errno(r, "Failed to read random seed: %m");
7560fffc
LP
1769 goto finish;
1770 }
1771
1772 log_info("Generating key pair...");
1773 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1774
baed47c3 1775 log_info("Generating sealing key...");
7560fffc
LP
1776 FSPRG_GenState0(state, mpk, seed, seed_size);
1777
baed47c3
LP
1778 assert(arg_interval > 0);
1779
7560fffc 1780 n = now(CLOCK_REALTIME);
baed47c3 1781 n /= arg_interval;
7560fffc 1782
03e334a1 1783 safe_close(fd);
646853bd 1784 fd = mkostemp_safe(k);
7560fffc 1785 if (fd < 0) {
709f6e46 1786 r = log_error_errno(fd, "Failed to open %s: %m", k);
7560fffc
LP
1787 goto finish;
1788 }
1789
f982e6f7
LP
1790 /* Enable secure remove, exclusion from dump, synchronous
1791 * writing and in-place updating */
db9a4254 1792 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 1793 if (r < 0)
709f6e46 1794 log_warning_errno(r, "Failed to set file attributes: %m");
f982e6f7 1795
7560fffc
LP
1796 zero(h);
1797 memcpy(h.signature, "KSHHRHLP", 8);
1798 h.machine_id = machine;
1799 h.boot_id = boot;
1800 h.header_size = htole64(sizeof(h));
baed47c3
LP
1801 h.start_usec = htole64(n * arg_interval);
1802 h.interval_usec = htole64(arg_interval);
1803 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1804 h.fsprg_state_size = htole64(state_size);
7560fffc 1805
553acb7b
ZJS
1806 r = loop_write(fd, &h, sizeof(h), false);
1807 if (r < 0) {
1808 log_error_errno(r, "Failed to write header: %m");
7560fffc
LP
1809 goto finish;
1810 }
1811
553acb7b
ZJS
1812 r = loop_write(fd, state, state_size, false);
1813 if (r < 0) {
1814 log_error_errno(r, "Failed to write state: %m");
7560fffc
LP
1815 goto finish;
1816 }
1817
1818 if (link(k, p) < 0) {
76ef789d 1819 r = log_error_errno(errno, "Failed to link file: %m");
7560fffc
LP
1820 goto finish;
1821 }
1822
8481248b 1823 if (on_tty()) {
7560fffc
LP
1824 fprintf(stderr,
1825 "\n"
54f8c958 1826 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
c05276f2
LP
1827 "the following local file. This key file is automatically updated when the\n"
1828 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1829 "\n"
1830 "\t%s\n"
1831 "\n"
54f8c958 1832 "Please write down the following %ssecret verification key%s. It should be stored\n"
baed47c3 1833 "at a safe location and should not be saved locally on disk.\n"
54f8c958
LP
1834 "\n\t%s",
1835 ansi_highlight(), ansi_normal(),
9ea78383 1836 p,
54f8c958 1837 ansi_highlight(), ansi_normal(),
9ea78383 1838 ansi_highlight_red());
7560fffc
LP
1839 fflush(stderr);
1840 }
1841 for (i = 0; i < seed_size; i++) {
1842 if (i > 0 && i % 3 == 0)
1843 putchar('-');
1844 printf("%02x", ((uint8_t*) seed)[i]);
1845 }
1846
baed47c3
LP
1847 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1848
8481248b 1849 if (on_tty()) {
f6a971bc 1850 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1851
baed47c3 1852 fprintf(stderr,
54f8c958 1853 "%s\n"
baed47c3 1854 "The sealing key is automatically changed every %s.\n",
54f8c958 1855 ansi_normal(),
2fa4092c 1856 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1857
1858 hn = gethostname_malloc();
1859
1860 if (hn) {
ae691c1d 1861 hostname_cleanup(hn);
adac1c93 1862 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1863 } else
adac1c93 1864 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc 1865
349cc4a5 1866#if HAVE_QRENCODE
cf5a3432 1867 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1868 if (is_locale_utf8()) {
cf5a3432
LP
1869 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1870 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1871 }
f6a971bc
LP
1872#endif
1873 free(hn);
baed47c3 1874 }
7560fffc
LP
1875
1876 r = 0;
1877
1878finish:
03e334a1 1879 safe_close(fd);
7560fffc
LP
1880
1881 if (k) {
6990fb6b 1882 (void) unlink(k);
7560fffc
LP
1883 free(k);
1884 }
1885
1886 free(p);
1887
1888 return r;
1889#else
baaa35ad
ZJS
1890 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1891 "Forward-secure sealing not available.");
7560fffc
LP
1892#endif
1893}
1894
beec0085
LP
1895static int verify(sd_journal *j) {
1896 int r = 0;
1897 Iterator i;
1898 JournalFile *f;
1899
1900 assert(j);
1901
cedb42bb
LP
1902 log_show_color(true);
1903
c1f906bd 1904 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
beec0085 1905 int k;
a7f7d1bd 1906 usec_t first = 0, validated = 0, last = 0;
beec0085 1907
349cc4a5 1908#if HAVE_GCRYPT
feb12d3e 1909 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1910 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1911#endif
4da416aa 1912
2a7b539a 1913 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1914 if (k == -EINVAL) {
baed47c3 1915 /* If the key was invalid give up right-away. */
56e81f7c
LP
1916 return k;
1917 } else if (k < 0) {
e53fc357 1918 log_warning_errno(k, "FAIL: %s (%m)", f->path);
56e81f7c 1919 r = k;
6c7be122
LP
1920 } else {
1921 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1922 log_info("PASS: %s", f->path);
6c7be122 1923
c0ca7aee 1924 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1925 if (validated > 0) {
c0ca7aee 1926 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1927 format_timestamp_maybe_utc(a, sizeof(a), first),
1928 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1929 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1930 } else if (last > 0)
c0ca7aee 1931 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1932 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1933 else
1934 log_info("=> No sealing yet, no entries in file.");
1935 }
6c7be122 1936 }
beec0085
LP
1937 }
1938
1939 return r;
1940}
1941
4f413af2
LP
1942static int simple_varlink_call(const char *option, const char *method) {
1943 _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
1944 const char *error;
74055aa7
LP
1945 int r;
1946
4f413af2
LP
1947 if (arg_machine)
1948 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not supported in conjunction with --machine=.", option);
74055aa7 1949
4f413af2 1950 r = varlink_connect_address(&link, "/run/systemd/journal/io.systemd.journal");
94b65516 1951 if (r < 0)
4f413af2 1952 return log_error_errno(r, "Failed to connect to journal: %m");
74055aa7 1953
4f413af2
LP
1954 r = varlink_call(link, method, NULL, NULL, &error, NULL);
1955 if (r < 0)
1956 return log_error_errno(r, "Failed to execute operation: %s", error);
74055aa7 1957
4f413af2 1958 return 0;
74055aa7
LP
1959}
1960
4f413af2
LP
1961static int flush_to_var(void) {
1962 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
94b65516
LP
1963}
1964
c0dfcb31
LP
1965static int relinquish_var(void) {
1966 return simple_varlink_call("--relinquish-var", "io.systemd.Journal.RelinquishVar");
1967}
1968
dbd6e31c 1969static int rotate(void) {
4f413af2 1970 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
dbd6e31c
LP
1971}
1972
1973static int sync_journal(void) {
4f413af2 1974 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
dbd6e31c
LP
1975}
1976
2a1e0f22
LP
1977static int wait_for_change(sd_journal *j, int poll_fd) {
1978 struct pollfd pollfds[] = {
1979 { .fd = poll_fd, .events = POLLIN },
1980 { .fd = STDOUT_FILENO },
1981 };
1982
1983 struct timespec ts;
1984 usec_t timeout;
a963990f 1985 int r;
2a1e0f22
LP
1986
1987 assert(j);
1988 assert(poll_fd >= 0);
1989
1990 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
1991 * i.e. when it is closed. */
1992
1993 r = sd_journal_get_timeout(j, &timeout);
1994 if (r < 0)
1995 return log_error_errno(r, "Failed to determine journal waiting time: %m");
1996
8e143a12
ZJS
1997 if (ppoll(pollfds, ELEMENTSOF(pollfds),
1998 timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) {
1999 if (errno == EINTR)
2000 return 0;
2001
2a1e0f22 2002 return log_error_errno(errno, "Couldn't wait for journal event: %m");
8e143a12 2003 }
2a1e0f22 2004
baaa35ad
ZJS
2005 if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */
2006 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED),
2007 "Standard output has been closed.");
2a1e0f22
LP
2008
2009 r = sd_journal_process(j);
2010 if (r < 0)
2011 return log_error_errno(r, "Failed to process journal events: %m");
2012
2013 return 0;
2014}
2015
2016int main(int argc, char *argv[]) {
2017 bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false;
d9e15cbd 2018 bool use_cursor = false, after_cursor = false;
4afd3348 2019 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
14a65d65 2020 sd_id128_t previous_boot_id;
2a1e0f22 2021 int n_shown = 0, r, poll_fd = -1;
a963990f 2022
a9cdc94f 2023 setlocale(LC_ALL, "");
1a043959 2024 log_show_color(true);
a963990f
LP
2025 log_parse_environment();
2026 log_open();
2027
1abaf488
LP
2028 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2029 * split up into many files. */
2030 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
2031
a963990f
LP
2032 r = parse_argv(argc, argv);
2033 if (r <= 0)
2034 goto finish;
2035
ed757c0c 2036 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 2037 sigbus_install();
ed757c0c 2038
a020b3b3 2039 switch (arg_action) {
94b65516 2040
a020b3b3 2041 case ACTION_NEW_ID128:
0d1d512f 2042 r = id128_print_new(true);
e3fdfb49 2043 goto finish;
e3fdfb49 2044
a020b3b3 2045 case ACTION_SETUP_KEYS:
7560fffc
LP
2046 r = setup_keys();
2047 goto finish;
844ec79b 2048
a020b3b3
LP
2049 case ACTION_LIST_CATALOG:
2050 case ACTION_DUMP_CATALOG:
2051 case ACTION_UPDATE_CATALOG: {
0c6ea3a4
ZJS
2052 _cleanup_free_ char *database;
2053
652ef298 2054 database = path_join(arg_root, CATALOG_DATABASE);
0c6ea3a4
ZJS
2055 if (!database) {
2056 r = log_oom();
2057 goto finish;
13cbf3a5
ZJS
2058 }
2059
844ec79b 2060 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 2061 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b 2062 if (r < 0)
da927ba9 2063 log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
2064 } else {
2065 bool oneline = arg_action == ACTION_LIST_CATALOG;
2066
0221d68a 2067 (void) pager_open(arg_pager_flags);
a020b3b3 2068
844ec79b 2069 if (optind < argc)
a020b3b3 2070 r = catalog_list_items(stdout, database, oneline, argv + optind);
844ec79b 2071 else
13cbf3a5 2072 r = catalog_list(stdout, database, oneline);
844ec79b 2073 if (r < 0)
da927ba9 2074 log_error_errno(r, "Failed to list catalog: %m");
844ec79b 2075 }
d4205751 2076
d4205751
LP
2077 goto finish;
2078 }
2079
a020b3b3
LP
2080 case ACTION_FLUSH:
2081 r = flush_to_var();
2082 goto finish;
2083
c0dfcb31
LP
2084 case ACTION_RELINQUISH_VAR:
2085 r = relinquish_var();
2086 goto finish;
2087
a020b3b3
LP
2088 case ACTION_SYNC:
2089 r = sync_journal();
2090 goto finish;
2091
2092 case ACTION_ROTATE:
2093 r = rotate();
2094 goto finish;
2095
2096 case ACTION_SHOW:
2097 case ACTION_PRINT_HEADER:
2098 case ACTION_VERIFY:
2099 case ACTION_DISK_USAGE:
2100 case ACTION_LIST_BOOTS:
2101 case ACTION_VACUUM:
8df64fd0 2102 case ACTION_ROTATE_AND_VACUUM:
69e714f3
LP
2103 case ACTION_LIST_FIELDS:
2104 case ACTION_LIST_FIELD_NAMES:
a020b3b3
LP
2105 /* These ones require access to the journal files, continue below. */
2106 break;
2107
2108 default:
2109 assert_not_reached("Unknown action");
2110 }
2111
a963990f 2112 if (arg_directory)
3f3a438f 2113 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
0a175093
ZJS
2114 else if (arg_root)
2115 r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
5d1ce257
LP
2116 else if (arg_file_stdin) {
2117 int ifd = STDIN_FILENO;
2118 r = sd_journal_open_files_fd(&j, &ifd, 1, 0);
2119 } else if (arg_file)
8d98da3f 2120 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
d38c62cc
LP
2121 else if (arg_machine) {
2122 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2123 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2124 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2125 int fd;
2126
2127 if (geteuid() != 0) {
2128 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2129 * the container, thus we need root privileges to override them. */
2130 log_error("Using the --machine= switch requires root privileges.");
2131 r = -EPERM;
2132 goto finish;
2133 }
2134
2135 r = sd_bus_open_system(&bus);
2136 if (r < 0) {
2137 log_error_errno(r, "Failed to open system bus: %m");
2138 goto finish;
2139 }
2140
2141 r = sd_bus_call_method(
2142 bus,
2143 "org.freedesktop.machine1",
2144 "/org/freedesktop/machine1",
2145 "org.freedesktop.machine1.Manager",
2146 "OpenMachineRootDirectory",
2147 &error,
2148 &reply,
2149 "s", arg_machine);
2150 if (r < 0) {
2151 log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
2152 goto finish;
2153 }
2154
2155 r = sd_bus_message_read(reply, "h", &fd);
2156 if (r < 0) {
2157 bus_log_parse_error(r);
2158 goto finish;
2159 }
2160
2161 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
2162 if (fd < 0) {
2163 r = log_error_errno(errno, "Failed to duplicate file descriptor: %m");
2164 goto finish;
2165 }
2166
2167 r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT);
2168 if (r < 0)
2169 safe_close(fd);
2170 } else
3f3a438f 2171 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 2172 if (r < 0) {
a020b3b3 2173 log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
909dea0c 2174 goto finish;
a963990f
LP
2175 }
2176
e79d0b59
ZJS
2177 r = journal_access_check_and_warn(j, arg_quiet,
2178 !(arg_journal_type == SD_JOURNAL_CURRENT_USER || arg_user_units));
6fe391c5 2179 if (r < 0)
909dea0c 2180 goto finish;
6fe391c5 2181
a020b3b3 2182 switch (arg_action) {
beec0085 2183
a020b3b3
LP
2184 case ACTION_NEW_ID128:
2185 case ACTION_SETUP_KEYS:
2186 case ACTION_LIST_CATALOG:
2187 case ACTION_DUMP_CATALOG:
2188 case ACTION_UPDATE_CATALOG:
2189 case ACTION_FLUSH:
2190 case ACTION_SYNC:
2191 case ACTION_ROTATE:
2192 assert_not_reached("Unexpected action.");
2193
2194 case ACTION_PRINT_HEADER:
dca6219e 2195 journal_print_header(j);
909dea0c
LP
2196 r = 0;
2197 goto finish;
dca6219e 2198
a020b3b3
LP
2199 case ACTION_VERIFY:
2200 r = verify(j);
2201 goto finish;
2202
2203 case ACTION_DISK_USAGE: {
39883f62 2204 uint64_t bytes = 0;
a1a03e30
LP
2205 char sbytes[FORMAT_BYTES_MAX];
2206
2207 r = sd_journal_get_usage(j, &bytes);
2208 if (r < 0)
909dea0c 2209 goto finish;
a1a03e30 2210
8da830bc 2211 printf("Archived and active journals take up %s in the file system.\n",
763c7aa2 2212 format_bytes(sbytes, sizeof(sbytes), bytes));
909dea0c 2213 goto finish;
a1a03e30
LP
2214 }
2215
a020b3b3
LP
2216 case ACTION_LIST_BOOTS:
2217 r = list_boots(j);
2218 goto finish;
2219
8df64fd0
LP
2220 case ACTION_ROTATE_AND_VACUUM:
2221
2222 r = rotate();
2223 if (r < 0)
2224 goto finish;
2225
2226 _fallthrough_;
2227
a020b3b3 2228 case ACTION_VACUUM: {
dbd2a83f
LP
2229 Directory *d;
2230 Iterator i;
2231
2232 HASHMAP_FOREACH(d, j->directories_by_path, i) {
2233 int q;
2234
2235 if (d->is_root)
2236 continue;
2237
e3695e49 2238 q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, !arg_quiet);
dbd2a83f 2239 if (q < 0) {
8580d1f7 2240 log_error_errno(q, "Failed to vacuum %s: %m", d->path);
dbd2a83f
LP
2241 r = q;
2242 }
2243 }
2244
909dea0c 2245 goto finish;
dbd2a83f
LP
2246 }
2247
69e714f3
LP
2248 case ACTION_LIST_FIELD_NAMES: {
2249 const char *field;
2250
2251 SD_JOURNAL_FOREACH_FIELD(j, field) {
2252 printf("%s\n", field);
313cefa1 2253 n_shown++;
69e714f3
LP
2254 }
2255
2256 r = 0;
2257 goto finish;
2258 }
2259
a020b3b3 2260 case ACTION_SHOW:
69e714f3 2261 case ACTION_LIST_FIELDS:
a020b3b3
LP
2262 break;
2263
2264 default:
2265 assert_not_reached("Unknown action");
f1188074
ZJS
2266 }
2267
0f1a9a83
JS
2268 if (arg_boot_offset != 0 &&
2269 sd_journal_has_runtime_files(j) > 0 &&
2270 sd_journal_has_persistent_files(j) == 0) {
493097ee 2271 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
0f1a9a83
JS
2272 r = 0;
2273 goto finish;
2274 }
a331b5e6
JJ
2275 /* add_boot() must be called first!
2276 * It may need to seek the journal to find parent boot IDs. */
2277 r = add_boot(j);
a963990f 2278 if (r < 0)
909dea0c 2279 goto finish;
a963990f 2280
99271804
ZJS
2281 r = add_dmesg(j);
2282 if (r < 0)
909dea0c 2283 goto finish;
99271804 2284
b9e40524 2285 r = add_units(j);
ea18a4b5 2286 if (r < 0) {
da927ba9 2287 log_error_errno(r, "Failed to add filter for units: %m");
909dea0c 2288 goto finish;
ea18a4b5 2289 }
c3f60ec5 2290
73083640
HH
2291 r = add_syslog_identifier(j);
2292 if (r < 0) {
da927ba9 2293 log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
909dea0c 2294 goto finish;
73083640
HH
2295 }
2296
cd34b3c6 2297 r = add_priorities(j);
b56d608e 2298 if (r < 0)
909dea0c 2299 goto finish;
a963990f 2300
cd34b3c6 2301 r = add_matches(j, argv + optind);
b56d608e 2302 if (r < 0)
909dea0c 2303 goto finish;
941e990d 2304
f1d34068 2305 if (DEBUG_LOGGING) {
4ad16808
ZJS
2306 _cleanup_free_ char *filter;
2307
2308 filter = journal_make_match_string(j);
b56d608e
LP
2309 if (!filter)
2310 return log_oom();
2311
4ad16808
ZJS
2312 log_debug("Journal filter: %s", filter);
2313 }
67e04a48 2314
69e714f3 2315 if (arg_action == ACTION_LIST_FIELDS) {
15119c16
LP
2316 const void *data;
2317 size_t size;
2318
69e714f3
LP
2319 assert(arg_field);
2320
21ae4593
ZJS
2321 r = sd_journal_set_data_threshold(j, 0);
2322 if (r < 0) {
b56d608e 2323 log_error_errno(r, "Failed to unset data size threshold: %m");
909dea0c 2324 goto finish;
21ae4593
ZJS
2325 }
2326
15119c16
LP
2327 r = sd_journal_query_unique(j, arg_field);
2328 if (r < 0) {
da927ba9 2329 log_error_errno(r, "Failed to query unique data objects: %m");
909dea0c 2330 goto finish;
15119c16
LP
2331 }
2332
2333 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
2334 const void *eq;
2335
67e04a48 2336 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
2337 break;
2338
15119c16
LP
2339 eq = memchr(data, '=', size);
2340 if (eq)
2341 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
2342 else
2343 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875 2344
313cefa1 2345 n_shown++;
15119c16
LP
2346 }
2347
909dea0c
LP
2348 r = 0;
2349 goto finish;
15119c16
LP
2350 }
2351
8d98da3f
ZJS
2352 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2353 if (arg_follow) {
2a1e0f22
LP
2354 poll_fd = sd_journal_get_fd(j);
2355 if (poll_fd == -EMFILE) {
5238e957 2356 log_warning_errno(poll_fd, "Insufficient watch descriptors available. Reverting to -n.");
321ed364 2357 arg_follow = false;
2a1e0f22
LP
2358 } else if (poll_fd == -EMEDIUMTYPE) {
2359 log_error_errno(poll_fd, "The --follow switch is not supported in conjunction with reading from STDIN.");
5d1ce257 2360 goto finish;
2a1e0f22
LP
2361 } else if (poll_fd < 0) {
2362 log_error_errno(poll_fd, "Failed to get journal fd: %m");
909dea0c 2363 goto finish;
b56d608e 2364 }
8d98da3f
ZJS
2365 }
2366
d9e15cbd
JS
2367 if (arg_cursor || arg_after_cursor || arg_cursor_file) {
2368 _cleanup_free_ char *cursor_from_file = NULL;
2369 const char *cursor = arg_cursor ?: arg_after_cursor;
2370
2371 if (arg_cursor_file) {
2372 r = read_one_line_file(arg_cursor_file, &cursor_from_file);
2373 if (r < 0 && r != -ENOENT) {
2374 log_error_errno(r, "Failed to read cursor file %s: %m", arg_cursor_file);
2375 goto finish;
2376 }
2377
2378 if (r > 0) {
2379 cursor = cursor_from_file;
2380 after_cursor = true;
2381 }
2382 } else
2383 after_cursor = !!arg_after_cursor;
2384
2385 if (cursor) {
2386 r = sd_journal_seek_cursor(j, cursor);
2387 if (r < 0) {
2388 log_error_errno(r, "Failed to seek to cursor: %m");
2389 goto finish;
2390 }
2391 use_cursor = true;
08984293 2392 }
d9e15cbd 2393 }
909dea0c 2394
d9e15cbd 2395 if (use_cursor) {
d89d6c86 2396 if (!arg_reverse)
d9e15cbd 2397 r = sd_journal_next_skip(j, 1 + after_cursor);
d89d6c86 2398 else
d9e15cbd 2399 r = sd_journal_previous_skip(j, 1 + after_cursor);
248fc619 2400
d9e15cbd 2401 if (after_cursor && r < 2) {
248fc619 2402 /* We couldn't find the next entry after the cursor. */
8ee8e536
WD
2403 if (arg_follow)
2404 need_seek = true;
2405 else
2406 arg_lines = 0;
2407 }
08984293 2408
d89d6c86 2409 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 2410 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 2411 if (r < 0) {
da927ba9 2412 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2413 goto finish;
8f14c832 2414 }
8f14c832
LP
2415 r = sd_journal_next(j);
2416
d89d6c86
LN
2417 } else if (arg_until_set && arg_reverse) {
2418 r = sd_journal_seek_realtime_usec(j, arg_until);
2419 if (r < 0) {
da927ba9 2420 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2421 goto finish;
d89d6c86
LN
2422 }
2423 r = sd_journal_previous(j);
2424
67e04a48 2425 } else if (arg_lines >= 0) {
2100675e
LP
2426 r = sd_journal_seek_tail(j);
2427 if (r < 0) {
da927ba9 2428 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2429 goto finish;
2100675e
LP
2430 }
2431
2432 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 2433
d89d6c86
LN
2434 } else if (arg_reverse) {
2435 r = sd_journal_seek_tail(j);
2436 if (r < 0) {
da927ba9 2437 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2438 goto finish;
d89d6c86
LN
2439 }
2440
2441 r = sd_journal_previous(j);
2442
2100675e
LP
2443 } else {
2444 r = sd_journal_seek_head(j);
2445 if (r < 0) {
da927ba9 2446 log_error_errno(r, "Failed to seek to head: %m");
909dea0c 2447 goto finish;
2100675e 2448 }
6f003b43
LP
2449
2450 r = sd_journal_next(j);
2451 }
2452
2453 if (r < 0) {
da927ba9 2454 log_error_errno(r, "Failed to iterate through journal: %m");
909dea0c 2455 goto finish;
50f20cfd 2456 }
5f42943c
LK
2457 if (r == 0)
2458 need_seek = true;
87d2c1ff 2459
faf5077f 2460 if (!arg_follow)
0221d68a 2461 (void) pager_open(arg_pager_flags);
0d43c694 2462
5f42943c 2463 if (!arg_quiet && (arg_lines != 0 || arg_follow)) {
cfbc22ab
LP
2464 usec_t start, end;
2465 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
2466
2467 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
2468 if (r < 0) {
da927ba9 2469 log_error_errno(r, "Failed to get cutoff: %m");
cfbc22ab
LP
2470 goto finish;
2471 }
2472
2473 if (r > 0) {
2474 if (arg_follow)
9048b11f 2475 printf("-- Logs begin at %s. --\n",
5ab99e07 2476 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2477 else
9048b11f 2478 printf("-- Logs begin at %s, end at %s. --\n",
5ab99e07
LP
2479 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2480 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2481 }
2482 }
2483
50f20cfd 2484 for (;;) {
67e04a48 2485 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab 2486 int flags;
b4766d5f 2487 size_t highlight[2] = {};
cfbc22ab 2488
6f003b43 2489 if (need_seek) {
99613ec5 2490 if (!arg_reverse)
d89d6c86
LN
2491 r = sd_journal_next(j);
2492 else
2493 r = sd_journal_previous(j);
6f003b43 2494 if (r < 0) {
da927ba9 2495 log_error_errno(r, "Failed to iterate through journal: %m");
6f003b43
LP
2496 goto finish;
2497 }
a72b6353
ZJS
2498 if (r == 0)
2499 break;
0d43c694
LP
2500 }
2501
d89d6c86 2502 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
2503 usec_t usec;
2504
2505 r = sd_journal_get_realtime_usec(j, &usec);
2506 if (r < 0) {
da927ba9 2507 log_error_errno(r, "Failed to determine timestamp: %m");
cfbc22ab
LP
2508 goto finish;
2509 }
3ba09ee8
PF
2510 if (usec > arg_until)
2511 goto finish;
cfbc22ab
LP
2512 }
2513
d89d6c86
LN
2514 if (arg_since_set && arg_reverse) {
2515 usec_t usec;
2516
2517 r = sd_journal_get_realtime_usec(j, &usec);
2518 if (r < 0) {
da927ba9 2519 log_error_errno(r, "Failed to determine timestamp: %m");
d89d6c86
LN
2520 goto finish;
2521 }
2522 if (usec < arg_since)
2523 goto finish;
2524 }
2525
4bed2485 2526 if (!arg_merge && !arg_quiet) {
cd931c0a 2527 sd_id128_t boot_id;
14a65d65 2528
cd931c0a
LP
2529 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2530 if (r >= 0) {
2531 if (previous_boot_id_valid &&
2532 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c 2533 printf("%s-- Reboot --%s\n",
1fc464f6 2534 ansi_highlight(), ansi_normal());
cd931c0a
LP
2535
2536 previous_boot_id = boot_id;
2537 previous_boot_id_valid = true;
2538 }
14a65d65
LP
2539 }
2540
6becf48c 2541#if HAVE_PCRE2
61c5f8a1 2542 if (arg_compiled_pattern) {
6becf48c
ZJS
2543 _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL;
2544 const void *message;
2545 size_t len;
b4766d5f 2546 PCRE2_SIZE *ovec;
6becf48c
ZJS
2547
2548 md = pcre2_match_data_create(1, NULL);
2549 if (!md)
2550 return log_oom();
2551
2552 r = sd_journal_get_data(j, "MESSAGE", &message, &len);
2553 if (r < 0) {
2554 if (r == -ENOENT) {
2555 need_seek = true;
2556 continue;
2557 }
2558
2559 log_error_errno(r, "Failed to get MESSAGE field: %m");
2560 goto finish;
2561 }
2562
2563 assert_se(message = startswith(message, "MESSAGE="));
2564
61c5f8a1 2565 r = pcre2_match(arg_compiled_pattern,
6becf48c
ZJS
2566 message,
2567 len - strlen("MESSAGE="),
2568 0, /* start at offset 0 in the subject */
2569 0, /* default options */
2570 md,
2571 NULL);
2572 if (r == PCRE2_ERROR_NOMATCH) {
2573 need_seek = true;
2574 continue;
2575 }
2576 if (r < 0) {
2577 unsigned char buf[LINE_MAX];
2578 int r2;
2579
2580 r2 = pcre2_get_error_message(r, buf, sizeof buf);
2581 log_error("Pattern matching failed: %s",
2582 r2 < 0 ? "unknown error" : (char*) buf);
2583 r = -EINVAL;
2584 goto finish;
2585 }
b4766d5f
ZJS
2586
2587 ovec = pcre2_get_ovector_pointer(md);
2588 highlight[0] = ovec[0];
2589 highlight[1] = ovec[1];
6becf48c
ZJS
2590 }
2591#endif
2592
cfbc22ab 2593 flags =
cd4b13e0 2594 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 2595 arg_full * OUTPUT_FULL_WIDTH |
40c9fe4c 2596 colors_enabled() * OUTPUT_COLOR |
9fd29044 2597 arg_catalog * OUTPUT_CATALOG |
991e274b
LP
2598 arg_utc * OUTPUT_UTC |
2599 arg_no_hostname * OUTPUT_NO_HOSTNAME;
cfbc22ab 2600
9b972c9a
ZJS
2601 r = show_journal_entry(stdout, j, arg_output, 0, flags,
2602 arg_output_fields, highlight, &ellipsized);
a72b6353
ZJS
2603 need_seek = true;
2604 if (r == -EADDRNOTAVAIL)
2605 break;
2a1e0f22 2606 else if (r < 0)
72f59706 2607 goto finish;
6f003b43 2608
cfbc22ab 2609 n_shown++;
ec316d19
PP
2610
2611 /* If journalctl take a long time to process messages, and during that time journal file
2612 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2613 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2614 * in the "following" case. By periodically calling sd_journal_process() during the processing
2615 * loop we shrink the window of time a client instance has open file descriptors for rotated
2616 * (deleted) journal files. */
2617 if ((n_shown % PROCESS_INOTIFY_INTERVAL) == 0) {
2618 r = sd_journal_process(j);
2619 if (r < 0) {
2620 log_error_errno(r, "Failed to process inotify events: %m");
2621 goto finish;
2622 }
2623 }
87d2c1ff
LP
2624 }
2625
248fc619 2626 if (!arg_follow) {
5f42943c
LK
2627 if (n_shown == 0 && !arg_quiet)
2628 printf("-- No entries --\n");
2629
d9e15cbd 2630 if (arg_show_cursor || arg_cursor_file) {
248fc619
ZJS
2631 _cleanup_free_ char *cursor = NULL;
2632
2633 r = sd_journal_get_cursor(j, &cursor);
2634 if (r < 0 && r != -EADDRNOTAVAIL)
da927ba9 2635 log_error_errno(r, "Failed to get cursor: %m");
d9e15cbd
JS
2636 else if (r >= 0) {
2637 if (arg_show_cursor)
2638 printf("-- cursor: %s\n", cursor);
2639
2640 if (arg_cursor_file) {
2641 r = write_string_file(arg_cursor_file, cursor,
2642 WRITE_STRING_FILE_CREATE |
2643 WRITE_STRING_FILE_ATOMIC);
2644 if (r < 0)
2645 log_error_errno(r,
2646 "Failed to write new cursor to %s: %m",
2647 arg_cursor_file);
2648 }
2649 }
248fc619
ZJS
2650 }
2651
50f20cfd 2652 break;
248fc619 2653 }
50f20cfd 2654
b1aa5ced 2655 fflush(stdout);
2a1e0f22
LP
2656
2657 r = wait_for_change(j, poll_fd);
2658 if (r < 0)
50f20cfd 2659 goto finish;
67e04a48
ZJS
2660
2661 first_line = false;
de190aef 2662 }
87d2c1ff
LP
2663
2664finish:
b1aa5ced 2665 fflush(stdout);
0d43c694
LP
2666 pager_close();
2667
a36b8deb
ZJS
2668 strv_free(arg_file);
2669
d52da205
LP
2670 strv_free(arg_syslog_identifier);
2671 strv_free(arg_system_units);
2672 strv_free(arg_user_units);
cc25a67e 2673 strv_free(arg_output_fields);
d52da205 2674
0f03c2a4 2675 free(arg_root);
6bae9b2a 2676 free(arg_verify_key);
0f03c2a4 2677
6becf48c 2678#if HAVE_PCRE2
61c5f8a1
ZJS
2679 if (arg_compiled_pattern)
2680 pcre2_code_free(arg_compiled_pattern);
6becf48c
ZJS
2681#endif
2682
3fbf9cbb 2683 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2684}