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