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