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