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