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