]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[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
ee5324aa 319 (void) 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
2de6b06b 497 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:g: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
1cc6c93a
YW
924 if (!arg_output_fields)
925 arg_output_fields = TAKE_PTR(v);
926 else {
cc25a67e
LK
927 r = strv_extend_strv(&arg_output_fields, v, true);
928 if (r < 0)
929 return log_oom();
930 }
931 break;
932 }
933
eb9da376 934 case '?':
0d43c694 935 return -EINVAL;
eb9da376
LP
936
937 default:
938 assert_not_reached("Unhandled option");
0d43c694 939 }
0d43c694 940
70af7b8a 941 if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT)
e91af489
LP
942 arg_lines = 10;
943
0a175093
ZJS
944 if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root > 1) {
945 log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
8d98da3f
ZJS
946 return -EINVAL;
947 }
948
3ba09ee8 949 if (arg_since_set && arg_until_set && arg_since > arg_until) {
cfbc22ab
LP
950 log_error("--since= must be before --until=.");
951 return -EINVAL;
952 }
953
248fc619
ZJS
954 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
955 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
cfbc22ab
LP
956 return -EINVAL;
957 }
958
d89d6c86
LN
959 if (arg_follow && arg_reverse) {
960 log_error("Please specify either --reverse= or --follow=, not both.");
961 return -EINVAL;
962 }
963
f98a41c2 964 if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) {
0b6b7c20
ZJS
965 log_error("Extraneous arguments starting with '%s'", argv[optind]);
966 return -EINVAL;
967 }
968
f3bd7561
ZJS
969 if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge) {
970 log_error("Using --boot or --list-boots with --merge is not supported.");
596a2329
JJ
971 return -EINVAL;
972 }
973
e79d0b59 974 if (!strv_isempty(arg_system_units) && arg_journal_type == SD_JOURNAL_CURRENT_USER) {
52051dd8
LP
975 /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
976 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
977 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
978 r = strv_extend_strv(&arg_user_units, arg_system_units, true);
979 if (r < 0)
e50412ef 980 return r;
52051dd8
LP
981
982 arg_system_units = strv_free(arg_system_units);
983 }
984
61c5f8a1
ZJS
985
986#if HAVE_PCRE2
987 if (arg_pattern) {
988 unsigned flags;
989
990 if (arg_case_sensitive >= 0)
991 flags = !arg_case_sensitive * PCRE2_CASELESS;
992 else {
993 _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL;
994 bool has_case;
995 _cleanup_(pcre2_code_freep) pcre2_code *cs = NULL;
996
997 md = pcre2_match_data_create(1, NULL);
998 if (!md)
999 return log_oom();
1000
1001 r = pattern_compile("[[:upper:]]", 0, &cs);
1002 if (r < 0)
1003 return r;
1004
1005 r = pcre2_match(cs, (PCRE2_SPTR8) arg_pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL);
1006 has_case = r >= 0;
1007
1008 flags = !has_case * PCRE2_CASELESS;
1009 }
1010
1011 log_debug("Doing case %s matching based on %s",
1012 flags & PCRE2_CASELESS ? "insensitive" : "sensitive",
1013 arg_case_sensitive >= 0 ? "request" : "pattern casing");
1014
1015 r = pattern_compile(arg_pattern, flags, &arg_compiled_pattern);
1016 if (r < 0)
1017 return r;
1018 }
1019#endif
1020
0d43c694
LP
1021 return 1;
1022}
1023
39f7f5c1 1024static int generate_new_id128(void) {
55ee336c
LP
1025 sd_id128_t id;
1026 int r;
1027 unsigned i;
1028
1029 r = sd_id128_randomize(&id);
23bbb0de
MS
1030 if (r < 0)
1031 return log_error_errno(r, "Failed to generate ID: %m");
55ee336c
LP
1032
1033 printf("As string:\n"
1034 SD_ID128_FORMAT_STR "\n\n"
1035 "As UUID:\n"
1036 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
cc7de2ba 1037 "As man:sd-id128(3) macro:\n"
d489071f 1038 "#define MESSAGE_XYZ SD_ID128_MAKE(",
55ee336c
LP
1039 SD_ID128_FORMAT_VAL(id),
1040 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
1041 for (i = 0; i < 16; i++)
1042 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
d489071f 1043 fputs(")\n\n", stdout);
55ee336c 1044
d489071f
ZJS
1045 printf("As Python constant:\n"
1046 ">>> import uuid\n"
1047 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
1048 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
1049
1050 return 0;
1051}
1052
a963990f
LP
1053static int add_matches(sd_journal *j, char **args) {
1054 char **i;
4e602943 1055 bool have_term = false;
59cea26a 1056
a963990f 1057 assert(j);
59cea26a 1058
a963990f 1059 STRV_FOREACH(i, args) {
52aeb63c 1060 int r;
59cea26a 1061
4e602943
ZJS
1062 if (streq(*i, "+")) {
1063 if (!have_term)
1064 break;
cbdca852 1065 r = sd_journal_add_disjunction(j);
4e602943
ZJS
1066 have_term = false;
1067
1068 } else if (path_is_absolute(*i)) {
e1873695 1069 _cleanup_free_ char *p = NULL, *t = NULL, *t2 = NULL, *interpreter = NULL;
a963990f 1070 struct stat st;
e5124088 1071
62570f6f 1072 r = chase_symlinks(*i, NULL, CHASE_TRAIL_SLASH, &p);
e1873695
LP
1073 if (r < 0)
1074 return log_error_errno(r, "Couldn't canonicalize path: %m");
e5124088 1075
e1873695 1076 if (lstat(p, &st) < 0)
4a62c710 1077 return log_error_errno(errno, "Couldn't stat file: %m");
e5124088 1078
68fee104 1079 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
e1873695 1080 if (executable_is_script(p, &interpreter) > 0) {
68fee104
ZJS
1081 _cleanup_free_ char *comm;
1082
e1873695 1083 comm = strndup(basename(p), 15);
68fee104
ZJS
1084 if (!comm)
1085 return log_oom();
1086
1087 t = strappend("_COMM=", comm);
795ab08f
MS
1088 if (!t)
1089 return log_oom();
68fee104
ZJS
1090
1091 /* Append _EXE only if the interpreter is not a link.
73e231ab 1092 Otherwise, it might be outdated often. */
795ab08f 1093 if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) {
68fee104
ZJS
1094 t2 = strappend("_EXE=", interpreter);
1095 if (!t2)
1096 return log_oom();
1097 }
795ab08f 1098 } else {
e1873695 1099 t = strappend("_EXE=", p);
795ab08f
MS
1100 if (!t)
1101 return log_oom();
1102 }
1103
1104 r = sd_journal_add_match(j, t, 0);
1105
1106 if (r >=0 && t2)
1107 r = sd_journal_add_match(j, t2, 0);
1108
1109 } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
e1873695 1110 r = add_matches_for_device(j, p);
795ab08f
MS
1111 if (r < 0)
1112 return r;
1113 } else {
fb93cf73 1114 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
a963990f 1115 return -EINVAL;
50940700 1116 }
e5124088 1117
4e602943 1118 have_term = true;
4e602943 1119 } else {
cbdca852 1120 r = sd_journal_add_match(j, *i, 0);
4e602943
ZJS
1121 have_term = true;
1122 }
e5124088 1123
23bbb0de
MS
1124 if (r < 0)
1125 return log_error_errno(r, "Failed to add match '%s': %m", *i);
de7b95cd
LP
1126 }
1127
4e602943
ZJS
1128 if (!strv_isempty(args) && !have_term) {
1129 log_error("\"+\" can only be used between terms");
1130 return -EINVAL;
1131 }
1132
a963990f
LP
1133 return 0;
1134}
1135
9530e0d0
LP
1136static void boot_id_free_all(BootId *l) {
1137
1138 while (l) {
1139 BootId *i = l;
1140 LIST_REMOVE(boot_list, l, i);
1141 free(i);
1142 }
1143}
1144
dc009662
LP
1145static int discover_next_boot(sd_journal *j,
1146 sd_id128_t previous_boot_id,
1147 bool advance_older,
1148 BootId **ret) {
45bc27b6 1149
45bc27b6 1150 _cleanup_free_ BootId *next_boot = NULL;
dc009662
LP
1151 char match[9+32+1] = "_BOOT_ID=";
1152 sd_id128_t boot_id;
1153 int r;
ea7061e4
JJ
1154
1155 assert(j);
dc009662 1156 assert(ret);
596a2329
JJ
1157
1158 /* We expect the journal to be on the last position of a boot
1159 * (in relation to the direction we are going), so that the next
1160 * invocation of sd_journal_next/previous will be from a different
1161 * boot. We then collect any information we desire and then jump
1162 * to the last location of the new boot by using a _BOOT_ID match
1163 * coming from the other journal direction. */
1164
1165 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1166 * we can actually advance to a *different* boot. */
1167 sd_journal_flush_matches(j);
1168
dc009662
LP
1169 do {
1170 if (advance_older)
1171 r = sd_journal_previous(j);
1172 else
1173 r = sd_journal_next(j);
1174 if (r < 0)
1175 return r;
1176 else if (r == 0)
1177 return 0; /* End of journal, yay. */
1178
1179 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1180 if (r < 0)
1181 return r;
1182
1183 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1184 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
1185 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1186 * complete than the main entry array, and hence might reference an entry that's not actually the last
1187 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1188 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1189 * necessary. */
1190
1191 } while (sd_id128_equal(boot_id, previous_boot_id));
596a2329 1192
45bc27b6 1193 next_boot = new0(BootId, 1);
596a2329 1194 if (!next_boot)
b56d608e 1195 return -ENOMEM;
f1188074 1196
dc009662 1197 next_boot->id = boot_id;
f1188074 1198
d1bf9dc9
LP
1199 r = sd_journal_get_realtime_usec(j, &next_boot->first);
1200 if (r < 0)
1201 return r;
ea7061e4 1202
596a2329
JJ
1203 /* Now seek to the last occurrence of this boot ID. */
1204 sd_id128_to_string(next_boot->id, match + 9);
1205 r = sd_journal_add_match(j, match, sizeof(match) - 1);
1206 if (r < 0)
1207 return r;
f1188074 1208
596a2329
JJ
1209 if (advance_older)
1210 r = sd_journal_seek_head(j);
1211 else
1212 r = sd_journal_seek_tail(j);
1213 if (r < 0)
1214 return r;
f1188074 1215
596a2329
JJ
1216 if (advance_older)
1217 r = sd_journal_next(j);
1218 else
1219 r = sd_journal_previous(j);
1220 if (r < 0)
1221 return r;
202fd896
LP
1222 else if (r == 0) {
1223 log_debug("Whoopsie! We found a boot ID but can't read its last entry.");
596a2329 1224 return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */
202fd896 1225 }
f1188074 1226
d1bf9dc9
LP
1227 r = sd_journal_get_realtime_usec(j, &next_boot->last);
1228 if (r < 0)
1229 return r;
596a2329 1230
1cc6c93a 1231 *ret = TAKE_PTR(next_boot);
9530e0d0 1232
596a2329
JJ
1233 return 0;
1234}
1235
45bc27b6
LP
1236static int get_boots(
1237 sd_journal *j,
1238 BootId **boots,
07ff6b08
ZJS
1239 sd_id128_t *boot_id,
1240 int offset) {
45bc27b6 1241
596a2329
JJ
1242 bool skip_once;
1243 int r, count = 0;
ec02a6c9 1244 BootId *head = NULL, *tail = NULL, *id;
07ff6b08 1245 const bool advance_older = boot_id && offset <= 0;
dc009662 1246 sd_id128_t previous_boot_id;
596a2329
JJ
1247
1248 assert(j);
f1188074 1249
596a2329
JJ
1250 /* Adjust for the asymmetry that offset 0 is
1251 * the last (and current) boot, while 1 is considered the
1252 * (chronological) first boot in the journal. */
592855c3 1253 skip_once = boot_id && sd_id128_is_null(*boot_id) && offset <= 0;
596a2329
JJ
1254
1255 /* Advance to the earliest/latest occurrence of our reference
1256 * boot ID (taking our lookup direction into account), so that
1257 * discover_next_boot() can do its job.
1258 * If no reference is given, the journal head/tail will do,
1259 * they're "virtual" boots after all. */
07ff6b08 1260 if (boot_id && !sd_id128_is_null(*boot_id)) {
596a2329
JJ
1261 char match[9+32+1] = "_BOOT_ID=";
1262
1263 sd_journal_flush_matches(j);
1264
07ff6b08 1265 sd_id128_to_string(*boot_id, match + 9);
596a2329 1266 r = sd_journal_add_match(j, match, sizeof(match) - 1);
f1188074
ZJS
1267 if (r < 0)
1268 return r;
1269
596a2329 1270 if (advance_older)
c4fbc6b6 1271 r = sd_journal_seek_head(j); /* seek to oldest */
596a2329 1272 else
c4fbc6b6 1273 r = sd_journal_seek_tail(j); /* seek to newest */
f1188074
ZJS
1274 if (r < 0)
1275 return r;
1276
596a2329 1277 if (advance_older)
c4fbc6b6 1278 r = sd_journal_next(j); /* read the oldest entry */
596a2329 1279 else
c4fbc6b6 1280 r = sd_journal_previous(j); /* read the most recently added entry */
f1188074
ZJS
1281 if (r < 0)
1282 return r;
1283 else if (r == 0)
596a2329 1284 goto finish;
07ff6b08 1285 else if (offset == 0) {
596a2329
JJ
1286 count = 1;
1287 goto finish;
1288 }
c4fbc6b6
LP
1289
1290 /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
1291 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
1292 * the following entry, which must then have an older/newer boot ID */
596a2329 1293 } else {
c4fbc6b6 1294
596a2329 1295 if (advance_older)
c4fbc6b6 1296 r = sd_journal_seek_tail(j); /* seek to newest */
596a2329 1297 else
c4fbc6b6 1298 r = sd_journal_seek_head(j); /* seek to oldest */
f1188074
ZJS
1299 if (r < 0)
1300 return r;
1301
c4fbc6b6
LP
1302 /* No sd_journal_next()/_previous() here.
1303 *
1304 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
1305 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
1306 * entry we have. */
596a2329 1307 }
f1188074 1308
dc009662 1309 previous_boot_id = SD_ID128_NULL;
45bc27b6
LP
1310 for (;;) {
1311 _cleanup_free_ BootId *current = NULL;
f1188074 1312
dc009662 1313 r = discover_next_boot(j, previous_boot_id, advance_older, &current);
596a2329 1314 if (r < 0) {
9530e0d0 1315 boot_id_free_all(head);
596a2329 1316 return r;
ea7061e4 1317 }
f1188074 1318
596a2329
JJ
1319 if (!current)
1320 break;
1321
dc009662
LP
1322 previous_boot_id = current->id;
1323
07ff6b08 1324 if (boot_id) {
596a2329 1325 if (!skip_once)
07ff6b08 1326 offset += advance_older ? 1 : -1;
596a2329
JJ
1327 skip_once = false;
1328
07ff6b08 1329 if (offset == 0) {
596a2329 1330 count = 1;
07ff6b08 1331 *boot_id = current->id;
596a2329
JJ
1332 break;
1333 }
1334 } else {
ec02a6c9
HK
1335 LIST_FOREACH(boot_list, id, head) {
1336 if (sd_id128_equal(id->id, current->id)) {
1337 /* boot id already stored, something wrong with the journal files */
1338 /* exiting as otherwise this problem would cause forever loop */
1339 goto finish;
1340 }
1341 }
596a2329 1342 LIST_INSERT_AFTER(boot_list, head, tail, current);
1cc6c93a 1343 tail = TAKE_PTR(current);
596a2329
JJ
1344 count++;
1345 }
f1188074
ZJS
1346 }
1347
596a2329
JJ
1348finish:
1349 if (boots)
1350 *boots = head;
1351
1352 sd_journal_flush_matches(j);
1353
1354 return count;
ea7061e4
JJ
1355}
1356
1357static int list_boots(sd_journal *j) {
596a2329 1358 int w, i, count;
9530e0d0 1359 BootId *id, *all_ids;
ea7061e4
JJ
1360
1361 assert(j);
1362
596a2329 1363 count = get_boots(j, &all_ids, NULL, 0);
b56d608e
LP
1364 if (count < 0)
1365 return log_error_errno(count, "Failed to determine boots: %m");
1366 if (count == 0)
596a2329 1367 return count;
ea7061e4 1368
ee5324aa 1369 (void) pager_open(arg_no_pager, arg_pager_end);
f1188074
ZJS
1370
1371 /* numbers are one less, but we need an extra char for the sign */
1372 w = DECIMAL_STR_WIDTH(count - 1) + 1;
1373
596a2329 1374 i = 0;
9530e0d0 1375 LIST_FOREACH(boot_list, id, all_ids) {
f1188074
ZJS
1376 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
1377
1378 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
1379 w, i - count + 1,
1380 SD_ID128_FORMAT_VAL(id->id),
5ab99e07
LP
1381 format_timestamp_maybe_utc(a, sizeof(a), id->first),
1382 format_timestamp_maybe_utc(b, sizeof(b), id->last));
596a2329 1383 i++;
d121b396 1384 }
a963990f 1385
9530e0d0
LP
1386 boot_id_free_all(all_ids);
1387
a331b5e6
JJ
1388 return 0;
1389}
1390
1391static int add_boot(sd_journal *j) {
1392 char match[9+32+1] = "_BOOT_ID=";
07ff6b08 1393 sd_id128_t boot_id;
442e2def 1394 int r;
a331b5e6
JJ
1395
1396 assert(j);
1397
d121b396 1398 if (!arg_boot)
a331b5e6
JJ
1399 return 0;
1400
592855c3
ZJS
1401 /* Take a shortcut and use the current boot_id, which we can do very quickly.
1402 * We can do this only when we logs are coming from the current machine,
1403 * so take the slow path if log location is specified. */
3bbaff3e 1404 if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) &&
0a175093 1405 !arg_directory && !arg_file && !arg_root)
592855c3 1406
b6741478 1407 return add_match_this_boot(j, arg_machine);
a331b5e6 1408
07ff6b08
ZJS
1409 boot_id = arg_boot_id;
1410 r = get_boots(j, NULL, &boot_id, arg_boot_offset);
596a2329
JJ
1411 assert(r <= 1);
1412 if (r <= 0) {
1413 const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r);
1414
1415 if (sd_id128_is_null(arg_boot_id))
c34e9399
JS
1416 log_error("Data from the specified boot (%+i) is not available: %s",
1417 arg_boot_offset, reason);
d121b396 1418 else
c34e9399
JS
1419 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s",
1420 SD_ID128_FORMAT_VAL(arg_boot_id), reason);
596a2329
JJ
1421
1422 return r == 0 ? -ENODATA : r;
a331b5e6
JJ
1423 }
1424
07ff6b08 1425 sd_id128_to_string(boot_id, match + 9);
d121b396
ZJS
1426
1427 r = sd_journal_add_match(j, match, sizeof(match) - 1);
23bbb0de
MS
1428 if (r < 0)
1429 return log_error_errno(r, "Failed to add match: %m");
a331b5e6
JJ
1430
1431 r = sd_journal_add_conjunction(j);
1432 if (r < 0)
b56d608e 1433 return log_error_errno(r, "Failed to add conjunction: %m");
a331b5e6
JJ
1434
1435 return 0;
a963990f
LP
1436}
1437
99271804
ZJS
1438static int add_dmesg(sd_journal *j) {
1439 int r;
1440 assert(j);
1441
1442 if (!arg_dmesg)
1443 return 0;
1444
fbd0b64f
LP
1445 r = sd_journal_add_match(j, "_TRANSPORT=kernel",
1446 STRLEN("_TRANSPORT=kernel"));
23bbb0de
MS
1447 if (r < 0)
1448 return log_error_errno(r, "Failed to add match: %m");
99271804
ZJS
1449
1450 r = sd_journal_add_conjunction(j);
1451 if (r < 0)
b56d608e 1452 return log_error_errno(r, "Failed to add conjunction: %m");
99271804
ZJS
1453
1454 return 0;
1455}
1456
b56d608e
LP
1457static int get_possible_units(
1458 sd_journal *j,
1459 const char *fields,
1460 char **patterns,
1461 Set **units) {
1462
ea18a4b5
ZJS
1463 _cleanup_set_free_free_ Set *found;
1464 const char *field;
c3f60ec5 1465 int r;
ea18a4b5 1466
d5099efc 1467 found = set_new(&string_hash_ops);
ea18a4b5 1468 if (!found)
b56d608e 1469 return -ENOMEM;
ea18a4b5
ZJS
1470
1471 NULSTR_FOREACH(field, fields) {
1472 const void *data;
1473 size_t size;
1474
1475 r = sd_journal_query_unique(j, field);
1476 if (r < 0)
1477 return r;
1478
1479 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1480 char **pattern, *eq;
1481 size_t prefix;
1482 _cleanup_free_ char *u = NULL;
1483
1484 eq = memchr(data, '=', size);
1485 if (eq)
1486 prefix = eq - (char*) data + 1;
1487 else
1488 prefix = 0;
1489
1490 u = strndup((char*) data + prefix, size - prefix);
1491 if (!u)
b56d608e 1492 return -ENOMEM;
ea18a4b5
ZJS
1493
1494 STRV_FOREACH(pattern, patterns)
1495 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1496 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1497
1498 r = set_consume(found, u);
1499 u = NULL;
1500 if (r < 0 && r != -EEXIST)
1501 return r;
1502
1503 break;
1504 }
1505 }
1506 }
1507
1cc6c93a
YW
1508 *units = TAKE_PTR(found);
1509
ea18a4b5
ZJS
1510 return 0;
1511}
1512
1513/* This list is supposed to return the superset of unit names
1514 * possibly matched by rules added with add_matches_for_unit... */
1515#define SYSTEM_UNITS \
1516 "_SYSTEMD_UNIT\0" \
1517 "COREDUMP_UNIT\0" \
1518 "UNIT\0" \
1519 "OBJECT_SYSTEMD_UNIT\0" \
1520 "_SYSTEMD_SLICE\0"
1521
1522/* ... and add_matches_for_user_unit */
1523#define USER_UNITS \
1524 "_SYSTEMD_USER_UNIT\0" \
1525 "USER_UNIT\0" \
1526 "COREDUMP_USER_UNIT\0" \
1527 "OBJECT_SYSTEMD_USER_UNIT\0"
1528
1529static int add_units(sd_journal *j) {
1530 _cleanup_strv_free_ char **patterns = NULL;
1531 int r, count = 0;
b9e40524 1532 char **i;
c3f60ec5
LP
1533
1534 assert(j);
1535
b9e40524 1536 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1537 _cleanup_free_ char *u = NULL;
1538
37cbc1d5 1539 r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN), &u);
7410616c
LP
1540 if (r < 0)
1541 return r;
ea18a4b5
ZJS
1542
1543 if (string_is_glob(u)) {
1544 r = strv_push(&patterns, u);
1545 if (r < 0)
1546 return r;
1547 u = NULL;
1548 } else {
1549 r = add_matches_for_unit(j, u);
1550 if (r < 0)
1551 return r;
1552 r = sd_journal_add_disjunction(j);
1553 if (r < 0)
1554 return r;
313cefa1 1555 count++;
ea18a4b5
ZJS
1556 }
1557 }
1558
1559 if (!strv_isempty(patterns)) {
1560 _cleanup_set_free_free_ Set *units = NULL;
1561 Iterator it;
1562 char *u;
1563
1564 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1565 if (r < 0)
1566 return r;
ea18a4b5
ZJS
1567
1568 SET_FOREACH(u, units, it) {
1569 r = add_matches_for_unit(j, u);
1570 if (r < 0)
1571 return r;
1572 r = sd_journal_add_disjunction(j);
1573 if (r < 0)
1574 return r;
313cefa1 1575 count++;
ea18a4b5 1576 }
b9e40524 1577 }
c3f60ec5 1578
97b11eed 1579 patterns = strv_free(patterns);
ea18a4b5 1580
b9e40524 1581 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1582 _cleanup_free_ char *u = NULL;
1583
37cbc1d5 1584 r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN), &u);
7410616c
LP
1585 if (r < 0)
1586 return r;
c3f60ec5 1587
ea18a4b5
ZJS
1588 if (string_is_glob(u)) {
1589 r = strv_push(&patterns, u);
1590 if (r < 0)
1591 return r;
1592 u = NULL;
1593 } else {
1594 r = add_matches_for_user_unit(j, u, getuid());
1595 if (r < 0)
1596 return r;
1597 r = sd_journal_add_disjunction(j);
1598 if (r < 0)
1599 return r;
313cefa1 1600 count++;
ea18a4b5
ZJS
1601 }
1602 }
1603
1604 if (!strv_isempty(patterns)) {
1605 _cleanup_set_free_free_ Set *units = NULL;
1606 Iterator it;
1607 char *u;
b9e40524 1608
ea18a4b5 1609 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1610 if (r < 0)
1611 return r;
1612
ea18a4b5
ZJS
1613 SET_FOREACH(u, units, it) {
1614 r = add_matches_for_user_unit(j, u, getuid());
1615 if (r < 0)
1616 return r;
1617 r = sd_journal_add_disjunction(j);
1618 if (r < 0)
1619 return r;
313cefa1 1620 count++;
ea18a4b5 1621 }
b9e40524 1622 }
c3f60ec5 1623
ea18a4b5
ZJS
1624 /* Complain if the user request matches but nothing whatsoever was
1625 * found, since otherwise everything would be matched. */
1626 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1627 return -ENODATA;
1628
cd34b3c6
HH
1629 r = sd_journal_add_conjunction(j);
1630 if (r < 0)
1631 return r;
1632
c3f60ec5
LP
1633 return 0;
1634}
1635
941e990d
LP
1636static int add_priorities(sd_journal *j) {
1637 char match[] = "PRIORITY=0";
1638 int i, r;
941e990d
LP
1639 assert(j);
1640
1641 if (arg_priorities == 0xFF)
1642 return 0;
1643
1644 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1645 if (arg_priorities & (1 << i)) {
1646 match[sizeof(match)-2] = '0' + i;
1647
941e990d 1648 r = sd_journal_add_match(j, match, strlen(match));
23bbb0de
MS
1649 if (r < 0)
1650 return log_error_errno(r, "Failed to add match: %m");
941e990d
LP
1651 }
1652
cd34b3c6
HH
1653 r = sd_journal_add_conjunction(j);
1654 if (r < 0)
b56d608e 1655 return log_error_errno(r, "Failed to add conjunction: %m");
cd34b3c6 1656
941e990d
LP
1657 return 0;
1658}
1659
73083640
HH
1660
1661static int add_syslog_identifier(sd_journal *j) {
1662 int r;
1663 char **i;
1664
1665 assert(j);
1666
1667 STRV_FOREACH(i, arg_syslog_identifier) {
1668 char *u;
1669
63c372cb 1670 u = strjoina("SYSLOG_IDENTIFIER=", *i);
73083640
HH
1671 r = sd_journal_add_match(j, u, 0);
1672 if (r < 0)
1673 return r;
1674 r = sd_journal_add_disjunction(j);
1675 if (r < 0)
1676 return r;
1677 }
1678
1679 r = sd_journal_add_conjunction(j);
1680 if (r < 0)
1681 return r;
1682
1683 return 0;
1684}
1685
7560fffc 1686static int setup_keys(void) {
349cc4a5 1687#if HAVE_GCRYPT
7560fffc
LP
1688 size_t mpk_size, seed_size, state_size, i;
1689 uint8_t *mpk, *seed, *state;
11689d2a 1690 int fd = -1, r;
7560fffc
LP
1691 sd_id128_t machine, boot;
1692 char *p = NULL, *k = NULL;
baed47c3 1693 struct FSSHeader h;
14d10188 1694 uint64_t n;
b98e3866
SL
1695 struct stat st;
1696
1697 r = stat("/var/log/journal", &st);
4c701096 1698 if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR))
4a62c710 1699 return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
b98e3866
SL
1700
1701 if (r < 0 || !S_ISDIR(st.st_mode)) {
1702 log_error("%s is not a directory, must be using persistent logging for FSS.",
1703 "/var/log/journal");
1704 return r < 0 ? -errno : -ENOTDIR;
1705 }
7560fffc
LP
1706
1707 r = sd_id128_get_machine(&machine);
23bbb0de
MS
1708 if (r < 0)
1709 return log_error_errno(r, "Failed to get machine ID: %m");
7560fffc
LP
1710
1711 r = sd_id128_get_boot(&boot);
23bbb0de
MS
1712 if (r < 0)
1713 return log_error_errno(r, "Failed to get boot ID: %m");
7560fffc 1714
baed47c3 1715 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1716 SD_ID128_FORMAT_VAL(machine)) < 0)
1717 return log_oom();
1718
faf9da01
ZJS
1719 if (arg_force) {
1720 r = unlink(p);
1721 if (r < 0 && errno != ENOENT) {
1722 r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
b8547c10
SL
1723 goto finish;
1724 }
faf9da01
ZJS
1725 } else if (access(p, F_OK) >= 0) {
1726 log_error("Sealing key file %s exists already. Use --force to recreate.", p);
1727 r = -EEXIST;
1728 goto finish;
7560fffc
LP
1729 }
1730
baed47c3 1731 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1732 SD_ID128_FORMAT_VAL(machine)) < 0) {
1733 r = log_oom();
1734 goto finish;
1735 }
1736
1737 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1738 mpk = alloca(mpk_size);
1739
1740 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1741 seed = alloca(seed_size);
1742
1743 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1744 state = alloca(state_size);
1745
1746 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1747 if (fd < 0) {
76ef789d 1748 r = log_error_errno(errno, "Failed to open /dev/random: %m");
7560fffc
LP
1749 goto finish;
1750 }
1751
1752 log_info("Generating seed...");
a6dcc7e5
ZJS
1753 r = loop_read_exact(fd, seed, seed_size, true);
1754 if (r < 0) {
1755 log_error_errno(r, "Failed to read random seed: %m");
7560fffc
LP
1756 goto finish;
1757 }
1758
1759 log_info("Generating key pair...");
1760 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1761
baed47c3 1762 log_info("Generating sealing key...");
7560fffc
LP
1763 FSPRG_GenState0(state, mpk, seed, seed_size);
1764
baed47c3
LP
1765 assert(arg_interval > 0);
1766
7560fffc 1767 n = now(CLOCK_REALTIME);
baed47c3 1768 n /= arg_interval;
7560fffc 1769
03e334a1 1770 safe_close(fd);
646853bd 1771 fd = mkostemp_safe(k);
7560fffc 1772 if (fd < 0) {
709f6e46 1773 r = log_error_errno(fd, "Failed to open %s: %m", k);
7560fffc
LP
1774 goto finish;
1775 }
1776
f982e6f7
LP
1777 /* Enable secure remove, exclusion from dump, synchronous
1778 * writing and in-place updating */
1ed8f8c1 1779 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 1780 if (r < 0)
709f6e46 1781 log_warning_errno(r, "Failed to set file attributes: %m");
f982e6f7 1782
7560fffc
LP
1783 zero(h);
1784 memcpy(h.signature, "KSHHRHLP", 8);
1785 h.machine_id = machine;
1786 h.boot_id = boot;
1787 h.header_size = htole64(sizeof(h));
baed47c3
LP
1788 h.start_usec = htole64(n * arg_interval);
1789 h.interval_usec = htole64(arg_interval);
1790 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1791 h.fsprg_state_size = htole64(state_size);
7560fffc 1792
553acb7b
ZJS
1793 r = loop_write(fd, &h, sizeof(h), false);
1794 if (r < 0) {
1795 log_error_errno(r, "Failed to write header: %m");
7560fffc
LP
1796 goto finish;
1797 }
1798
553acb7b
ZJS
1799 r = loop_write(fd, state, state_size, false);
1800 if (r < 0) {
1801 log_error_errno(r, "Failed to write state: %m");
7560fffc
LP
1802 goto finish;
1803 }
1804
1805 if (link(k, p) < 0) {
76ef789d 1806 r = log_error_errno(errno, "Failed to link file: %m");
7560fffc
LP
1807 goto finish;
1808 }
1809
8481248b 1810 if (on_tty()) {
7560fffc
LP
1811 fprintf(stderr,
1812 "\n"
54f8c958 1813 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
c05276f2
LP
1814 "the following local file. This key file is automatically updated when the\n"
1815 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1816 "\n"
1817 "\t%s\n"
1818 "\n"
54f8c958 1819 "Please write down the following %ssecret verification key%s. It should be stored\n"
baed47c3 1820 "at a safe location and should not be saved locally on disk.\n"
54f8c958
LP
1821 "\n\t%s",
1822 ansi_highlight(), ansi_normal(),
9ea78383 1823 p,
54f8c958 1824 ansi_highlight(), ansi_normal(),
9ea78383 1825 ansi_highlight_red());
7560fffc
LP
1826 fflush(stderr);
1827 }
1828 for (i = 0; i < seed_size; i++) {
1829 if (i > 0 && i % 3 == 0)
1830 putchar('-');
1831 printf("%02x", ((uint8_t*) seed)[i]);
1832 }
1833
baed47c3
LP
1834 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1835
8481248b 1836 if (on_tty()) {
f6a971bc 1837 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1838
baed47c3 1839 fprintf(stderr,
54f8c958 1840 "%s\n"
baed47c3 1841 "The sealing key is automatically changed every %s.\n",
54f8c958 1842 ansi_normal(),
2fa4092c 1843 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1844
1845 hn = gethostname_malloc();
1846
1847 if (hn) {
ae691c1d 1848 hostname_cleanup(hn);
adac1c93 1849 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1850 } else
adac1c93 1851 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc 1852
349cc4a5 1853#if HAVE_QRENCODE
cf5a3432 1854 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1855 if (is_locale_utf8()) {
cf5a3432
LP
1856 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1857 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1858 }
f6a971bc
LP
1859#endif
1860 free(hn);
baed47c3 1861 }
7560fffc
LP
1862
1863 r = 0;
1864
1865finish:
03e334a1 1866 safe_close(fd);
7560fffc
LP
1867
1868 if (k) {
1869 unlink(k);
1870 free(k);
1871 }
1872
1873 free(p);
1874
1875 return r;
1876#else
feb12d3e 1877 log_error("Forward-secure sealing not available.");
15411c0c 1878 return -EOPNOTSUPP;
7560fffc
LP
1879#endif
1880}
1881
beec0085
LP
1882static int verify(sd_journal *j) {
1883 int r = 0;
1884 Iterator i;
1885 JournalFile *f;
1886
1887 assert(j);
1888
cedb42bb
LP
1889 log_show_color(true);
1890
c1f906bd 1891 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
beec0085 1892 int k;
a7f7d1bd 1893 usec_t first = 0, validated = 0, last = 0;
beec0085 1894
349cc4a5 1895#if HAVE_GCRYPT
feb12d3e 1896 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1897 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1898#endif
4da416aa 1899
2a7b539a 1900 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1901 if (k == -EINVAL) {
baed47c3 1902 /* If the key was invalid give up right-away. */
56e81f7c
LP
1903 return k;
1904 } else if (k < 0) {
e53fc357 1905 log_warning_errno(k, "FAIL: %s (%m)", f->path);
56e81f7c 1906 r = k;
6c7be122
LP
1907 } else {
1908 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1909 log_info("PASS: %s", f->path);
6c7be122 1910
c0ca7aee 1911 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1912 if (validated > 0) {
c0ca7aee 1913 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1914 format_timestamp_maybe_utc(a, sizeof(a), first),
1915 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1916 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1917 } else if (last > 0)
c0ca7aee 1918 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1919 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1920 else
1921 log_info("=> No sealing yet, no entries in file.");
1922 }
6c7be122 1923 }
beec0085
LP
1924 }
1925
1926 return r;
1927}
1928
74055aa7 1929static int flush_to_var(void) {
4afd3348
LP
1930 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1931 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
74055aa7
LP
1932 _cleanup_close_ int watch_fd = -1;
1933 int r;
1934
176ee07b
LP
1935 if (arg_machine) {
1936 log_error("--flush is not supported in conjunction with --machine=.");
1937 return -EOPNOTSUPP;
1938 }
1939
74055aa7
LP
1940 /* Quick exit */
1941 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1942 return 0;
1943
1944 /* OK, let's actually do the full logic, send SIGUSR1 to the
1945 * daemon and set up inotify to wait for the flushed file to appear */
266f3e26 1946 r = bus_connect_system_systemd(&bus);
23bbb0de
MS
1947 if (r < 0)
1948 return log_error_errno(r, "Failed to get D-Bus connection: %m");
74055aa7
LP
1949
1950 r = sd_bus_call_method(
1951 bus,
1952 "org.freedesktop.systemd1",
1953 "/org/freedesktop/systemd1",
1954 "org.freedesktop.systemd1.Manager",
1955 "KillUnit",
1956 &error,
1957 NULL,
1958 "ssi", "systemd-journald.service", "main", SIGUSR1);
94b65516
LP
1959 if (r < 0)
1960 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
74055aa7
LP
1961
1962 mkdir_p("/run/systemd/journal", 0755);
1963
1964 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
4a62c710
MS
1965 if (watch_fd < 0)
1966 return log_error_errno(errno, "Failed to create inotify watch: %m");
74055aa7
LP
1967
1968 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
4a62c710
MS
1969 if (r < 0)
1970 return log_error_errno(errno, "Failed to watch journal directory: %m");
74055aa7
LP
1971
1972 for (;;) {
1973 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1974 break;
1975
4a62c710 1976 if (errno != ENOENT)
f131770b 1977 return log_error_errno(errno, "Failed to check for existence of /run/systemd/journal/flushed: %m");
74055aa7
LP
1978
1979 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
23bbb0de
MS
1980 if (r < 0)
1981 return log_error_errno(r, "Failed to wait for event: %m");
74055aa7
LP
1982
1983 r = flush_fd(watch_fd);
23bbb0de
MS
1984 if (r < 0)
1985 return log_error_errno(r, "Failed to flush inotify events: %m");
74055aa7
LP
1986 }
1987
1988 return 0;
1989}
1990
dbd6e31c 1991static int send_signal_and_wait(int sig, const char *watch_path) {
4afd3348 1992 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
94b65516
LP
1993 _cleanup_close_ int watch_fd = -1;
1994 usec_t start;
1995 int r;
1996
176ee07b
LP
1997 if (arg_machine) {
1998 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
1999 return -EOPNOTSUPP;
2000 }
2001
33d52ab9 2002 start = now(CLOCK_MONOTONIC);
94b65516 2003
dbd6e31c
LP
2004 /* This call sends the specified signal to journald, and waits
2005 * for acknowledgment by watching the mtime of the specified
2006 * flag file. This is used to trigger syncing or rotation and
2007 * then wait for the operation to complete. */
94b65516
LP
2008
2009 for (;;) {
33d52ab9 2010 usec_t tstamp;
94b65516
LP
2011
2012 /* See if a sync happened by now. */
33d52ab9
LP
2013 r = read_timestamp_file(watch_path, &tstamp);
2014 if (r < 0 && r != -ENOENT)
2015 return log_error_errno(errno, "Failed to read %s: %m", watch_path);
2016 if (r >= 0 && tstamp >= start)
2017 return 0;
94b65516
LP
2018
2019 /* Let's ask for a sync, but only once. */
2020 if (!bus) {
4afd3348 2021 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
94b65516
LP
2022
2023 r = bus_connect_system_systemd(&bus);
2024 if (r < 0)
2025 return log_error_errno(r, "Failed to get D-Bus connection: %m");
2026
2027 r = sd_bus_call_method(
2028 bus,
2029 "org.freedesktop.systemd1",
2030 "/org/freedesktop/systemd1",
2031 "org.freedesktop.systemd1.Manager",
2032 "KillUnit",
2033 &error,
2034 NULL,
dbd6e31c 2035 "ssi", "systemd-journald.service", "main", sig);
94b65516
LP
2036 if (r < 0)
2037 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
2038
2039 continue;
2040 }
2041
2042 /* Let's install the inotify watch, if we didn't do that yet. */
2043 if (watch_fd < 0) {
2044
2045 mkdir_p("/run/systemd/journal", 0755);
2046
2047 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
2048 if (watch_fd < 0)
2049 return log_error_errno(errno, "Failed to create inotify watch: %m");
2050
33d52ab9 2051 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR);
94b65516
LP
2052 if (r < 0)
2053 return log_error_errno(errno, "Failed to watch journal directory: %m");
2054
2055 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
2056 continue;
2057 }
2058
2059 /* OK, all preparatory steps done, let's wait until
2060 * inotify reports an event. */
2061
2062 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
2063 if (r < 0)
2064 return log_error_errno(r, "Failed to wait for event: %m");
2065
2066 r = flush_fd(watch_fd);
2067 if (r < 0)
2068 return log_error_errno(r, "Failed to flush inotify events: %m");
2069 }
2070
2071 return 0;
2072}
2073
dbd6e31c
LP
2074static int rotate(void) {
2075 return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated");
2076}
2077
2078static int sync_journal(void) {
2079 return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced");
2080}
2081
a963990f
LP
2082int main(int argc, char *argv[]) {
2083 int r;
4afd3348 2084 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
a963990f 2085 bool need_seek = false;
14a65d65 2086 sd_id128_t previous_boot_id;
67e04a48
ZJS
2087 bool previous_boot_id_valid = false, first_line = true;
2088 int n_shown = 0;
94e0bd7d 2089 bool ellipsized = false;
a963990f 2090
a9cdc94f 2091 setlocale(LC_ALL, "");
a963990f
LP
2092 log_parse_environment();
2093 log_open();
2094
2095 r = parse_argv(argc, argv);
2096 if (r <= 0)
2097 goto finish;
2098
ed757c0c 2099 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 2100 sigbus_install();
ed757c0c 2101
de45d726
LP
2102 /* Increase max number of open files to 16K if we can, we
2103 * might needs this when browsing journal files, which might
2104 * be split up into many files. */
2105 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
2106
a020b3b3 2107 switch (arg_action) {
94b65516 2108
a020b3b3
LP
2109 case ACTION_NEW_ID128:
2110 r = generate_new_id128();
e3fdfb49 2111 goto finish;
e3fdfb49 2112
a020b3b3 2113 case ACTION_SETUP_KEYS:
7560fffc
LP
2114 r = setup_keys();
2115 goto finish;
844ec79b 2116
a020b3b3
LP
2117 case ACTION_LIST_CATALOG:
2118 case ACTION_DUMP_CATALOG:
2119 case ACTION_UPDATE_CATALOG: {
0c6ea3a4
ZJS
2120 _cleanup_free_ char *database;
2121
2122 database = path_join(arg_root, CATALOG_DATABASE, NULL);
2123 if (!database) {
2124 r = log_oom();
2125 goto finish;
13cbf3a5
ZJS
2126 }
2127
844ec79b 2128 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 2129 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b 2130 if (r < 0)
da927ba9 2131 log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
2132 } else {
2133 bool oneline = arg_action == ACTION_LIST_CATALOG;
2134
ee5324aa 2135 (void) pager_open(arg_no_pager, arg_pager_end);
a020b3b3 2136
844ec79b 2137 if (optind < argc)
a020b3b3 2138 r = catalog_list_items(stdout, database, oneline, argv + optind);
844ec79b 2139 else
13cbf3a5 2140 r = catalog_list(stdout, database, oneline);
844ec79b 2141 if (r < 0)
da927ba9 2142 log_error_errno(r, "Failed to list catalog: %m");
844ec79b 2143 }
d4205751 2144
d4205751
LP
2145 goto finish;
2146 }
2147
a020b3b3
LP
2148 case ACTION_FLUSH:
2149 r = flush_to_var();
2150 goto finish;
2151
2152 case ACTION_SYNC:
2153 r = sync_journal();
2154 goto finish;
2155
2156 case ACTION_ROTATE:
2157 r = rotate();
2158 goto finish;
2159
2160 case ACTION_SHOW:
2161 case ACTION_PRINT_HEADER:
2162 case ACTION_VERIFY:
2163 case ACTION_DISK_USAGE:
2164 case ACTION_LIST_BOOTS:
2165 case ACTION_VACUUM:
69e714f3
LP
2166 case ACTION_LIST_FIELDS:
2167 case ACTION_LIST_FIELD_NAMES:
a020b3b3
LP
2168 /* These ones require access to the journal files, continue below. */
2169 break;
2170
2171 default:
2172 assert_not_reached("Unknown action");
2173 }
2174
a963990f 2175 if (arg_directory)
3f3a438f 2176 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
0a175093
ZJS
2177 else if (arg_root)
2178 r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
5d1ce257
LP
2179 else if (arg_file_stdin) {
2180 int ifd = STDIN_FILENO;
2181 r = sd_journal_open_files_fd(&j, &ifd, 1, 0);
2182 } else if (arg_file)
8d98da3f 2183 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
d38c62cc
LP
2184 else if (arg_machine) {
2185 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2186 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2187 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2188 int fd;
2189
2190 if (geteuid() != 0) {
2191 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2192 * the container, thus we need root privileges to override them. */
2193 log_error("Using the --machine= switch requires root privileges.");
2194 r = -EPERM;
2195 goto finish;
2196 }
2197
2198 r = sd_bus_open_system(&bus);
2199 if (r < 0) {
2200 log_error_errno(r, "Failed to open system bus: %m");
2201 goto finish;
2202 }
2203
2204 r = sd_bus_call_method(
2205 bus,
2206 "org.freedesktop.machine1",
2207 "/org/freedesktop/machine1",
2208 "org.freedesktop.machine1.Manager",
2209 "OpenMachineRootDirectory",
2210 &error,
2211 &reply,
2212 "s", arg_machine);
2213 if (r < 0) {
2214 log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
2215 goto finish;
2216 }
2217
2218 r = sd_bus_message_read(reply, "h", &fd);
2219 if (r < 0) {
2220 bus_log_parse_error(r);
2221 goto finish;
2222 }
2223
2224 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
2225 if (fd < 0) {
2226 r = log_error_errno(errno, "Failed to duplicate file descriptor: %m");
2227 goto finish;
2228 }
2229
2230 r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT);
2231 if (r < 0)
2232 safe_close(fd);
2233 } else
3f3a438f 2234 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 2235 if (r < 0) {
a020b3b3 2236 log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
909dea0c 2237 goto finish;
a963990f
LP
2238 }
2239
e79d0b59
ZJS
2240 r = journal_access_check_and_warn(j, arg_quiet,
2241 !(arg_journal_type == SD_JOURNAL_CURRENT_USER || arg_user_units));
6fe391c5 2242 if (r < 0)
909dea0c 2243 goto finish;
6fe391c5 2244
a020b3b3 2245 switch (arg_action) {
beec0085 2246
a020b3b3
LP
2247 case ACTION_NEW_ID128:
2248 case ACTION_SETUP_KEYS:
2249 case ACTION_LIST_CATALOG:
2250 case ACTION_DUMP_CATALOG:
2251 case ACTION_UPDATE_CATALOG:
2252 case ACTION_FLUSH:
2253 case ACTION_SYNC:
2254 case ACTION_ROTATE:
2255 assert_not_reached("Unexpected action.");
2256
2257 case ACTION_PRINT_HEADER:
dca6219e 2258 journal_print_header(j);
909dea0c
LP
2259 r = 0;
2260 goto finish;
dca6219e 2261
a020b3b3
LP
2262 case ACTION_VERIFY:
2263 r = verify(j);
2264 goto finish;
2265
2266 case ACTION_DISK_USAGE: {
39883f62 2267 uint64_t bytes = 0;
a1a03e30
LP
2268 char sbytes[FORMAT_BYTES_MAX];
2269
2270 r = sd_journal_get_usage(j, &bytes);
2271 if (r < 0)
909dea0c 2272 goto finish;
a1a03e30 2273
8da830bc 2274 printf("Archived and active journals take up %s in the file system.\n",
763c7aa2 2275 format_bytes(sbytes, sizeof(sbytes), bytes));
909dea0c 2276 goto finish;
a1a03e30
LP
2277 }
2278
a020b3b3
LP
2279 case ACTION_LIST_BOOTS:
2280 r = list_boots(j);
2281 goto finish;
2282
2283 case ACTION_VACUUM: {
dbd2a83f
LP
2284 Directory *d;
2285 Iterator i;
2286
2287 HASHMAP_FOREACH(d, j->directories_by_path, i) {
2288 int q;
2289
2290 if (d->is_root)
2291 continue;
2292
e3695e49 2293 q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, !arg_quiet);
dbd2a83f 2294 if (q < 0) {
8580d1f7 2295 log_error_errno(q, "Failed to vacuum %s: %m", d->path);
dbd2a83f
LP
2296 r = q;
2297 }
2298 }
2299
909dea0c 2300 goto finish;
dbd2a83f
LP
2301 }
2302
69e714f3
LP
2303 case ACTION_LIST_FIELD_NAMES: {
2304 const char *field;
2305
2306 SD_JOURNAL_FOREACH_FIELD(j, field) {
2307 printf("%s\n", field);
313cefa1 2308 n_shown++;
69e714f3
LP
2309 }
2310
2311 r = 0;
2312 goto finish;
2313 }
2314
a020b3b3 2315 case ACTION_SHOW:
69e714f3 2316 case ACTION_LIST_FIELDS:
a020b3b3
LP
2317 break;
2318
2319 default:
2320 assert_not_reached("Unknown action");
f1188074
ZJS
2321 }
2322
0f1a9a83
JS
2323 if (arg_boot_offset != 0 &&
2324 sd_journal_has_runtime_files(j) > 0 &&
2325 sd_journal_has_persistent_files(j) == 0) {
493097ee 2326 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
0f1a9a83
JS
2327 r = 0;
2328 goto finish;
2329 }
a331b5e6
JJ
2330 /* add_boot() must be called first!
2331 * It may need to seek the journal to find parent boot IDs. */
2332 r = add_boot(j);
a963990f 2333 if (r < 0)
909dea0c 2334 goto finish;
a963990f 2335
99271804
ZJS
2336 r = add_dmesg(j);
2337 if (r < 0)
909dea0c 2338 goto finish;
99271804 2339
b9e40524 2340 r = add_units(j);
ea18a4b5 2341 if (r < 0) {
da927ba9 2342 log_error_errno(r, "Failed to add filter for units: %m");
909dea0c 2343 goto finish;
ea18a4b5 2344 }
c3f60ec5 2345
73083640
HH
2346 r = add_syslog_identifier(j);
2347 if (r < 0) {
da927ba9 2348 log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
909dea0c 2349 goto finish;
73083640
HH
2350 }
2351
cd34b3c6 2352 r = add_priorities(j);
b56d608e 2353 if (r < 0)
909dea0c 2354 goto finish;
a963990f 2355
cd34b3c6 2356 r = add_matches(j, argv + optind);
b56d608e 2357 if (r < 0)
909dea0c 2358 goto finish;
941e990d 2359
f1d34068 2360 if (DEBUG_LOGGING) {
4ad16808
ZJS
2361 _cleanup_free_ char *filter;
2362
2363 filter = journal_make_match_string(j);
b56d608e
LP
2364 if (!filter)
2365 return log_oom();
2366
4ad16808
ZJS
2367 log_debug("Journal filter: %s", filter);
2368 }
67e04a48 2369
69e714f3 2370 if (arg_action == ACTION_LIST_FIELDS) {
15119c16
LP
2371 const void *data;
2372 size_t size;
2373
69e714f3
LP
2374 assert(arg_field);
2375
21ae4593
ZJS
2376 r = sd_journal_set_data_threshold(j, 0);
2377 if (r < 0) {
b56d608e 2378 log_error_errno(r, "Failed to unset data size threshold: %m");
909dea0c 2379 goto finish;
21ae4593
ZJS
2380 }
2381
15119c16
LP
2382 r = sd_journal_query_unique(j, arg_field);
2383 if (r < 0) {
da927ba9 2384 log_error_errno(r, "Failed to query unique data objects: %m");
909dea0c 2385 goto finish;
15119c16
LP
2386 }
2387
2388 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
2389 const void *eq;
2390
67e04a48 2391 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
2392 break;
2393
15119c16
LP
2394 eq = memchr(data, '=', size);
2395 if (eq)
2396 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
2397 else
2398 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875 2399
313cefa1 2400 n_shown++;
15119c16
LP
2401 }
2402
909dea0c
LP
2403 r = 0;
2404 goto finish;
15119c16
LP
2405 }
2406
8d98da3f
ZJS
2407 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2408 if (arg_follow) {
2409 r = sd_journal_get_fd(j);
5d1ce257
LP
2410 if (r == -EMEDIUMTYPE) {
2411 log_error_errno(r, "The --follow switch is not supported in conjunction with reading from STDIN.");
2412 goto finish;
2413 }
b56d608e
LP
2414 if (r < 0) {
2415 log_error_errno(r, "Failed to get journal fd: %m");
909dea0c 2416 goto finish;
b56d608e 2417 }
8d98da3f
ZJS
2418 }
2419
248fc619 2420 if (arg_cursor || arg_after_cursor) {
eacbb4d3 2421 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
08984293 2422 if (r < 0) {
da927ba9 2423 log_error_errno(r, "Failed to seek to cursor: %m");
909dea0c 2424 goto finish;
08984293 2425 }
909dea0c 2426
d89d6c86 2427 if (!arg_reverse)
248fc619 2428 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
d89d6c86 2429 else
248fc619
ZJS
2430 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
2431
8ee8e536 2432 if (arg_after_cursor && r < 2) {
248fc619 2433 /* We couldn't find the next entry after the cursor. */
8ee8e536
WD
2434 if (arg_follow)
2435 need_seek = true;
2436 else
2437 arg_lines = 0;
2438 }
08984293 2439
d89d6c86 2440 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 2441 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 2442 if (r < 0) {
da927ba9 2443 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2444 goto finish;
8f14c832 2445 }
8f14c832
LP
2446 r = sd_journal_next(j);
2447
d89d6c86
LN
2448 } else if (arg_until_set && arg_reverse) {
2449 r = sd_journal_seek_realtime_usec(j, arg_until);
2450 if (r < 0) {
da927ba9 2451 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2452 goto finish;
d89d6c86
LN
2453 }
2454 r = sd_journal_previous(j);
2455
67e04a48 2456 } else if (arg_lines >= 0) {
2100675e
LP
2457 r = sd_journal_seek_tail(j);
2458 if (r < 0) {
da927ba9 2459 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2460 goto finish;
2100675e
LP
2461 }
2462
2463 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 2464
d89d6c86
LN
2465 } else if (arg_reverse) {
2466 r = sd_journal_seek_tail(j);
2467 if (r < 0) {
da927ba9 2468 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2469 goto finish;
d89d6c86
LN
2470 }
2471
2472 r = sd_journal_previous(j);
2473
2100675e
LP
2474 } else {
2475 r = sd_journal_seek_head(j);
2476 if (r < 0) {
da927ba9 2477 log_error_errno(r, "Failed to seek to head: %m");
909dea0c 2478 goto finish;
2100675e 2479 }
6f003b43
LP
2480
2481 r = sd_journal_next(j);
2482 }
2483
2484 if (r < 0) {
da927ba9 2485 log_error_errno(r, "Failed to iterate through journal: %m");
909dea0c 2486 goto finish;
50f20cfd 2487 }
5f42943c
LK
2488 if (r == 0)
2489 need_seek = true;
87d2c1ff 2490
faf5077f 2491 if (!arg_follow)
ee5324aa 2492 (void) pager_open(arg_no_pager, arg_pager_end);
0d43c694 2493
5f42943c 2494 if (!arg_quiet && (arg_lines != 0 || arg_follow)) {
cfbc22ab
LP
2495 usec_t start, end;
2496 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
2497
2498 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
2499 if (r < 0) {
da927ba9 2500 log_error_errno(r, "Failed to get cutoff: %m");
cfbc22ab
LP
2501 goto finish;
2502 }
2503
2504 if (r > 0) {
2505 if (arg_follow)
9048b11f 2506 printf("-- Logs begin at %s. --\n",
5ab99e07 2507 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2508 else
9048b11f 2509 printf("-- Logs begin at %s, end at %s. --\n",
5ab99e07
LP
2510 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2511 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2512 }
2513 }
2514
50f20cfd 2515 for (;;) {
67e04a48 2516 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab 2517 int flags;
b4766d5f 2518 size_t highlight[2] = {};
cfbc22ab 2519
6f003b43 2520 if (need_seek) {
99613ec5 2521 if (!arg_reverse)
d89d6c86
LN
2522 r = sd_journal_next(j);
2523 else
2524 r = sd_journal_previous(j);
6f003b43 2525 if (r < 0) {
da927ba9 2526 log_error_errno(r, "Failed to iterate through journal: %m");
6f003b43
LP
2527 goto finish;
2528 }
a72b6353
ZJS
2529 if (r == 0)
2530 break;
0d43c694
LP
2531 }
2532
d89d6c86 2533 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
2534 usec_t usec;
2535
2536 r = sd_journal_get_realtime_usec(j, &usec);
2537 if (r < 0) {
da927ba9 2538 log_error_errno(r, "Failed to determine timestamp: %m");
cfbc22ab
LP
2539 goto finish;
2540 }
3ba09ee8
PF
2541 if (usec > arg_until)
2542 goto finish;
cfbc22ab
LP
2543 }
2544
d89d6c86
LN
2545 if (arg_since_set && arg_reverse) {
2546 usec_t usec;
2547
2548 r = sd_journal_get_realtime_usec(j, &usec);
2549 if (r < 0) {
da927ba9 2550 log_error_errno(r, "Failed to determine timestamp: %m");
d89d6c86
LN
2551 goto finish;
2552 }
2553 if (usec < arg_since)
2554 goto finish;
2555 }
2556
4bed2485 2557 if (!arg_merge && !arg_quiet) {
cd931c0a 2558 sd_id128_t boot_id;
14a65d65 2559
cd931c0a
LP
2560 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2561 if (r >= 0) {
2562 if (previous_boot_id_valid &&
2563 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c 2564 printf("%s-- Reboot --%s\n",
1fc464f6 2565 ansi_highlight(), ansi_normal());
cd931c0a
LP
2566
2567 previous_boot_id = boot_id;
2568 previous_boot_id_valid = true;
2569 }
14a65d65
LP
2570 }
2571
6becf48c 2572#if HAVE_PCRE2
61c5f8a1 2573 if (arg_compiled_pattern) {
6becf48c
ZJS
2574 _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL;
2575 const void *message;
2576 size_t len;
b4766d5f 2577 PCRE2_SIZE *ovec;
6becf48c
ZJS
2578
2579 md = pcre2_match_data_create(1, NULL);
2580 if (!md)
2581 return log_oom();
2582
2583 r = sd_journal_get_data(j, "MESSAGE", &message, &len);
2584 if (r < 0) {
2585 if (r == -ENOENT) {
2586 need_seek = true;
2587 continue;
2588 }
2589
2590 log_error_errno(r, "Failed to get MESSAGE field: %m");
2591 goto finish;
2592 }
2593
2594 assert_se(message = startswith(message, "MESSAGE="));
2595
61c5f8a1 2596 r = pcre2_match(arg_compiled_pattern,
6becf48c
ZJS
2597 message,
2598 len - strlen("MESSAGE="),
2599 0, /* start at offset 0 in the subject */
2600 0, /* default options */
2601 md,
2602 NULL);
2603 if (r == PCRE2_ERROR_NOMATCH) {
2604 need_seek = true;
2605 continue;
2606 }
2607 if (r < 0) {
2608 unsigned char buf[LINE_MAX];
2609 int r2;
2610
2611 r2 = pcre2_get_error_message(r, buf, sizeof buf);
2612 log_error("Pattern matching failed: %s",
2613 r2 < 0 ? "unknown error" : (char*) buf);
2614 r = -EINVAL;
2615 goto finish;
2616 }
b4766d5f
ZJS
2617
2618 ovec = pcre2_get_ovector_pointer(md);
2619 highlight[0] = ovec[0];
2620 highlight[1] = ovec[1];
6becf48c
ZJS
2621 }
2622#endif
2623
cfbc22ab 2624 flags =
cd4b13e0 2625 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 2626 arg_full * OUTPUT_FULL_WIDTH |
40c9fe4c 2627 colors_enabled() * OUTPUT_COLOR |
9fd29044 2628 arg_catalog * OUTPUT_CATALOG |
991e274b
LP
2629 arg_utc * OUTPUT_UTC |
2630 arg_no_hostname * OUTPUT_NO_HOSTNAME;
cfbc22ab 2631
b4766d5f
ZJS
2632 r = output_journal(stdout, j, arg_output, 0, flags,
2633 arg_output_fields, highlight, &ellipsized);
a72b6353
ZJS
2634 need_seek = true;
2635 if (r == -EADDRNOTAVAIL)
2636 break;
2637 else if (r < 0 || ferror(stdout))
72f59706 2638 goto finish;
6f003b43 2639
cfbc22ab 2640 n_shown++;
ec316d19
PP
2641
2642 /* If journalctl take a long time to process messages, and during that time journal file
2643 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2644 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2645 * in the "following" case. By periodically calling sd_journal_process() during the processing
2646 * loop we shrink the window of time a client instance has open file descriptors for rotated
2647 * (deleted) journal files. */
2648 if ((n_shown % PROCESS_INOTIFY_INTERVAL) == 0) {
2649 r = sd_journal_process(j);
2650 if (r < 0) {
2651 log_error_errno(r, "Failed to process inotify events: %m");
2652 goto finish;
2653 }
2654 }
87d2c1ff
LP
2655 }
2656
248fc619 2657 if (!arg_follow) {
5f42943c
LK
2658 if (n_shown == 0 && !arg_quiet)
2659 printf("-- No entries --\n");
2660
248fc619
ZJS
2661 if (arg_show_cursor) {
2662 _cleanup_free_ char *cursor = NULL;
2663
2664 r = sd_journal_get_cursor(j, &cursor);
2665 if (r < 0 && r != -EADDRNOTAVAIL)
da927ba9 2666 log_error_errno(r, "Failed to get cursor: %m");
248fc619
ZJS
2667 else if (r >= 0)
2668 printf("-- cursor: %s\n", cursor);
2669 }
2670
50f20cfd 2671 break;
248fc619 2672 }
50f20cfd 2673
b1aa5ced 2674 fflush(stdout);
e02d1cf7 2675 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 2676 if (r < 0) {
da927ba9 2677 log_error_errno(r, "Couldn't wait for journal event: %m");
50f20cfd
LP
2678 goto finish;
2679 }
67e04a48
ZJS
2680
2681 first_line = false;
de190aef 2682 }
87d2c1ff
LP
2683
2684finish:
b1aa5ced 2685 fflush(stdout);
0d43c694
LP
2686 pager_close();
2687
a36b8deb
ZJS
2688 strv_free(arg_file);
2689
d52da205
LP
2690 strv_free(arg_syslog_identifier);
2691 strv_free(arg_system_units);
2692 strv_free(arg_user_units);
cc25a67e 2693 strv_free(arg_output_fields);
d52da205 2694
0f03c2a4 2695 free(arg_root);
6bae9b2a 2696 free(arg_verify_key);
0f03c2a4 2697
6becf48c 2698#if HAVE_PCRE2
61c5f8a1
ZJS
2699 if (arg_compiled_pattern)
2700 pcre2_code_free(arg_compiled_pattern);
6becf48c
ZJS
2701#endif
2702
3fbf9cbb 2703 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2704}