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