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