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