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