]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
basic: split out inotify-related calls from fs-util.h → inotify-util.h
[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;
0d5765f7 279 } else if (strlen(x) >= SD_ID128_STRING_MAX - 1) {
442e2def
LP
280 char *t;
281
0d5765f7 282 t = strndupa(x, SD_ID128_STRING_MAX - 1);
442e2def
LP
283 r = sd_id128_from_string(t, &id);
284 if (r >= 0)
0d5765f7 285 x += SD_ID128_STRING_MAX - 1;
442e2def 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:
04499a70 1049 assert_not_reached();
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) {
c2b2df60 1161 _cleanup_free_ char *comm = NULL;
68fee104 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;
492f148f 1230 char match[STRLEN("_BOOT_ID=") + SD_ID128_STRING_MAX] = "_BOOT_ID=";
dc009662
LP
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 1282 /* Now seek to the last occurrence of this boot ID. */
0d5765f7 1283 sd_id128_to_string(next_boot->id, match + STRLEN("_BOOT_ID="));
596a2329
JJ
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)) {
492f148f 1339 char match[STRLEN("_BOOT_ID=") + SD_ID128_STRING_MAX] = "_BOOT_ID=";
596a2329
JJ
1340
1341 sd_journal_flush_matches(j);
1342
0d5765f7 1343 sd_id128_to_string(*boot_id, match + STRLEN("_BOOT_ID="));
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) {
492f148f 1470 char match[STRLEN("_BOOT_ID=") + SD_ID128_STRING_MAX] = "_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
0d5765f7 1502 sd_id128_to_string(boot_id, match + STRLEN("_BOOT_ID="));
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
c2b2df60 1540 _cleanup_set_free_free_ Set *found = NULL;
ea18a4b5 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
c1631ee1
LP
1905 r = chattr_secret(fd, CHATTR_WARN_UNSUPPORTED_FLAGS);
1906 if (r < 0)
1907 log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING,
1908 r, "Failed to set file attributes on '%s', ignoring: %m", k);
f982e6f7 1909
41ab8c67 1910 struct FSSHeader h = {
9bff1410 1911 .signature = { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' },
41ab8c67
LP
1912 .machine_id = machine,
1913 .boot_id = boot,
1914 .header_size = htole64(sizeof(h)),
1915 .start_usec = htole64(n * arg_interval),
1916 .interval_usec = htole64(arg_interval),
1917 .fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR),
1918 .fsprg_state_size = htole64(state_size),
1919 };
1920
553acb7b 1921 r = loop_write(fd, &h, sizeof(h), false);
9bff1410
LP
1922 if (r < 0)
1923 return log_error_errno(r, "Failed to write header: %m");
7560fffc 1924
553acb7b 1925 r = loop_write(fd, state, state_size, false);
9bff1410
LP
1926 if (r < 0)
1927 return log_error_errno(r, "Failed to write state: %m");
7560fffc 1928
9bff1410
LP
1929 if (rename(k, p) < 0)
1930 return log_error_errno(errno, "Failed to link file: %m");
1931
1932 k = mfree(k);
7560fffc 1933
f1b82359
ZJS
1934 _cleanup_free_ char *hn = NULL, *key = NULL;
1935
1936 r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, false, &key);
1937 if (r < 0)
1938 return r;
da012db0 1939
8481248b 1940 if (on_tty()) {
da012db0
ZJS
1941 hn = gethostname_malloc();
1942 if (hn)
1943 hostname_cleanup(hn);
1944
7560fffc 1945 fprintf(stderr,
da012db0 1946 "\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR ".\n"
7560fffc 1947 "\n"
da012db0
ZJS
1948 "The %ssecret sealing key%s has been written to the following local file.\n"
1949 "This key file is automatically updated when the sealing key is advanced.\n"
1950 "It should not be used on multiple hosts.\n"
7560fffc
LP
1951 "\n"
1952 "\t%s\n"
1953 "\n"
da012db0
ZJS
1954 "The sealing key is automatically changed every %s.\n"
1955 "\n"
54f8c958 1956 "Please write down the following %ssecret verification key%s. It should be stored\n"
da012db0 1957 "in a safe location and should not be saved locally on disk.\n"
54f8c958 1958 "\n\t%s",
d7a0f1f4
FS
1959 strempty(hn), hn ? "/" : "",
1960 SD_ID128_FORMAT_VAL(machine),
54f8c958 1961 ansi_highlight(), ansi_normal(),
9ea78383 1962 p,
5291f26d 1963 FORMAT_TIMESPAN(arg_interval, 0),
54f8c958 1964 ansi_highlight(), ansi_normal(),
9ea78383 1965 ansi_highlight_red());
7560fffc
LP
1966 fflush(stderr);
1967 }
da012db0 1968
f1b82359 1969 puts(key);
baed47c3 1970
8481248b 1971 if (on_tty()) {
da012db0 1972 fprintf(stderr, "%s", ansi_normal());
349cc4a5 1973#if HAVE_QRENCODE
f1b82359
ZJS
1974 _cleanup_free_ char *url = NULL;
1975 r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, true, &url);
1976 if (r < 0)
1977 return r;
1978
1979 (void) print_qrcode(stderr,
1980 "To transfer the verification key to your phone scan the QR code below",
1981 url);
f6a971bc 1982#endif
baed47c3 1983 }
7560fffc 1984
9bff1410 1985 return 0;
7560fffc 1986#else
baaa35ad
ZJS
1987 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1988 "Forward-secure sealing not available.");
7560fffc
LP
1989#endif
1990}
1991
beec0085
LP
1992static int verify(sd_journal *j) {
1993 int r = 0;
beec0085
LP
1994 JournalFile *f;
1995
1996 assert(j);
1997
cedb42bb
LP
1998 log_show_color(true);
1999
90e74a66 2000 ORDERED_HASHMAP_FOREACH(f, j->files) {
beec0085 2001 int k;
a7f7d1bd 2002 usec_t first = 0, validated = 0, last = 0;
beec0085 2003
349cc4a5 2004#if HAVE_GCRYPT
feb12d3e 2005 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 2006 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 2007#endif
4da416aa 2008
2a7b539a 2009 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
fed66db0 2010 if (k == -EINVAL)
baed47c3 2011 /* If the key was invalid give up right-away. */
56e81f7c 2012 return k;
fed66db0
YW
2013 else if (k < 0)
2014 r = log_warning_errno(k, "FAIL: %s (%m)", f->path);
2015 else {
5291f26d 2016 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
beec0085 2017 log_info("PASS: %s", f->path);
6c7be122 2018
c0ca7aee 2019 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 2020 if (validated > 0) {
c0ca7aee 2021 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
2022 format_timestamp_maybe_utc(a, sizeof(a), first),
2023 format_timestamp_maybe_utc(b, sizeof(b), validated),
5291f26d 2024 FORMAT_TIMESPAN(last > validated ? last - validated : 0, 0));
2a7b539a 2025 } else if (last > 0)
c0ca7aee 2026 log_info("=> No sealing yet, %s of entries not sealed.",
5291f26d 2027 FORMAT_TIMESPAN(last - first, 0));
c0ca7aee
LP
2028 else
2029 log_info("=> No sealing yet, no entries in file.");
2030 }
6c7be122 2031 }
beec0085
LP
2032 }
2033
2034 return r;
2035}
2036
4f413af2
LP
2037static int simple_varlink_call(const char *option, const char *method) {
2038 _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
6b25db87 2039 const char *error, *fn;
74055aa7
LP
2040 int r;
2041
4f413af2
LP
2042 if (arg_machine)
2043 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not supported in conjunction with --machine=.", option);
74055aa7 2044
6b25db87
LP
2045 fn = arg_namespace ?
2046 strjoina("/run/systemd/journal.", arg_namespace, "/io.systemd.journal") :
2047 "/run/systemd/journal/io.systemd.journal";
2048
2049 r = varlink_connect_address(&link, fn);
94b65516 2050 if (r < 0)
6b25db87 2051 return log_error_errno(r, "Failed to connect to %s: %m", fn);
77740b59
ZJS
2052
2053 (void) varlink_set_description(link, "journal");
0bd3c210 2054 (void) varlink_set_relative_timeout(link, USEC_INFINITY);
74055aa7 2055
4f413af2
LP
2056 r = varlink_call(link, method, NULL, NULL, &error, NULL);
2057 if (r < 0)
17087340
YW
2058 return log_error_errno(r, "Failed to execute varlink call: %m");
2059 if (error)
2060 return log_error_errno(SYNTHETIC_ERRNO(ENOANO),
2061 "Failed to execute varlink call: %s", error);
74055aa7 2062
4f413af2 2063 return 0;
74055aa7
LP
2064}
2065
4f413af2 2066static int flush_to_var(void) {
f6fca35e
FB
2067 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
2068 return 0; /* Already flushed, no need to contact journald */
2069 if (errno != ENOENT)
2070 return log_error_errno(errno, "Unable to check for existence of /run/systemd/journal/flushed: %m");
2071
4f413af2 2072 return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
94b65516
LP
2073}
2074
c0dfcb31 2075static int relinquish_var(void) {
f2083c71 2076 return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
c0dfcb31
LP
2077}
2078
dbd6e31c 2079static int rotate(void) {
4f413af2 2080 return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
dbd6e31c
LP
2081}
2082
2083static int sync_journal(void) {
4f413af2 2084 return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
dbd6e31c
LP
2085}
2086
2a1e0f22
LP
2087static int wait_for_change(sd_journal *j, int poll_fd) {
2088 struct pollfd pollfds[] = {
2089 { .fd = poll_fd, .events = POLLIN },
2090 { .fd = STDOUT_FILENO },
2091 };
2a1e0f22 2092 usec_t timeout;
a963990f 2093 int r;
2a1e0f22
LP
2094
2095 assert(j);
2096 assert(poll_fd >= 0);
2097
2098 /* Much like sd_journal_wait() but also keeps an eye on STDOUT, and exits as soon as we see a POLLHUP on that,
2099 * i.e. when it is closed. */
2100
2101 r = sd_journal_get_timeout(j, &timeout);
2102 if (r < 0)
2103 return log_error_errno(r, "Failed to determine journal waiting time: %m");
2104
d9e2af0a
YW
2105 r = ppoll_usec(pollfds, ELEMENTSOF(pollfds), timeout);
2106 if (r == -EINTR)
2107 return 0;
2108 if (r < 0)
2109 return log_error_errno(r, "Couldn't wait for journal event: %m");
2a1e0f22 2110
d9e2af0a 2111 if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */
baaa35ad
ZJS
2112 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED),
2113 "Standard output has been closed.");
2a1e0f22
LP
2114
2115 r = sd_journal_process(j);
2116 if (r < 0)
2117 return log_error_errno(r, "Failed to process journal events: %m");
2118
2119 return 0;
2120}
2121
2122int main(int argc, char *argv[]) {
cc171228
LP
2123 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
2124 _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
2125 _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
2a1e0f22 2126 bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false;
d9e15cbd 2127 bool use_cursor = false, after_cursor = false;
4afd3348 2128 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
14a65d65 2129 sd_id128_t previous_boot_id;
2a1e0f22 2130 int n_shown = 0, r, poll_fd = -1;
a963990f 2131
a9cdc94f 2132 setlocale(LC_ALL, "");
d2acb93d 2133 log_setup();
a963990f 2134
1abaf488
LP
2135 /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
2136 * split up into many files. */
2137 (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
2138
a963990f
LP
2139 r = parse_argv(argc, argv);
2140 if (r <= 0)
2141 goto finish;
2142
cc171228
LP
2143 if (arg_image) {
2144 assert(!arg_root);
2145
2146 r = mount_image_privately_interactively(
2147 arg_image,
4b5de5dd
LP
2148 DISSECT_IMAGE_GENERIC_ROOT |
2149 DISSECT_IMAGE_REQUIRE_ROOT |
2150 DISSECT_IMAGE_VALIDATE_OS |
2151 DISSECT_IMAGE_RELAX_VAR_CHECK |
c65f854a 2152 (arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS : DISSECT_IMAGE_READ_ONLY),
cc171228
LP
2153 &unlink_dir,
2154 &loop_device,
2155 &decrypted_image);
2156 if (r < 0)
2157 return r;
2158
2159 arg_root = strdup(unlink_dir);
2160 if (!arg_root)
2161 return log_oom();
2162 }
2163
ed757c0c 2164 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 2165 sigbus_install();
ed757c0c 2166
a020b3b3 2167 switch (arg_action) {
94b65516 2168
a020b3b3 2169 case ACTION_NEW_ID128:
a19fdd66 2170 r = id128_print_new(ID128_PRINT_PRETTY);
e3fdfb49 2171 goto finish;
e3fdfb49 2172
a020b3b3 2173 case ACTION_SETUP_KEYS:
7560fffc
LP
2174 r = setup_keys();
2175 goto finish;
844ec79b 2176
a020b3b3
LP
2177 case ACTION_LIST_CATALOG:
2178 case ACTION_DUMP_CATALOG:
2179 case ACTION_UPDATE_CATALOG: {
c2b2df60 2180 _cleanup_free_ char *database = NULL;
0c6ea3a4 2181
652ef298 2182 database = path_join(arg_root, CATALOG_DATABASE);
0c6ea3a4
ZJS
2183 if (!database) {
2184 r = log_oom();
2185 goto finish;
13cbf3a5
ZJS
2186 }
2187
844ec79b 2188 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 2189 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b 2190 if (r < 0)
da927ba9 2191 log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
2192 } else {
2193 bool oneline = arg_action == ACTION_LIST_CATALOG;
2194
0221d68a 2195 (void) pager_open(arg_pager_flags);
a020b3b3 2196
844ec79b 2197 if (optind < argc)
a020b3b3 2198 r = catalog_list_items(stdout, database, oneline, argv + optind);
844ec79b 2199 else
13cbf3a5 2200 r = catalog_list(stdout, database, oneline);
844ec79b 2201 if (r < 0)
da927ba9 2202 log_error_errno(r, "Failed to list catalog: %m");
844ec79b 2203 }
d4205751 2204
d4205751
LP
2205 goto finish;
2206 }
2207
a020b3b3
LP
2208 case ACTION_FLUSH:
2209 r = flush_to_var();
2210 goto finish;
2211
c0dfcb31
LP
2212 case ACTION_RELINQUISH_VAR:
2213 r = relinquish_var();
2214 goto finish;
2215
a020b3b3
LP
2216 case ACTION_SYNC:
2217 r = sync_journal();
2218 goto finish;
2219
2220 case ACTION_ROTATE:
2221 r = rotate();
2222 goto finish;
2223
2224 case ACTION_SHOW:
2225 case ACTION_PRINT_HEADER:
2226 case ACTION_VERIFY:
2227 case ACTION_DISK_USAGE:
2228 case ACTION_LIST_BOOTS:
2229 case ACTION_VACUUM:
8df64fd0 2230 case ACTION_ROTATE_AND_VACUUM:
69e714f3
LP
2231 case ACTION_LIST_FIELDS:
2232 case ACTION_LIST_FIELD_NAMES:
a020b3b3
LP
2233 /* These ones require access to the journal files, continue below. */
2234 break;
2235
2236 default:
04499a70 2237 assert_not_reached();
a020b3b3
LP
2238 }
2239
a963990f 2240 if (arg_directory)
3f3a438f 2241 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
0a175093
ZJS
2242 else if (arg_root)
2243 r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
33ff7464
LP
2244 else if (arg_file_stdin)
2245 r = sd_journal_open_files_fd(&j, (int[]) { STDIN_FILENO }, 1, 0);
2246 else if (arg_file)
8d98da3f 2247 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
d38c62cc
LP
2248 else if (arg_machine) {
2249 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2250 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2251 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2252 int fd;
2253
2254 if (geteuid() != 0) {
2255 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2256 * the container, thus we need root privileges to override them. */
0491150b 2257 r = log_error_errno(SYNTHETIC_ERRNO(EPERM), "Using the --machine= switch requires root privileges.");
d38c62cc
LP
2258 goto finish;
2259 }
2260
2261 r = sd_bus_open_system(&bus);
2262 if (r < 0) {
2263 log_error_errno(r, "Failed to open system bus: %m");
2264 goto finish;
2265 }
2266
2267 r = sd_bus_call_method(
2268 bus,
2269 "org.freedesktop.machine1",
2270 "/org/freedesktop/machine1",
2271 "org.freedesktop.machine1.Manager",
2272 "OpenMachineRootDirectory",
2273 &error,
2274 &reply,
2275 "s", arg_machine);
2276 if (r < 0) {
2277 log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
2278 goto finish;
2279 }
2280
2281 r = sd_bus_message_read(reply, "h", &fd);
2282 if (r < 0) {
2283 bus_log_parse_error(r);
2284 goto finish;
2285 }
2286
2287 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
2288 if (fd < 0) {
2289 r = log_error_errno(errno, "Failed to duplicate file descriptor: %m");
2290 goto finish;
2291 }
2292
2293 r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT);
2294 if (r < 0)
2295 safe_close(fd);
2296 } else
6b25db87
LP
2297 r = sd_journal_open_namespace(
2298 &j,
2299 arg_namespace,
2300 (arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY) |
2301 arg_namespace_flags | arg_journal_type);
a963990f 2302 if (r < 0) {
a020b3b3 2303 log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
909dea0c 2304 goto finish;
a963990f
LP
2305 }
2306
e79d0b59
ZJS
2307 r = journal_access_check_and_warn(j, arg_quiet,
2308 !(arg_journal_type == SD_JOURNAL_CURRENT_USER || arg_user_units));
6fe391c5 2309 if (r < 0)
909dea0c 2310 goto finish;
6fe391c5 2311
a020b3b3 2312 switch (arg_action) {
beec0085 2313
a020b3b3
LP
2314 case ACTION_NEW_ID128:
2315 case ACTION_SETUP_KEYS:
2316 case ACTION_LIST_CATALOG:
2317 case ACTION_DUMP_CATALOG:
2318 case ACTION_UPDATE_CATALOG:
2319 case ACTION_FLUSH:
2320 case ACTION_SYNC:
2321 case ACTION_ROTATE:
04499a70 2322 assert_not_reached();
a020b3b3
LP
2323
2324 case ACTION_PRINT_HEADER:
dca6219e 2325 journal_print_header(j);
909dea0c
LP
2326 r = 0;
2327 goto finish;
dca6219e 2328
a020b3b3
LP
2329 case ACTION_VERIFY:
2330 r = verify(j);
2331 goto finish;
2332
2333 case ACTION_DISK_USAGE: {
39883f62 2334 uint64_t bytes = 0;
a1a03e30
LP
2335
2336 r = sd_journal_get_usage(j, &bytes);
2337 if (r < 0)
909dea0c 2338 goto finish;
a1a03e30 2339
8da830bc 2340 printf("Archived and active journals take up %s in the file system.\n",
2b59bf51 2341 FORMAT_BYTES(bytes));
909dea0c 2342 goto finish;
a1a03e30
LP
2343 }
2344
a020b3b3
LP
2345 case ACTION_LIST_BOOTS:
2346 r = list_boots(j);
2347 goto finish;
2348
8df64fd0
LP
2349 case ACTION_ROTATE_AND_VACUUM:
2350
2351 r = rotate();
2352 if (r < 0)
2353 goto finish;
2354
2355 _fallthrough_;
2356
a020b3b3 2357 case ACTION_VACUUM: {
dbd2a83f 2358 Directory *d;
dbd2a83f 2359
90e74a66 2360 HASHMAP_FOREACH(d, j->directories_by_path) {
dbd2a83f
LP
2361 int q;
2362
e3695e49 2363 q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, !arg_quiet);
fed66db0
YW
2364 if (q < 0)
2365 r = log_error_errno(q, "Failed to vacuum %s: %m", d->path);
dbd2a83f
LP
2366 }
2367
909dea0c 2368 goto finish;
dbd2a83f
LP
2369 }
2370
69e714f3
LP
2371 case ACTION_LIST_FIELD_NAMES: {
2372 const char *field;
2373
2374 SD_JOURNAL_FOREACH_FIELD(j, field) {
2375 printf("%s\n", field);
313cefa1 2376 n_shown++;
69e714f3
LP
2377 }
2378
2379 r = 0;
2380 goto finish;
2381 }
2382
a020b3b3 2383 case ACTION_SHOW:
69e714f3 2384 case ACTION_LIST_FIELDS:
a020b3b3
LP
2385 break;
2386
2387 default:
04499a70 2388 assert_not_reached();
f1188074
ZJS
2389 }
2390
0f1a9a83
JS
2391 if (arg_boot_offset != 0 &&
2392 sd_journal_has_runtime_files(j) > 0 &&
2393 sd_journal_has_persistent_files(j) == 0) {
493097ee 2394 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
0f1a9a83
JS
2395 r = 0;
2396 goto finish;
2397 }
a331b5e6
JJ
2398 /* add_boot() must be called first!
2399 * It may need to seek the journal to find parent boot IDs. */
2400 r = add_boot(j);
a963990f 2401 if (r < 0)
909dea0c 2402 goto finish;
a963990f 2403
99271804
ZJS
2404 r = add_dmesg(j);
2405 if (r < 0)
909dea0c 2406 goto finish;
99271804 2407
b9e40524 2408 r = add_units(j);
ea18a4b5 2409 if (r < 0) {
da927ba9 2410 log_error_errno(r, "Failed to add filter for units: %m");
909dea0c 2411 goto finish;
ea18a4b5 2412 }
c3f60ec5 2413
73083640
HH
2414 r = add_syslog_identifier(j);
2415 if (r < 0) {
da927ba9 2416 log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
909dea0c 2417 goto finish;
73083640
HH
2418 }
2419
cd34b3c6 2420 r = add_priorities(j);
b56d608e 2421 if (r < 0)
909dea0c 2422 goto finish;
a963990f 2423
196dedd5
ZJS
2424 r = add_facilities(j);
2425 if (r < 0)
2426 goto finish;
2427
cd34b3c6 2428 r = add_matches(j, argv + optind);
b56d608e 2429 if (r < 0)
909dea0c 2430 goto finish;
941e990d 2431
f1d34068 2432 if (DEBUG_LOGGING) {
c2b2df60 2433 _cleanup_free_ char *filter = NULL;
4ad16808
ZJS
2434
2435 filter = journal_make_match_string(j);
b56d608e
LP
2436 if (!filter)
2437 return log_oom();
2438
4ad16808
ZJS
2439 log_debug("Journal filter: %s", filter);
2440 }
67e04a48 2441
69e714f3 2442 if (arg_action == ACTION_LIST_FIELDS) {
15119c16
LP
2443 const void *data;
2444 size_t size;
2445
69e714f3
LP
2446 assert(arg_field);
2447
21ae4593
ZJS
2448 r = sd_journal_set_data_threshold(j, 0);
2449 if (r < 0) {
b56d608e 2450 log_error_errno(r, "Failed to unset data size threshold: %m");
909dea0c 2451 goto finish;
21ae4593
ZJS
2452 }
2453
15119c16
LP
2454 r = sd_journal_query_unique(j, arg_field);
2455 if (r < 0) {
da927ba9 2456 log_error_errno(r, "Failed to query unique data objects: %m");
909dea0c 2457 goto finish;
15119c16
LP
2458 }
2459
2460 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
2461 const void *eq;
2462
67e04a48 2463 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
2464 break;
2465
15119c16
LP
2466 eq = memchr(data, '=', size);
2467 if (eq)
2468 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
2469 else
2470 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875 2471
313cefa1 2472 n_shown++;
15119c16
LP
2473 }
2474
909dea0c
LP
2475 r = 0;
2476 goto finish;
15119c16
LP
2477 }
2478
8d98da3f
ZJS
2479 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2480 if (arg_follow) {
2a1e0f22
LP
2481 poll_fd = sd_journal_get_fd(j);
2482 if (poll_fd == -EMFILE) {
5238e957 2483 log_warning_errno(poll_fd, "Insufficient watch descriptors available. Reverting to -n.");
321ed364 2484 arg_follow = false;
2a1e0f22
LP
2485 } else if (poll_fd == -EMEDIUMTYPE) {
2486 log_error_errno(poll_fd, "The --follow switch is not supported in conjunction with reading from STDIN.");
5d1ce257 2487 goto finish;
2a1e0f22
LP
2488 } else if (poll_fd < 0) {
2489 log_error_errno(poll_fd, "Failed to get journal fd: %m");
909dea0c 2490 goto finish;
b56d608e 2491 }
8d98da3f
ZJS
2492 }
2493
d9e15cbd
JS
2494 if (arg_cursor || arg_after_cursor || arg_cursor_file) {
2495 _cleanup_free_ char *cursor_from_file = NULL;
2496 const char *cursor = arg_cursor ?: arg_after_cursor;
2497
2498 if (arg_cursor_file) {
2499 r = read_one_line_file(arg_cursor_file, &cursor_from_file);
2500 if (r < 0 && r != -ENOENT) {
2501 log_error_errno(r, "Failed to read cursor file %s: %m", arg_cursor_file);
2502 goto finish;
2503 }
2504
2505 if (r > 0) {
2506 cursor = cursor_from_file;
2507 after_cursor = true;
2508 }
2509 } else
d7a0f1f4 2510 after_cursor = arg_after_cursor;
d9e15cbd
JS
2511
2512 if (cursor) {
2513 r = sd_journal_seek_cursor(j, cursor);
2514 if (r < 0) {
2515 log_error_errno(r, "Failed to seek to cursor: %m");
2516 goto finish;
2517 }
2518 use_cursor = true;
08984293 2519 }
d9e15cbd 2520 }
909dea0c 2521
d9e15cbd 2522 if (use_cursor) {
d89d6c86 2523 if (!arg_reverse)
d9e15cbd 2524 r = sd_journal_next_skip(j, 1 + after_cursor);
d89d6c86 2525 else
d9e15cbd 2526 r = sd_journal_previous_skip(j, 1 + after_cursor);
248fc619 2527
d9e15cbd 2528 if (after_cursor && r < 2) {
248fc619 2529 /* We couldn't find the next entry after the cursor. */
8ee8e536
WD
2530 if (arg_follow)
2531 need_seek = true;
2532 else
2533 arg_lines = 0;
2534 }
08984293 2535
d89d6c86 2536 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 2537 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 2538 if (r < 0) {
da927ba9 2539 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2540 goto finish;
8f14c832 2541 }
8f14c832
LP
2542 r = sd_journal_next(j);
2543
d89d6c86
LN
2544 } else if (arg_until_set && arg_reverse) {
2545 r = sd_journal_seek_realtime_usec(j, arg_until);
2546 if (r < 0) {
da927ba9 2547 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2548 goto finish;
d89d6c86
LN
2549 }
2550 r = sd_journal_previous(j);
2551
23b39216 2552 } else if (arg_reverse) {
2100675e
LP
2553 r = sd_journal_seek_tail(j);
2554 if (r < 0) {
da927ba9 2555 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2556 goto finish;
2100675e
LP
2557 }
2558
23b39216 2559 r = sd_journal_previous(j);
8f14c832 2560
23b39216 2561 } else if (arg_lines >= 0) {
d89d6c86
LN
2562 r = sd_journal_seek_tail(j);
2563 if (r < 0) {
da927ba9 2564 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2565 goto finish;
d89d6c86
LN
2566 }
2567
23b39216 2568 r = sd_journal_previous_skip(j, arg_lines);
d89d6c86 2569
2100675e
LP
2570 } else {
2571 r = sd_journal_seek_head(j);
2572 if (r < 0) {
da927ba9 2573 log_error_errno(r, "Failed to seek to head: %m");
909dea0c 2574 goto finish;
2100675e 2575 }
6f003b43
LP
2576
2577 r = sd_journal_next(j);
2578 }
2579
2580 if (r < 0) {
da927ba9 2581 log_error_errno(r, "Failed to iterate through journal: %m");
909dea0c 2582 goto finish;
50f20cfd 2583 }
5f42943c
LK
2584 if (r == 0)
2585 need_seek = true;
87d2c1ff 2586
faf5077f 2587 if (!arg_follow)
0221d68a 2588 (void) pager_open(arg_pager_flags);
0d43c694 2589
5f42943c 2590 if (!arg_quiet && (arg_lines != 0 || arg_follow)) {
cfbc22ab
LP
2591 usec_t start, end;
2592 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
2593
2594 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
2595 if (r < 0) {
da927ba9 2596 log_error_errno(r, "Failed to get cutoff: %m");
cfbc22ab
LP
2597 goto finish;
2598 }
2599
2600 if (r > 0) {
2601 if (arg_follow)
b91ae210 2602 printf("-- Journal begins at %s. --\n",
5ab99e07 2603 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2604 else
b91ae210 2605 printf("-- Journal begins at %s, ends at %s. --\n",
5ab99e07
LP
2606 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2607 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2608 }
2609 }
2610
50f20cfd 2611 for (;;) {
67e04a48 2612 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab 2613 int flags;
b4766d5f 2614 size_t highlight[2] = {};
cfbc22ab 2615
6f003b43 2616 if (need_seek) {
99613ec5 2617 if (!arg_reverse)
d89d6c86
LN
2618 r = sd_journal_next(j);
2619 else
2620 r = sd_journal_previous(j);
6f003b43 2621 if (r < 0) {
da927ba9 2622 log_error_errno(r, "Failed to iterate through journal: %m");
6f003b43
LP
2623 goto finish;
2624 }
a72b6353
ZJS
2625 if (r == 0)
2626 break;
0d43c694
LP
2627 }
2628
d89d6c86 2629 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
2630 usec_t usec;
2631
2632 r = sd_journal_get_realtime_usec(j, &usec);
2633 if (r < 0) {
da927ba9 2634 log_error_errno(r, "Failed to determine timestamp: %m");
cfbc22ab
LP
2635 goto finish;
2636 }
3ba09ee8 2637 if (usec > arg_until)
3ac9cac7 2638 break;
cfbc22ab
LP
2639 }
2640
d89d6c86
LN
2641 if (arg_since_set && arg_reverse) {
2642 usec_t usec;
2643
2644 r = sd_journal_get_realtime_usec(j, &usec);
2645 if (r < 0) {
da927ba9 2646 log_error_errno(r, "Failed to determine timestamp: %m");
d89d6c86
LN
2647 goto finish;
2648 }
2649 if (usec < arg_since)
3ac9cac7 2650 break;
d89d6c86
LN
2651 }
2652
4bed2485 2653 if (!arg_merge && !arg_quiet) {
cd931c0a 2654 sd_id128_t boot_id;
14a65d65 2655
cd931c0a
LP
2656 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2657 if (r >= 0) {
2658 if (previous_boot_id_valid &&
2659 !sd_id128_equal(boot_id, previous_boot_id))
ea394d48
RP
2660 printf("%s-- Boot "SD_ID128_FORMAT_STR" --%s\n",
2661 ansi_highlight(), SD_ID128_FORMAT_VAL(boot_id), ansi_normal());
cd931c0a
LP
2662
2663 previous_boot_id = boot_id;
2664 previous_boot_id_valid = true;
2665 }
14a65d65
LP
2666 }
2667
6becf48c 2668#if HAVE_PCRE2
61c5f8a1 2669 if (arg_compiled_pattern) {
9200bb30 2670 _cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL;
6becf48c
ZJS
2671 const void *message;
2672 size_t len;
b4766d5f 2673 PCRE2_SIZE *ovec;
6becf48c 2674
9200bb30 2675 md = sym_pcre2_match_data_create(1, NULL);
6becf48c
ZJS
2676 if (!md)
2677 return log_oom();
2678
2679 r = sd_journal_get_data(j, "MESSAGE", &message, &len);
2680 if (r < 0) {
2681 if (r == -ENOENT) {
2682 need_seek = true;
2683 continue;
2684 }
2685
2686 log_error_errno(r, "Failed to get MESSAGE field: %m");
2687 goto finish;
2688 }
2689
2690 assert_se(message = startswith(message, "MESSAGE="));
2691
9200bb30
LP
2692 r = sym_pcre2_match(arg_compiled_pattern,
2693 message,
2694 len - strlen("MESSAGE="),
2695 0, /* start at offset 0 in the subject */
2696 0, /* default options */
2697 md,
2698 NULL);
6becf48c
ZJS
2699 if (r == PCRE2_ERROR_NOMATCH) {
2700 need_seek = true;
2701 continue;
2702 }
2703 if (r < 0) {
2704 unsigned char buf[LINE_MAX];
2705 int r2;
2706
9200bb30 2707 r2 = sym_pcre2_get_error_message(r, buf, sizeof buf);
6becf48c
ZJS
2708 log_error("Pattern matching failed: %s",
2709 r2 < 0 ? "unknown error" : (char*) buf);
2710 r = -EINVAL;
2711 goto finish;
2712 }
b4766d5f 2713
9200bb30 2714 ovec = sym_pcre2_get_ovector_pointer(md);
b4766d5f
ZJS
2715 highlight[0] = ovec[0];
2716 highlight[1] = ovec[1];
6becf48c
ZJS
2717 }
2718#endif
2719
cfbc22ab 2720 flags =
cd4b13e0 2721 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 2722 arg_full * OUTPUT_FULL_WIDTH |
40c9fe4c 2723 colors_enabled() * OUTPUT_COLOR |
9fd29044 2724 arg_catalog * OUTPUT_CATALOG |
991e274b
LP
2725 arg_utc * OUTPUT_UTC |
2726 arg_no_hostname * OUTPUT_NO_HOSTNAME;
cfbc22ab 2727
9b972c9a
ZJS
2728 r = show_journal_entry(stdout, j, arg_output, 0, flags,
2729 arg_output_fields, highlight, &ellipsized);
a72b6353
ZJS
2730 need_seek = true;
2731 if (r == -EADDRNOTAVAIL)
2732 break;
2a1e0f22 2733 else if (r < 0)
72f59706 2734 goto finish;
6f003b43 2735
cfbc22ab 2736 n_shown++;
ec316d19
PP
2737
2738 /* If journalctl take a long time to process messages, and during that time journal file
2739 * rotation occurs, a journalctl client will keep those rotated files open until it calls
2740 * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below
2741 * in the "following" case. By periodically calling sd_journal_process() during the processing
2742 * loop we shrink the window of time a client instance has open file descriptors for rotated
2743 * (deleted) journal files. */
2744 if ((n_shown % PROCESS_INOTIFY_INTERVAL) == 0) {
2745 r = sd_journal_process(j);
2746 if (r < 0) {
2747 log_error_errno(r, "Failed to process inotify events: %m");
2748 goto finish;
2749 }
2750 }
87d2c1ff
LP
2751 }
2752
248fc619 2753 if (!arg_follow) {
5f42943c
LK
2754 if (n_shown == 0 && !arg_quiet)
2755 printf("-- No entries --\n");
50f20cfd 2756 break;
248fc619 2757 }
50f20cfd 2758
b1aa5ced 2759 fflush(stdout);
2a1e0f22
LP
2760
2761 r = wait_for_change(j, poll_fd);
2762 if (r < 0)
50f20cfd 2763 goto finish;
67e04a48
ZJS
2764
2765 first_line = false;
de190aef 2766 }
87d2c1ff 2767
3ac9cac7
TS
2768 if (arg_show_cursor || arg_cursor_file) {
2769 _cleanup_free_ char *cursor = NULL;
2770
2771 r = sd_journal_get_cursor(j, &cursor);
2772 if (r < 0 && r != -EADDRNOTAVAIL)
2773 log_error_errno(r, "Failed to get cursor: %m");
2774 else if (r >= 0) {
2775 if (arg_show_cursor)
2776 printf("-- cursor: %s\n", cursor);
2777
2778 if (arg_cursor_file) {
2779 r = write_string_file(arg_cursor_file, cursor,
2780 WRITE_STRING_FILE_CREATE |
2781 WRITE_STRING_FILE_ATOMIC);
2782 if (r < 0)
2783 log_error_errno(r,
2784 "Failed to write new cursor to %s: %m",
2785 arg_cursor_file);
2786 }
2787 }
2788 }
2789
87d2c1ff 2790finish:
0d43c694
LP
2791 pager_close();
2792
a36b8deb
ZJS
2793 strv_free(arg_file);
2794
196dedd5 2795 set_free(arg_facilities);
d52da205
LP
2796 strv_free(arg_syslog_identifier);
2797 strv_free(arg_system_units);
2798 strv_free(arg_user_units);
cc25a67e 2799 strv_free(arg_output_fields);
d52da205 2800
0f03c2a4 2801 free(arg_root);
6bae9b2a 2802 free(arg_verify_key);
0f03c2a4 2803
6becf48c 2804#if HAVE_PCRE2
6cda6774 2805 if (arg_compiled_pattern) {
9200bb30 2806 sym_pcre2_code_free(arg_compiled_pattern);
6cda6774
FS
2807
2808 /* --grep was used, no error was thrown, but the pattern didn't
2809 * match anything. Let's mimic grep's behavior here and return
2810 * a non-zero exit code, so journalctl --grep can be used
2811 * in scripts and such */
2812 if (r == 0 && n_shown == 0)
2813 r = -ENOENT;
2814 }
6becf48c
ZJS
2815#endif
2816
3fbf9cbb 2817 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2818}