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