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