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