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