]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
Merge pull request #8222 from poettering/journal-by-inode
[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
52051dd8
LP
975 if (!strv_isempty(arg_system_units) && (arg_journal_type == SD_JOURNAL_CURRENT_USER)) {
976
977 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
978 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
979 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
980 r = strv_extend_strv(&arg_user_units, arg_system_units, true);
981 if (r < 0)
e50412ef 982 return r;
52051dd8
LP
983
984 arg_system_units = strv_free(arg_system_units);
985 }
986
61c5f8a1
ZJS
987
988#if HAVE_PCRE2
989 if (arg_pattern) {
990 unsigned flags;
991
992 if (arg_case_sensitive >= 0)
993 flags = !arg_case_sensitive * PCRE2_CASELESS;
994 else {
995 _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL;
996 bool has_case;
997 _cleanup_(pcre2_code_freep) pcre2_code *cs = NULL;
998
999 md = pcre2_match_data_create(1, NULL);
1000 if (!md)
1001 return log_oom();
1002
1003 r = pattern_compile("[[:upper:]]", 0, &cs);
1004 if (r < 0)
1005 return r;
1006
1007 r = pcre2_match(cs, (PCRE2_SPTR8) arg_pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL);
1008 has_case = r >= 0;
1009
1010 flags = !has_case * PCRE2_CASELESS;
1011 }
1012
1013 log_debug("Doing case %s matching based on %s",
1014 flags & PCRE2_CASELESS ? "insensitive" : "sensitive",
1015 arg_case_sensitive >= 0 ? "request" : "pattern casing");
1016
1017 r = pattern_compile(arg_pattern, flags, &arg_compiled_pattern);
1018 if (r < 0)
1019 return r;
1020 }
1021#endif
1022
0d43c694
LP
1023 return 1;
1024}
1025
39f7f5c1 1026static int generate_new_id128(void) {
55ee336c
LP
1027 sd_id128_t id;
1028 int r;
1029 unsigned i;
1030
1031 r = sd_id128_randomize(&id);
23bbb0de
MS
1032 if (r < 0)
1033 return log_error_errno(r, "Failed to generate ID: %m");
55ee336c
LP
1034
1035 printf("As string:\n"
1036 SD_ID128_FORMAT_STR "\n\n"
1037 "As UUID:\n"
1038 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
cc7de2ba 1039 "As man:sd-id128(3) macro:\n"
d489071f 1040 "#define MESSAGE_XYZ SD_ID128_MAKE(",
55ee336c
LP
1041 SD_ID128_FORMAT_VAL(id),
1042 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
1043 for (i = 0; i < 16; i++)
1044 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
d489071f 1045 fputs(")\n\n", stdout);
55ee336c 1046
d489071f
ZJS
1047 printf("As Python constant:\n"
1048 ">>> import uuid\n"
1049 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
1050 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
1051
1052 return 0;
1053}
1054
a963990f
LP
1055static int add_matches(sd_journal *j, char **args) {
1056 char **i;
4e602943 1057 bool have_term = false;
59cea26a 1058
a963990f 1059 assert(j);
59cea26a 1060
a963990f 1061 STRV_FOREACH(i, args) {
52aeb63c 1062 int r;
59cea26a 1063
4e602943
ZJS
1064 if (streq(*i, "+")) {
1065 if (!have_term)
1066 break;
cbdca852 1067 r = sd_journal_add_disjunction(j);
4e602943
ZJS
1068 have_term = false;
1069
1070 } else if (path_is_absolute(*i)) {
e1873695 1071 _cleanup_free_ char *p = NULL, *t = NULL, *t2 = NULL, *interpreter = NULL;
a963990f 1072 struct stat st;
e5124088 1073
c4f4fce7 1074 r = chase_symlinks(*i, NULL, 0, &p);
e1873695
LP
1075 if (r < 0)
1076 return log_error_errno(r, "Couldn't canonicalize path: %m");
e5124088 1077
e1873695 1078 if (lstat(p, &st) < 0)
4a62c710 1079 return log_error_errno(errno, "Couldn't stat file: %m");
e5124088 1080
68fee104 1081 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
e1873695 1082 if (executable_is_script(p, &interpreter) > 0) {
68fee104
ZJS
1083 _cleanup_free_ char *comm;
1084
e1873695 1085 comm = strndup(basename(p), 15);
68fee104
ZJS
1086 if (!comm)
1087 return log_oom();
1088
1089 t = strappend("_COMM=", comm);
795ab08f
MS
1090 if (!t)
1091 return log_oom();
68fee104
ZJS
1092
1093 /* Append _EXE only if the interpreter is not a link.
73e231ab 1094 Otherwise, it might be outdated often. */
795ab08f 1095 if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) {
68fee104
ZJS
1096 t2 = strappend("_EXE=", interpreter);
1097 if (!t2)
1098 return log_oom();
1099 }
795ab08f 1100 } else {
e1873695 1101 t = strappend("_EXE=", p);
795ab08f
MS
1102 if (!t)
1103 return log_oom();
1104 }
1105
1106 r = sd_journal_add_match(j, t, 0);
1107
1108 if (r >=0 && t2)
1109 r = sd_journal_add_match(j, t2, 0);
1110
1111 } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
e1873695 1112 r = add_matches_for_device(j, p);
795ab08f
MS
1113 if (r < 0)
1114 return r;
1115 } else {
fb93cf73 1116 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
a963990f 1117 return -EINVAL;
50940700 1118 }
e5124088 1119
4e602943 1120 have_term = true;
4e602943 1121 } else {
cbdca852 1122 r = sd_journal_add_match(j, *i, 0);
4e602943
ZJS
1123 have_term = true;
1124 }
e5124088 1125
23bbb0de
MS
1126 if (r < 0)
1127 return log_error_errno(r, "Failed to add match '%s': %m", *i);
de7b95cd
LP
1128 }
1129
4e602943
ZJS
1130 if (!strv_isempty(args) && !have_term) {
1131 log_error("\"+\" can only be used between terms");
1132 return -EINVAL;
1133 }
1134
a963990f
LP
1135 return 0;
1136}
1137
9530e0d0
LP
1138static void boot_id_free_all(BootId *l) {
1139
1140 while (l) {
1141 BootId *i = l;
1142 LIST_REMOVE(boot_list, l, i);
1143 free(i);
1144 }
1145}
1146
dc009662
LP
1147static int discover_next_boot(sd_journal *j,
1148 sd_id128_t previous_boot_id,
1149 bool advance_older,
1150 BootId **ret) {
45bc27b6 1151
45bc27b6 1152 _cleanup_free_ BootId *next_boot = NULL;
dc009662
LP
1153 char match[9+32+1] = "_BOOT_ID=";
1154 sd_id128_t boot_id;
1155 int r;
ea7061e4
JJ
1156
1157 assert(j);
dc009662 1158 assert(ret);
596a2329
JJ
1159
1160 /* We expect the journal to be on the last position of a boot
1161 * (in relation to the direction we are going), so that the next
1162 * invocation of sd_journal_next/previous will be from a different
1163 * boot. We then collect any information we desire and then jump
1164 * to the last location of the new boot by using a _BOOT_ID match
1165 * coming from the other journal direction. */
1166
1167 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1168 * we can actually advance to a *different* boot. */
1169 sd_journal_flush_matches(j);
1170
dc009662
LP
1171 do {
1172 if (advance_older)
1173 r = sd_journal_previous(j);
1174 else
1175 r = sd_journal_next(j);
1176 if (r < 0)
1177 return r;
1178 else if (r == 0)
1179 return 0; /* End of journal, yay. */
1180
1181 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1182 if (r < 0)
1183 return r;
1184
1185 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1186 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1187 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1188 * complete than the main entry array, and hence might reference an entry that's not actually the last
1189 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1190 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1191 * necessary. */
1192
1193 } while (sd_id128_equal(boot_id, previous_boot_id));
596a2329 1194
45bc27b6 1195 next_boot = new0(BootId, 1);
596a2329 1196 if (!next_boot)
b56d608e 1197 return -ENOMEM;
f1188074 1198
dc009662 1199 next_boot->id = boot_id;
f1188074 1200
d1bf9dc9
LP
1201 r = sd_journal_get_realtime_usec(j, &next_boot->first);
1202 if (r < 0)
1203 return r;
ea7061e4 1204
596a2329
JJ
1205 /* Now seek to the last occurrence of this boot ID. */
1206 sd_id128_to_string(next_boot->id, match + 9);
1207 r = sd_journal_add_match(j, match, sizeof(match) - 1);
1208 if (r < 0)
1209 return r;
f1188074 1210
596a2329
JJ
1211 if (advance_older)
1212 r = sd_journal_seek_head(j);
1213 else
1214 r = sd_journal_seek_tail(j);
1215 if (r < 0)
1216 return r;
f1188074 1217
596a2329
JJ
1218 if (advance_older)
1219 r = sd_journal_next(j);
1220 else
1221 r = sd_journal_previous(j);
1222 if (r < 0)
1223 return r;
202fd896
LP
1224 else if (r == 0) {
1225 log_debug("Whoopsie! We found a boot ID but can't read its last entry.");
596a2329 1226 return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */
202fd896 1227 }
f1188074 1228
d1bf9dc9
LP
1229 r = sd_journal_get_realtime_usec(j, &next_boot->last);
1230 if (r < 0)
1231 return r;
596a2329 1232
dc009662 1233 *ret = next_boot;
596a2329 1234 next_boot = NULL;
9530e0d0 1235
596a2329
JJ
1236 return 0;
1237}
1238
45bc27b6
LP
1239static int get_boots(
1240 sd_journal *j,
1241 BootId **boots,
07ff6b08
ZJS
1242 sd_id128_t *boot_id,
1243 int offset) {
45bc27b6 1244
596a2329
JJ
1245 bool skip_once;
1246 int r, count = 0;
ec02a6c9 1247 BootId *head = NULL, *tail = NULL, *id;
07ff6b08 1248 const bool advance_older = boot_id && offset <= 0;
dc009662 1249 sd_id128_t previous_boot_id;
596a2329
JJ
1250
1251 assert(j);
f1188074 1252
596a2329
JJ
1253 /* Adjust for the asymmetry that offset 0 is
1254 * the last (and current) boot, while 1 is considered the
1255 * (chronological) first boot in the journal. */
592855c3 1256 skip_once = boot_id && sd_id128_is_null(*boot_id) && offset <= 0;
596a2329
JJ
1257
1258 /* Advance to the earliest/latest occurrence of our reference
1259 * boot ID (taking our lookup direction into account), so that
1260 * discover_next_boot() can do its job.
1261 * If no reference is given, the journal head/tail will do,
1262 * they're "virtual" boots after all. */
07ff6b08 1263 if (boot_id && !sd_id128_is_null(*boot_id)) {
596a2329
JJ
1264 char match[9+32+1] = "_BOOT_ID=";
1265
1266 sd_journal_flush_matches(j);
1267
07ff6b08 1268 sd_id128_to_string(*boot_id, match + 9);
596a2329 1269 r = sd_journal_add_match(j, match, sizeof(match) - 1);
f1188074
ZJS
1270 if (r < 0)
1271 return r;
1272
596a2329 1273 if (advance_older)
c4fbc6b6 1274 r = sd_journal_seek_head(j); /* seek to oldest */
596a2329 1275 else
c4fbc6b6 1276 r = sd_journal_seek_tail(j); /* seek to newest */
f1188074
ZJS
1277 if (r < 0)
1278 return r;
1279
596a2329 1280 if (advance_older)
c4fbc6b6 1281 r = sd_journal_next(j); /* read the oldest entry */
596a2329 1282 else
c4fbc6b6 1283 r = sd_journal_previous(j); /* read the most recently added entry */
f1188074
ZJS
1284 if (r < 0)
1285 return r;
1286 else if (r == 0)
596a2329 1287 goto finish;
07ff6b08 1288 else if (offset == 0) {
596a2329
JJ
1289 count = 1;
1290 goto finish;
1291 }
c4fbc6b6
LP
1292
1293 /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
1294 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1295 * the following entry, which must then have an older/newer boot ID */
596a2329 1296 } else {
c4fbc6b6 1297
596a2329 1298 if (advance_older)
c4fbc6b6 1299 r = sd_journal_seek_tail(j); /* seek to newest */
596a2329 1300 else
c4fbc6b6 1301 r = sd_journal_seek_head(j); /* seek to oldest */
f1188074
ZJS
1302 if (r < 0)
1303 return r;
1304
c4fbc6b6
LP
1305 /* No sd_journal_next()/_previous() here.
1306 *
1307 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1308 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1309 * entry we have. */
596a2329 1310 }
f1188074 1311
dc009662 1312 previous_boot_id = SD_ID128_NULL;
45bc27b6
LP
1313 for (;;) {
1314 _cleanup_free_ BootId *current = NULL;
f1188074 1315
dc009662 1316 r = discover_next_boot(j, previous_boot_id, advance_older, &current);
596a2329 1317 if (r < 0) {
9530e0d0 1318 boot_id_free_all(head);
596a2329 1319 return r;
ea7061e4 1320 }
f1188074 1321
596a2329
JJ
1322 if (!current)
1323 break;
1324
dc009662
LP
1325 previous_boot_id = current->id;
1326
07ff6b08 1327 if (boot_id) {
596a2329 1328 if (!skip_once)
07ff6b08 1329 offset += advance_older ? 1 : -1;
596a2329
JJ
1330 skip_once = false;
1331
07ff6b08 1332 if (offset == 0) {
596a2329 1333 count = 1;
07ff6b08 1334 *boot_id = current->id;
596a2329
JJ
1335 break;
1336 }
1337 } else {
ec02a6c9
HK
1338 LIST_FOREACH(boot_list, id, head) {
1339 if (sd_id128_equal(id->id, current->id)) {
1340 /* boot id already stored, something wrong with the journal files */
1341 /* exiting as otherwise this problem would cause forever loop */
1342 goto finish;
1343 }
1344 }
596a2329
JJ
1345 LIST_INSERT_AFTER(boot_list, head, tail, current);
1346 tail = current;
1347 current = NULL;
1348 count++;
1349 }
f1188074
ZJS
1350 }
1351
596a2329
JJ
1352finish:
1353 if (boots)
1354 *boots = head;
1355
1356 sd_journal_flush_matches(j);
1357
1358 return count;
ea7061e4
JJ
1359}
1360
1361static int list_boots(sd_journal *j) {
596a2329 1362 int w, i, count;
9530e0d0 1363 BootId *id, *all_ids;
ea7061e4
JJ
1364
1365 assert(j);
1366
596a2329 1367 count = get_boots(j, &all_ids, NULL, 0);
b56d608e
LP
1368 if (count < 0)
1369 return log_error_errno(count, "Failed to determine boots: %m");
1370 if (count == 0)
596a2329 1371 return count;
ea7061e4 1372
ea4b98e6 1373 pager_open(arg_no_pager, arg_pager_end);
f1188074
ZJS
1374
1375 /* numbers are one less, but we need an extra char for the sign */
1376 w = DECIMAL_STR_WIDTH(count - 1) + 1;
1377
596a2329 1378 i = 0;
9530e0d0 1379 LIST_FOREACH(boot_list, id, all_ids) {
f1188074
ZJS
1380 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
1381
1382 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
1383 w, i - count + 1,
1384 SD_ID128_FORMAT_VAL(id->id),
5ab99e07
LP
1385 format_timestamp_maybe_utc(a, sizeof(a), id->first),
1386 format_timestamp_maybe_utc(b, sizeof(b), id->last));
596a2329 1387 i++;
d121b396 1388 }
a963990f 1389
9530e0d0
LP
1390 boot_id_free_all(all_ids);
1391
a331b5e6
JJ
1392 return 0;
1393}
1394
1395static int add_boot(sd_journal *j) {
1396 char match[9+32+1] = "_BOOT_ID=";
07ff6b08 1397 sd_id128_t boot_id;
442e2def 1398 int r;
a331b5e6
JJ
1399
1400 assert(j);
1401
d121b396 1402 if (!arg_boot)
a331b5e6
JJ
1403 return 0;
1404
592855c3
ZJS
1405 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1406 * We can do this only when we logs are coming from the current machine,
1407 * so take the slow path if log location is specified. */
3bbaff3e 1408 if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) &&
0a175093 1409 !arg_directory && !arg_file && !arg_root)
592855c3 1410
b6741478 1411 return add_match_this_boot(j, arg_machine);
a331b5e6 1412
07ff6b08
ZJS
1413 boot_id = arg_boot_id;
1414 r = get_boots(j, NULL, &boot_id, arg_boot_offset);
596a2329
JJ
1415 assert(r <= 1);
1416 if (r <= 0) {
1417 const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r);
1418
1419 if (sd_id128_is_null(arg_boot_id))
c34e9399
JS
1420 log_error("Data from the specified boot (%+i) is not available: %s",
1421 arg_boot_offset, reason);
d121b396 1422 else
c34e9399
JS
1423 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s",
1424 SD_ID128_FORMAT_VAL(arg_boot_id), reason);
596a2329
JJ
1425
1426 return r == 0 ? -ENODATA : r;
a331b5e6
JJ
1427 }
1428
07ff6b08 1429 sd_id128_to_string(boot_id, match + 9);
d121b396
ZJS
1430
1431 r = sd_journal_add_match(j, match, sizeof(match) - 1);
23bbb0de
MS
1432 if (r < 0)
1433 return log_error_errno(r, "Failed to add match: %m");
a331b5e6
JJ
1434
1435 r = sd_journal_add_conjunction(j);
1436 if (r < 0)
b56d608e 1437 return log_error_errno(r, "Failed to add conjunction: %m");
a331b5e6
JJ
1438
1439 return 0;
a963990f
LP
1440}
1441
99271804
ZJS
1442static int add_dmesg(sd_journal *j) {
1443 int r;
1444 assert(j);
1445
1446 if (!arg_dmesg)
1447 return 0;
1448
fbd0b64f
LP
1449 r = sd_journal_add_match(j, "_TRANSPORT=kernel",
1450 STRLEN("_TRANSPORT=kernel"));
23bbb0de
MS
1451 if (r < 0)
1452 return log_error_errno(r, "Failed to add match: %m");
99271804
ZJS
1453
1454 r = sd_journal_add_conjunction(j);
1455 if (r < 0)
b56d608e 1456 return log_error_errno(r, "Failed to add conjunction: %m");
99271804
ZJS
1457
1458 return 0;
1459}
1460
b56d608e
LP
1461static int get_possible_units(
1462 sd_journal *j,
1463 const char *fields,
1464 char **patterns,
1465 Set **units) {
1466
ea18a4b5
ZJS
1467 _cleanup_set_free_free_ Set *found;
1468 const char *field;
c3f60ec5 1469 int r;
ea18a4b5 1470
d5099efc 1471 found = set_new(&string_hash_ops);
ea18a4b5 1472 if (!found)
b56d608e 1473 return -ENOMEM;
ea18a4b5
ZJS
1474
1475 NULSTR_FOREACH(field, fields) {
1476 const void *data;
1477 size_t size;
1478
1479 r = sd_journal_query_unique(j, field);
1480 if (r < 0)
1481 return r;
1482
1483 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1484 char **pattern, *eq;
1485 size_t prefix;
1486 _cleanup_free_ char *u = NULL;
1487
1488 eq = memchr(data, '=', size);
1489 if (eq)
1490 prefix = eq - (char*) data + 1;
1491 else
1492 prefix = 0;
1493
1494 u = strndup((char*) data + prefix, size - prefix);
1495 if (!u)
b56d608e 1496 return -ENOMEM;
ea18a4b5
ZJS
1497
1498 STRV_FOREACH(pattern, patterns)
1499 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1500 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1501
1502 r = set_consume(found, u);
1503 u = NULL;
1504 if (r < 0 && r != -EEXIST)
1505 return r;
1506
1507 break;
1508 }
1509 }
1510 }
1511
1512 *units = found;
1513 found = NULL;
1514 return 0;
1515}
1516
1517/* This list is supposed to return the superset of unit names
1518 * possibly matched by rules added with add_matches_for_unit... */
1519#define SYSTEM_UNITS \
1520 "_SYSTEMD_UNIT\0" \
1521 "COREDUMP_UNIT\0" \
1522 "UNIT\0" \
1523 "OBJECT_SYSTEMD_UNIT\0" \
1524 "_SYSTEMD_SLICE\0"
1525
1526/* ... and add_matches_for_user_unit */
1527#define USER_UNITS \
1528 "_SYSTEMD_USER_UNIT\0" \
1529 "USER_UNIT\0" \
1530 "COREDUMP_USER_UNIT\0" \
1531 "OBJECT_SYSTEMD_USER_UNIT\0"
1532
1533static int add_units(sd_journal *j) {
1534 _cleanup_strv_free_ char **patterns = NULL;
1535 int r, count = 0;
b9e40524 1536 char **i;
c3f60ec5
LP
1537
1538 assert(j);
1539
b9e40524 1540 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1541 _cleanup_free_ char *u = NULL;
1542
7410616c
LP
1543 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1544 if (r < 0)
1545 return r;
ea18a4b5
ZJS
1546
1547 if (string_is_glob(u)) {
1548 r = strv_push(&patterns, u);
1549 if (r < 0)
1550 return r;
1551 u = NULL;
1552 } else {
1553 r = add_matches_for_unit(j, u);
1554 if (r < 0)
1555 return r;
1556 r = sd_journal_add_disjunction(j);
1557 if (r < 0)
1558 return r;
313cefa1 1559 count++;
ea18a4b5
ZJS
1560 }
1561 }
1562
1563 if (!strv_isempty(patterns)) {
1564 _cleanup_set_free_free_ Set *units = NULL;
1565 Iterator it;
1566 char *u;
1567
1568 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1569 if (r < 0)
1570 return r;
ea18a4b5
ZJS
1571
1572 SET_FOREACH(u, units, it) {
1573 r = add_matches_for_unit(j, u);
1574 if (r < 0)
1575 return r;
1576 r = sd_journal_add_disjunction(j);
1577 if (r < 0)
1578 return r;
313cefa1 1579 count++;
ea18a4b5 1580 }
b9e40524 1581 }
c3f60ec5 1582
97b11eed 1583 patterns = strv_free(patterns);
ea18a4b5 1584
b9e40524 1585 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1586 _cleanup_free_ char *u = NULL;
1587
7410616c
LP
1588 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1589 if (r < 0)
1590 return r;
c3f60ec5 1591
ea18a4b5
ZJS
1592 if (string_is_glob(u)) {
1593 r = strv_push(&patterns, u);
1594 if (r < 0)
1595 return r;
1596 u = NULL;
1597 } else {
1598 r = add_matches_for_user_unit(j, u, getuid());
1599 if (r < 0)
1600 return r;
1601 r = sd_journal_add_disjunction(j);
1602 if (r < 0)
1603 return r;
313cefa1 1604 count++;
ea18a4b5
ZJS
1605 }
1606 }
1607
1608 if (!strv_isempty(patterns)) {
1609 _cleanup_set_free_free_ Set *units = NULL;
1610 Iterator it;
1611 char *u;
b9e40524 1612
ea18a4b5 1613 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1614 if (r < 0)
1615 return r;
1616
ea18a4b5
ZJS
1617 SET_FOREACH(u, units, it) {
1618 r = add_matches_for_user_unit(j, u, getuid());
1619 if (r < 0)
1620 return r;
1621 r = sd_journal_add_disjunction(j);
1622 if (r < 0)
1623 return r;
313cefa1 1624 count++;
ea18a4b5 1625 }
b9e40524 1626 }
c3f60ec5 1627
ea18a4b5
ZJS
1628 /* Complain if the user request matches but nothing whatsoever was
1629 * found, since otherwise everything would be matched. */
1630 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1631 return -ENODATA;
1632
cd34b3c6
HH
1633 r = sd_journal_add_conjunction(j);
1634 if (r < 0)
1635 return r;
1636
c3f60ec5
LP
1637 return 0;
1638}
1639
941e990d
LP
1640static int add_priorities(sd_journal *j) {
1641 char match[] = "PRIORITY=0";
1642 int i, r;
941e990d
LP
1643 assert(j);
1644
1645 if (arg_priorities == 0xFF)
1646 return 0;
1647
1648 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1649 if (arg_priorities & (1 << i)) {
1650 match[sizeof(match)-2] = '0' + i;
1651
941e990d 1652 r = sd_journal_add_match(j, match, strlen(match));
23bbb0de
MS
1653 if (r < 0)
1654 return log_error_errno(r, "Failed to add match: %m");
941e990d
LP
1655 }
1656
cd34b3c6
HH
1657 r = sd_journal_add_conjunction(j);
1658 if (r < 0)
b56d608e 1659 return log_error_errno(r, "Failed to add conjunction: %m");
cd34b3c6 1660
941e990d
LP
1661 return 0;
1662}
1663
73083640
HH
1664
1665static int add_syslog_identifier(sd_journal *j) {
1666 int r;
1667 char **i;
1668
1669 assert(j);
1670
1671 STRV_FOREACH(i, arg_syslog_identifier) {
1672 char *u;
1673
63c372cb 1674 u = strjoina("SYSLOG_IDENTIFIER=", *i);
73083640
HH
1675 r = sd_journal_add_match(j, u, 0);
1676 if (r < 0)
1677 return r;
1678 r = sd_journal_add_disjunction(j);
1679 if (r < 0)
1680 return r;
1681 }
1682
1683 r = sd_journal_add_conjunction(j);
1684 if (r < 0)
1685 return r;
1686
1687 return 0;
1688}
1689
7560fffc 1690static int setup_keys(void) {
349cc4a5 1691#if HAVE_GCRYPT
7560fffc
LP
1692 size_t mpk_size, seed_size, state_size, i;
1693 uint8_t *mpk, *seed, *state;
11689d2a 1694 int fd = -1, r;
7560fffc
LP
1695 sd_id128_t machine, boot;
1696 char *p = NULL, *k = NULL;
baed47c3 1697 struct FSSHeader h;
14d10188 1698 uint64_t n;
b98e3866
SL
1699 struct stat st;
1700
1701 r = stat("/var/log/journal", &st);
4c701096 1702 if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR))
4a62c710 1703 return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
b98e3866
SL
1704
1705 if (r < 0 || !S_ISDIR(st.st_mode)) {
1706 log_error("%s is not a directory, must be using persistent logging for FSS.",
1707 "/var/log/journal");
1708 return r < 0 ? -errno : -ENOTDIR;
1709 }
7560fffc
LP
1710
1711 r = sd_id128_get_machine(&machine);
23bbb0de
MS
1712 if (r < 0)
1713 return log_error_errno(r, "Failed to get machine ID: %m");
7560fffc
LP
1714
1715 r = sd_id128_get_boot(&boot);
23bbb0de
MS
1716 if (r < 0)
1717 return log_error_errno(r, "Failed to get boot ID: %m");
7560fffc 1718
baed47c3 1719 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1720 SD_ID128_FORMAT_VAL(machine)) < 0)
1721 return log_oom();
1722
faf9da01
ZJS
1723 if (arg_force) {
1724 r = unlink(p);
1725 if (r < 0 && errno != ENOENT) {
1726 r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
b8547c10
SL
1727 goto finish;
1728 }
faf9da01
ZJS
1729 } else if (access(p, F_OK) >= 0) {
1730 log_error("Sealing key file %s exists already. Use --force to recreate.", p);
1731 r = -EEXIST;
1732 goto finish;
7560fffc
LP
1733 }
1734
baed47c3 1735 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1736 SD_ID128_FORMAT_VAL(machine)) < 0) {
1737 r = log_oom();
1738 goto finish;
1739 }
1740
1741 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1742 mpk = alloca(mpk_size);
1743
1744 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1745 seed = alloca(seed_size);
1746
1747 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1748 state = alloca(state_size);
1749
1750 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1751 if (fd < 0) {
76ef789d 1752 r = log_error_errno(errno, "Failed to open /dev/random: %m");
7560fffc
LP
1753 goto finish;
1754 }
1755
1756 log_info("Generating seed...");
a6dcc7e5
ZJS
1757 r = loop_read_exact(fd, seed, seed_size, true);
1758 if (r < 0) {
1759 log_error_errno(r, "Failed to read random seed: %m");
7560fffc
LP
1760 goto finish;
1761 }
1762
1763 log_info("Generating key pair...");
1764 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1765
baed47c3 1766 log_info("Generating sealing key...");
7560fffc
LP
1767 FSPRG_GenState0(state, mpk, seed, seed_size);
1768
baed47c3
LP
1769 assert(arg_interval > 0);
1770
7560fffc 1771 n = now(CLOCK_REALTIME);
baed47c3 1772 n /= arg_interval;
7560fffc 1773
03e334a1 1774 safe_close(fd);
646853bd 1775 fd = mkostemp_safe(k);
7560fffc 1776 if (fd < 0) {
709f6e46 1777 r = log_error_errno(fd, "Failed to open %s: %m", k);
7560fffc
LP
1778 goto finish;
1779 }
1780
f982e6f7
LP
1781 /* Enable secure remove, exclusion from dump, synchronous
1782 * writing and in-place updating */
1ed8f8c1 1783 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 1784 if (r < 0)
709f6e46 1785 log_warning_errno(r, "Failed to set file attributes: %m");
f982e6f7 1786
7560fffc
LP
1787 zero(h);
1788 memcpy(h.signature, "KSHHRHLP", 8);
1789 h.machine_id = machine;
1790 h.boot_id = boot;
1791 h.header_size = htole64(sizeof(h));
baed47c3
LP
1792 h.start_usec = htole64(n * arg_interval);
1793 h.interval_usec = htole64(arg_interval);
1794 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1795 h.fsprg_state_size = htole64(state_size);
7560fffc 1796
553acb7b
ZJS
1797 r = loop_write(fd, &h, sizeof(h), false);
1798 if (r < 0) {
1799 log_error_errno(r, "Failed to write header: %m");
7560fffc
LP
1800 goto finish;
1801 }
1802
553acb7b
ZJS
1803 r = loop_write(fd, state, state_size, false);
1804 if (r < 0) {
1805 log_error_errno(r, "Failed to write state: %m");
7560fffc
LP
1806 goto finish;
1807 }
1808
1809 if (link(k, p) < 0) {
76ef789d 1810 r = log_error_errno(errno, "Failed to link file: %m");
7560fffc
LP
1811 goto finish;
1812 }
1813
8481248b 1814 if (on_tty()) {
7560fffc
LP
1815 fprintf(stderr,
1816 "\n"
54f8c958 1817 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
c05276f2
LP
1818 "the following local file. This key file is automatically updated when the\n"
1819 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1820 "\n"
1821 "\t%s\n"
1822 "\n"
54f8c958 1823 "Please write down the following %ssecret verification key%s. It should be stored\n"
baed47c3 1824 "at a safe location and should not be saved locally on disk.\n"
54f8c958
LP
1825 "\n\t%s",
1826 ansi_highlight(), ansi_normal(),
9ea78383 1827 p,
54f8c958 1828 ansi_highlight(), ansi_normal(),
9ea78383 1829 ansi_highlight_red());
7560fffc
LP
1830 fflush(stderr);
1831 }
1832 for (i = 0; i < seed_size; i++) {
1833 if (i > 0 && i % 3 == 0)
1834 putchar('-');
1835 printf("%02x", ((uint8_t*) seed)[i]);
1836 }
1837
baed47c3
LP
1838 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1839
8481248b 1840 if (on_tty()) {
f6a971bc 1841 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1842
baed47c3 1843 fprintf(stderr,
54f8c958 1844 "%s\n"
baed47c3 1845 "The sealing key is automatically changed every %s.\n",
54f8c958 1846 ansi_normal(),
2fa4092c 1847 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1848
1849 hn = gethostname_malloc();
1850
1851 if (hn) {
ae691c1d 1852 hostname_cleanup(hn);
adac1c93 1853 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1854 } else
adac1c93 1855 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc 1856
349cc4a5 1857#if HAVE_QRENCODE
cf5a3432 1858 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1859 if (is_locale_utf8()) {
cf5a3432
LP
1860 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1861 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1862 }
f6a971bc
LP
1863#endif
1864 free(hn);
baed47c3 1865 }
7560fffc
LP
1866
1867 r = 0;
1868
1869finish:
03e334a1 1870 safe_close(fd);
7560fffc
LP
1871
1872 if (k) {
1873 unlink(k);
1874 free(k);
1875 }
1876
1877 free(p);
1878
1879 return r;
1880#else
feb12d3e 1881 log_error("Forward-secure sealing not available.");
15411c0c 1882 return -EOPNOTSUPP;
7560fffc
LP
1883#endif
1884}
1885
beec0085
LP
1886static int verify(sd_journal *j) {
1887 int r = 0;
1888 Iterator i;
1889 JournalFile *f;
1890
1891 assert(j);
1892
cedb42bb
LP
1893 log_show_color(true);
1894
c1f906bd 1895 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
beec0085 1896 int k;
a7f7d1bd 1897 usec_t first = 0, validated = 0, last = 0;
beec0085 1898
349cc4a5 1899#if HAVE_GCRYPT
feb12d3e 1900 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1901 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1902#endif
4da416aa 1903
2a7b539a 1904 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1905 if (k == -EINVAL) {
baed47c3 1906 /* If the key was invalid give up right-away. */
56e81f7c
LP
1907 return k;
1908 } else if (k < 0) {
e53fc357 1909 log_warning_errno(k, "FAIL: %s (%m)", f->path);
56e81f7c 1910 r = k;
6c7be122
LP
1911 } else {
1912 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1913 log_info("PASS: %s", f->path);
6c7be122 1914
c0ca7aee 1915 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1916 if (validated > 0) {
c0ca7aee 1917 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1918 format_timestamp_maybe_utc(a, sizeof(a), first),
1919 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1920 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1921 } else if (last > 0)
c0ca7aee 1922 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1923 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1924 else
1925 log_info("=> No sealing yet, no entries in file.");
1926 }
6c7be122 1927 }
beec0085
LP
1928 }
1929
1930 return r;
1931}
1932
74055aa7 1933static int flush_to_var(void) {
4afd3348
LP
1934 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1935 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
74055aa7
LP
1936 _cleanup_close_ int watch_fd = -1;
1937 int r;
1938
176ee07b
LP
1939 if (arg_machine) {
1940 log_error("--flush is not supported in conjunction with --machine=.");
1941 return -EOPNOTSUPP;
1942 }
1943
74055aa7
LP
1944 /* Quick exit */
1945 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1946 return 0;
1947
1948 /* OK, let's actually do the full logic, send SIGUSR1 to the
1949 * daemon and set up inotify to wait for the flushed file to appear */
266f3e26 1950 r = bus_connect_system_systemd(&bus);
23bbb0de
MS
1951 if (r < 0)
1952 return log_error_errno(r, "Failed to get D-Bus connection: %m");
74055aa7
LP
1953
1954 r = sd_bus_call_method(
1955 bus,
1956 "org.freedesktop.systemd1",
1957 "/org/freedesktop/systemd1",
1958 "org.freedesktop.systemd1.Manager",
1959 "KillUnit",
1960 &error,
1961 NULL,
1962 "ssi", "systemd-journald.service", "main", SIGUSR1);
94b65516
LP
1963 if (r < 0)
1964 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
74055aa7
LP
1965
1966 mkdir_p("/run/systemd/journal", 0755);
1967
1968 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
4a62c710
MS
1969 if (watch_fd < 0)
1970 return log_error_errno(errno, "Failed to create inotify watch: %m");
74055aa7
LP
1971
1972 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
4a62c710
MS
1973 if (r < 0)
1974 return log_error_errno(errno, "Failed to watch journal directory: %m");
74055aa7
LP
1975
1976 for (;;) {
1977 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1978 break;
1979
4a62c710 1980 if (errno != ENOENT)
f131770b 1981 return log_error_errno(errno, "Failed to check for existence of /run/systemd/journal/flushed: %m");
74055aa7
LP
1982
1983 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
23bbb0de
MS
1984 if (r < 0)
1985 return log_error_errno(r, "Failed to wait for event: %m");
74055aa7
LP
1986
1987 r = flush_fd(watch_fd);
23bbb0de
MS
1988 if (r < 0)
1989 return log_error_errno(r, "Failed to flush inotify events: %m");
74055aa7
LP
1990 }
1991
1992 return 0;
1993}
1994
dbd6e31c 1995static int send_signal_and_wait(int sig, const char *watch_path) {
4afd3348 1996 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
94b65516
LP
1997 _cleanup_close_ int watch_fd = -1;
1998 usec_t start;
1999 int r;
2000
176ee07b
LP
2001 if (arg_machine) {
2002 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
2003 return -EOPNOTSUPP;
2004 }
2005
33d52ab9 2006 start = now(CLOCK_MONOTONIC);
94b65516 2007
dbd6e31c
LP
2008 /* This call sends the specified signal to journald, and waits
2009 * for acknowledgment by watching the mtime of the specified
2010 * flag file. This is used to trigger syncing or rotation and
2011 * then wait for the operation to complete. */
94b65516
LP
2012
2013 for (;;) {
33d52ab9 2014 usec_t tstamp;
94b65516
LP
2015
2016 /* See if a sync happened by now. */
33d52ab9
LP
2017 r = read_timestamp_file(watch_path, &tstamp);
2018 if (r < 0 && r != -ENOENT)
2019 return log_error_errno(errno, "Failed to read %s: %m", watch_path);
2020 if (r >= 0 && tstamp >= start)
2021 return 0;
94b65516
LP
2022
2023 /* Let's ask for a sync, but only once. */
2024 if (!bus) {
4afd3348 2025 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
94b65516
LP
2026
2027 r = bus_connect_system_systemd(&bus);
2028 if (r < 0)
2029 return log_error_errno(r, "Failed to get D-Bus connection: %m");
2030
2031 r = sd_bus_call_method(
2032 bus,
2033 "org.freedesktop.systemd1",
2034 "/org/freedesktop/systemd1",
2035 "org.freedesktop.systemd1.Manager",
2036 "KillUnit",
2037 &error,
2038 NULL,
dbd6e31c 2039 "ssi", "systemd-journald.service", "main", sig);
94b65516
LP
2040 if (r < 0)
2041 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
2042
2043 continue;
2044 }
2045
2046 /* Let's install the inotify watch, if we didn't do that yet. */
2047 if (watch_fd < 0) {
2048
2049 mkdir_p("/run/systemd/journal", 0755);
2050
2051 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
2052 if (watch_fd < 0)
2053 return log_error_errno(errno, "Failed to create inotify watch: %m");
2054
33d52ab9 2055 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR);
94b65516
LP
2056 if (r < 0)
2057 return log_error_errno(errno, "Failed to watch journal directory: %m");
2058
2059 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
2060 continue;
2061 }
2062
2063 /* OK, all preparatory steps done, let's wait until
2064 * inotify reports an event. */
2065
2066 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
2067 if (r < 0)
2068 return log_error_errno(r, "Failed to wait for event: %m");
2069
2070 r = flush_fd(watch_fd);
2071 if (r < 0)
2072 return log_error_errno(r, "Failed to flush inotify events: %m");
2073 }
2074
2075 return 0;
2076}
2077
dbd6e31c
LP
2078static int rotate(void) {
2079 return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated");
2080}
2081
2082static int sync_journal(void) {
2083 return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced");
2084}
2085
a963990f
LP
2086int main(int argc, char *argv[]) {
2087 int r;
4afd3348 2088 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
a963990f 2089 bool need_seek = false;
14a65d65 2090 sd_id128_t previous_boot_id;
67e04a48
ZJS
2091 bool previous_boot_id_valid = false, first_line = true;
2092 int n_shown = 0;
94e0bd7d 2093 bool ellipsized = false;
a963990f 2094
a9cdc94f 2095 setlocale(LC_ALL, "");
a963990f
LP
2096 log_parse_environment();
2097 log_open();
2098
2099 r = parse_argv(argc, argv);
2100 if (r <= 0)
2101 goto finish;
2102
ed757c0c 2103 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 2104 sigbus_install();
ed757c0c 2105
de45d726
LP
2106 /* Increase max number of open files to 16K if we can, we
2107 * might needs this when browsing journal files, which might
2108 * be split up into many files. */
2109 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
2110
a020b3b3 2111 switch (arg_action) {
94b65516 2112
a020b3b3
LP
2113 case ACTION_NEW_ID128:
2114 r = generate_new_id128();
e3fdfb49 2115 goto finish;
e3fdfb49 2116
a020b3b3 2117 case ACTION_SETUP_KEYS:
7560fffc
LP
2118 r = setup_keys();
2119 goto finish;
844ec79b 2120
a020b3b3
LP
2121 case ACTION_LIST_CATALOG:
2122 case ACTION_DUMP_CATALOG:
2123 case ACTION_UPDATE_CATALOG: {
0c6ea3a4
ZJS
2124 _cleanup_free_ char *database;
2125
2126 database = path_join(arg_root, CATALOG_DATABASE, NULL);
2127 if (!database) {
2128 r = log_oom();
2129 goto finish;
13cbf3a5
ZJS
2130 }
2131
844ec79b 2132 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 2133 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b 2134 if (r < 0)
da927ba9 2135 log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
2136 } else {
2137 bool oneline = arg_action == ACTION_LIST_CATALOG;
2138
ea4b98e6 2139 pager_open(arg_no_pager, arg_pager_end);
a020b3b3 2140
844ec79b 2141 if (optind < argc)
a020b3b3 2142 r = catalog_list_items(stdout, database, oneline, argv + optind);
844ec79b 2143 else
13cbf3a5 2144 r = catalog_list(stdout, database, oneline);
844ec79b 2145 if (r < 0)
da927ba9 2146 log_error_errno(r, "Failed to list catalog: %m");
844ec79b 2147 }
d4205751 2148
d4205751
LP
2149 goto finish;
2150 }
2151
a020b3b3
LP
2152 case ACTION_FLUSH:
2153 r = flush_to_var();
2154 goto finish;
2155
2156 case ACTION_SYNC:
2157 r = sync_journal();
2158 goto finish;
2159
2160 case ACTION_ROTATE:
2161 r = rotate();
2162 goto finish;
2163
2164 case ACTION_SHOW:
2165 case ACTION_PRINT_HEADER:
2166 case ACTION_VERIFY:
2167 case ACTION_DISK_USAGE:
2168 case ACTION_LIST_BOOTS:
2169 case ACTION_VACUUM:
69e714f3
LP
2170 case ACTION_LIST_FIELDS:
2171 case ACTION_LIST_FIELD_NAMES:
a020b3b3
LP
2172 /* These ones require access to the journal files, continue below. */
2173 break;
2174
2175 default:
2176 assert_not_reached("Unknown action");
2177 }
2178
a963990f 2179 if (arg_directory)
3f3a438f 2180 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
0a175093
ZJS
2181 else if (arg_root)
2182 r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
5d1ce257
LP
2183 else if (arg_file_stdin) {
2184 int ifd = STDIN_FILENO;
2185 r = sd_journal_open_files_fd(&j, &ifd, 1, 0);
2186 } else if (arg_file)
8d98da3f 2187 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
d38c62cc
LP
2188 else if (arg_machine) {
2189 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2190 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2191 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2192 int fd;
2193
2194 if (geteuid() != 0) {
2195 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2196 * the container, thus we need root privileges to override them. */
2197 log_error("Using the --machine= switch requires root privileges.");
2198 r = -EPERM;
2199 goto finish;
2200 }
2201
2202 r = sd_bus_open_system(&bus);
2203 if (r < 0) {
2204 log_error_errno(r, "Failed to open system bus: %m");
2205 goto finish;
2206 }
2207
2208 r = sd_bus_call_method(
2209 bus,
2210 "org.freedesktop.machine1",
2211 "/org/freedesktop/machine1",
2212 "org.freedesktop.machine1.Manager",
2213 "OpenMachineRootDirectory",
2214 &error,
2215 &reply,
2216 "s", arg_machine);
2217 if (r < 0) {
2218 log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
2219 goto finish;
2220 }
2221
2222 r = sd_bus_message_read(reply, "h", &fd);
2223 if (r < 0) {
2224 bus_log_parse_error(r);
2225 goto finish;
2226 }
2227
2228 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
2229 if (fd < 0) {
2230 r = log_error_errno(errno, "Failed to duplicate file descriptor: %m");
2231 goto finish;
2232 }
2233
2234 r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT);
2235 if (r < 0)
2236 safe_close(fd);
2237 } else
3f3a438f 2238 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 2239 if (r < 0) {
a020b3b3 2240 log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
909dea0c 2241 goto finish;
a963990f
LP
2242 }
2243
4f37cbd9 2244 r = journal_access_check_and_warn(j, arg_quiet);
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}