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