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