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