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