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