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