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