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