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