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