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