]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
Merge pull request #7610 from poettering/stdio-nolocking
[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
1346 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
23bbb0de
MS
1347 if (r < 0)
1348 return log_error_errno(r, "Failed to add match: %m");
99271804
ZJS
1349
1350 r = sd_journal_add_conjunction(j);
1351 if (r < 0)
b56d608e 1352 return log_error_errno(r, "Failed to add conjunction: %m");
99271804
ZJS
1353
1354 return 0;
1355}
1356
b56d608e
LP
1357static int get_possible_units(
1358 sd_journal *j,
1359 const char *fields,
1360 char **patterns,
1361 Set **units) {
1362
ea18a4b5
ZJS
1363 _cleanup_set_free_free_ Set *found;
1364 const char *field;
c3f60ec5 1365 int r;
ea18a4b5 1366
d5099efc 1367 found = set_new(&string_hash_ops);
ea18a4b5 1368 if (!found)
b56d608e 1369 return -ENOMEM;
ea18a4b5
ZJS
1370
1371 NULSTR_FOREACH(field, fields) {
1372 const void *data;
1373 size_t size;
1374
1375 r = sd_journal_query_unique(j, field);
1376 if (r < 0)
1377 return r;
1378
1379 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1380 char **pattern, *eq;
1381 size_t prefix;
1382 _cleanup_free_ char *u = NULL;
1383
1384 eq = memchr(data, '=', size);
1385 if (eq)
1386 prefix = eq - (char*) data + 1;
1387 else
1388 prefix = 0;
1389
1390 u = strndup((char*) data + prefix, size - prefix);
1391 if (!u)
b56d608e 1392 return -ENOMEM;
ea18a4b5
ZJS
1393
1394 STRV_FOREACH(pattern, patterns)
1395 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1396 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1397
1398 r = set_consume(found, u);
1399 u = NULL;
1400 if (r < 0 && r != -EEXIST)
1401 return r;
1402
1403 break;
1404 }
1405 }
1406 }
1407
1408 *units = found;
1409 found = NULL;
1410 return 0;
1411}
1412
1413/* This list is supposed to return the superset of unit names
1414 * possibly matched by rules added with add_matches_for_unit... */
1415#define SYSTEM_UNITS \
1416 "_SYSTEMD_UNIT\0" \
1417 "COREDUMP_UNIT\0" \
1418 "UNIT\0" \
1419 "OBJECT_SYSTEMD_UNIT\0" \
1420 "_SYSTEMD_SLICE\0"
1421
1422/* ... and add_matches_for_user_unit */
1423#define USER_UNITS \
1424 "_SYSTEMD_USER_UNIT\0" \
1425 "USER_UNIT\0" \
1426 "COREDUMP_USER_UNIT\0" \
1427 "OBJECT_SYSTEMD_USER_UNIT\0"
1428
1429static int add_units(sd_journal *j) {
1430 _cleanup_strv_free_ char **patterns = NULL;
1431 int r, count = 0;
b9e40524 1432 char **i;
c3f60ec5
LP
1433
1434 assert(j);
1435
b9e40524 1436 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1437 _cleanup_free_ char *u = NULL;
1438
7410616c
LP
1439 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1440 if (r < 0)
1441 return r;
ea18a4b5
ZJS
1442
1443 if (string_is_glob(u)) {
1444 r = strv_push(&patterns, u);
1445 if (r < 0)
1446 return r;
1447 u = NULL;
1448 } else {
1449 r = add_matches_for_unit(j, u);
1450 if (r < 0)
1451 return r;
1452 r = sd_journal_add_disjunction(j);
1453 if (r < 0)
1454 return r;
313cefa1 1455 count++;
ea18a4b5
ZJS
1456 }
1457 }
1458
1459 if (!strv_isempty(patterns)) {
1460 _cleanup_set_free_free_ Set *units = NULL;
1461 Iterator it;
1462 char *u;
1463
1464 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1465 if (r < 0)
1466 return r;
ea18a4b5
ZJS
1467
1468 SET_FOREACH(u, units, it) {
1469 r = add_matches_for_unit(j, u);
1470 if (r < 0)
1471 return r;
1472 r = sd_journal_add_disjunction(j);
1473 if (r < 0)
1474 return r;
313cefa1 1475 count++;
ea18a4b5 1476 }
b9e40524 1477 }
c3f60ec5 1478
97b11eed 1479 patterns = strv_free(patterns);
ea18a4b5 1480
b9e40524 1481 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1482 _cleanup_free_ char *u = NULL;
1483
7410616c
LP
1484 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1485 if (r < 0)
1486 return r;
c3f60ec5 1487
ea18a4b5
ZJS
1488 if (string_is_glob(u)) {
1489 r = strv_push(&patterns, u);
1490 if (r < 0)
1491 return r;
1492 u = NULL;
1493 } else {
1494 r = add_matches_for_user_unit(j, u, getuid());
1495 if (r < 0)
1496 return r;
1497 r = sd_journal_add_disjunction(j);
1498 if (r < 0)
1499 return r;
313cefa1 1500 count++;
ea18a4b5
ZJS
1501 }
1502 }
1503
1504 if (!strv_isempty(patterns)) {
1505 _cleanup_set_free_free_ Set *units = NULL;
1506 Iterator it;
1507 char *u;
b9e40524 1508
ea18a4b5 1509 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1510 if (r < 0)
1511 return r;
1512
ea18a4b5
ZJS
1513 SET_FOREACH(u, units, it) {
1514 r = add_matches_for_user_unit(j, u, getuid());
1515 if (r < 0)
1516 return r;
1517 r = sd_journal_add_disjunction(j);
1518 if (r < 0)
1519 return r;
313cefa1 1520 count++;
ea18a4b5 1521 }
b9e40524 1522 }
c3f60ec5 1523
ea18a4b5
ZJS
1524 /* Complain if the user request matches but nothing whatsoever was
1525 * found, since otherwise everything would be matched. */
1526 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1527 return -ENODATA;
1528
cd34b3c6
HH
1529 r = sd_journal_add_conjunction(j);
1530 if (r < 0)
1531 return r;
1532
c3f60ec5
LP
1533 return 0;
1534}
1535
941e990d
LP
1536static int add_priorities(sd_journal *j) {
1537 char match[] = "PRIORITY=0";
1538 int i, r;
941e990d
LP
1539 assert(j);
1540
1541 if (arg_priorities == 0xFF)
1542 return 0;
1543
1544 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1545 if (arg_priorities & (1 << i)) {
1546 match[sizeof(match)-2] = '0' + i;
1547
941e990d 1548 r = sd_journal_add_match(j, match, strlen(match));
23bbb0de
MS
1549 if (r < 0)
1550 return log_error_errno(r, "Failed to add match: %m");
941e990d
LP
1551 }
1552
cd34b3c6
HH
1553 r = sd_journal_add_conjunction(j);
1554 if (r < 0)
b56d608e 1555 return log_error_errno(r, "Failed to add conjunction: %m");
cd34b3c6 1556
941e990d
LP
1557 return 0;
1558}
1559
73083640
HH
1560
1561static int add_syslog_identifier(sd_journal *j) {
1562 int r;
1563 char **i;
1564
1565 assert(j);
1566
1567 STRV_FOREACH(i, arg_syslog_identifier) {
1568 char *u;
1569
63c372cb 1570 u = strjoina("SYSLOG_IDENTIFIER=", *i);
73083640
HH
1571 r = sd_journal_add_match(j, u, 0);
1572 if (r < 0)
1573 return r;
1574 r = sd_journal_add_disjunction(j);
1575 if (r < 0)
1576 return r;
1577 }
1578
1579 r = sd_journal_add_conjunction(j);
1580 if (r < 0)
1581 return r;
1582
1583 return 0;
1584}
1585
7560fffc 1586static int setup_keys(void) {
349cc4a5 1587#if HAVE_GCRYPT
7560fffc
LP
1588 size_t mpk_size, seed_size, state_size, i;
1589 uint8_t *mpk, *seed, *state;
11689d2a 1590 int fd = -1, r;
7560fffc
LP
1591 sd_id128_t machine, boot;
1592 char *p = NULL, *k = NULL;
baed47c3 1593 struct FSSHeader h;
14d10188 1594 uint64_t n;
b98e3866
SL
1595 struct stat st;
1596
1597 r = stat("/var/log/journal", &st);
4c701096 1598 if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR))
4a62c710 1599 return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
b98e3866
SL
1600
1601 if (r < 0 || !S_ISDIR(st.st_mode)) {
1602 log_error("%s is not a directory, must be using persistent logging for FSS.",
1603 "/var/log/journal");
1604 return r < 0 ? -errno : -ENOTDIR;
1605 }
7560fffc
LP
1606
1607 r = sd_id128_get_machine(&machine);
23bbb0de
MS
1608 if (r < 0)
1609 return log_error_errno(r, "Failed to get machine ID: %m");
7560fffc
LP
1610
1611 r = sd_id128_get_boot(&boot);
23bbb0de
MS
1612 if (r < 0)
1613 return log_error_errno(r, "Failed to get boot ID: %m");
7560fffc 1614
baed47c3 1615 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1616 SD_ID128_FORMAT_VAL(machine)) < 0)
1617 return log_oom();
1618
faf9da01
ZJS
1619 if (arg_force) {
1620 r = unlink(p);
1621 if (r < 0 && errno != ENOENT) {
1622 r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
b8547c10
SL
1623 goto finish;
1624 }
faf9da01
ZJS
1625 } else if (access(p, F_OK) >= 0) {
1626 log_error("Sealing key file %s exists already. Use --force to recreate.", p);
1627 r = -EEXIST;
1628 goto finish;
7560fffc
LP
1629 }
1630
baed47c3 1631 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1632 SD_ID128_FORMAT_VAL(machine)) < 0) {
1633 r = log_oom();
1634 goto finish;
1635 }
1636
1637 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1638 mpk = alloca(mpk_size);
1639
1640 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1641 seed = alloca(seed_size);
1642
1643 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1644 state = alloca(state_size);
1645
1646 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1647 if (fd < 0) {
76ef789d 1648 r = log_error_errno(errno, "Failed to open /dev/random: %m");
7560fffc
LP
1649 goto finish;
1650 }
1651
1652 log_info("Generating seed...");
a6dcc7e5
ZJS
1653 r = loop_read_exact(fd, seed, seed_size, true);
1654 if (r < 0) {
1655 log_error_errno(r, "Failed to read random seed: %m");
7560fffc
LP
1656 goto finish;
1657 }
1658
1659 log_info("Generating key pair...");
1660 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1661
baed47c3 1662 log_info("Generating sealing key...");
7560fffc
LP
1663 FSPRG_GenState0(state, mpk, seed, seed_size);
1664
baed47c3
LP
1665 assert(arg_interval > 0);
1666
7560fffc 1667 n = now(CLOCK_REALTIME);
baed47c3 1668 n /= arg_interval;
7560fffc 1669
03e334a1 1670 safe_close(fd);
646853bd 1671 fd = mkostemp_safe(k);
7560fffc 1672 if (fd < 0) {
709f6e46 1673 r = log_error_errno(fd, "Failed to open %s: %m", k);
7560fffc
LP
1674 goto finish;
1675 }
1676
f982e6f7
LP
1677 /* Enable secure remove, exclusion from dump, synchronous
1678 * writing and in-place updating */
1ed8f8c1 1679 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 1680 if (r < 0)
709f6e46 1681 log_warning_errno(r, "Failed to set file attributes: %m");
f982e6f7 1682
7560fffc
LP
1683 zero(h);
1684 memcpy(h.signature, "KSHHRHLP", 8);
1685 h.machine_id = machine;
1686 h.boot_id = boot;
1687 h.header_size = htole64(sizeof(h));
baed47c3
LP
1688 h.start_usec = htole64(n * arg_interval);
1689 h.interval_usec = htole64(arg_interval);
1690 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1691 h.fsprg_state_size = htole64(state_size);
7560fffc 1692
553acb7b
ZJS
1693 r = loop_write(fd, &h, sizeof(h), false);
1694 if (r < 0) {
1695 log_error_errno(r, "Failed to write header: %m");
7560fffc
LP
1696 goto finish;
1697 }
1698
553acb7b
ZJS
1699 r = loop_write(fd, state, state_size, false);
1700 if (r < 0) {
1701 log_error_errno(r, "Failed to write state: %m");
7560fffc
LP
1702 goto finish;
1703 }
1704
1705 if (link(k, p) < 0) {
76ef789d 1706 r = log_error_errno(errno, "Failed to link file: %m");
7560fffc
LP
1707 goto finish;
1708 }
1709
8481248b 1710 if (on_tty()) {
7560fffc
LP
1711 fprintf(stderr,
1712 "\n"
54f8c958 1713 "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
c05276f2
LP
1714 "the following local file. This key file is automatically updated when the\n"
1715 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1716 "\n"
1717 "\t%s\n"
1718 "\n"
54f8c958 1719 "Please write down the following %ssecret verification key%s. It should be stored\n"
baed47c3 1720 "at a safe location and should not be saved locally on disk.\n"
54f8c958
LP
1721 "\n\t%s",
1722 ansi_highlight(), ansi_normal(),
9ea78383 1723 p,
54f8c958 1724 ansi_highlight(), ansi_normal(),
9ea78383 1725 ansi_highlight_red());
7560fffc
LP
1726 fflush(stderr);
1727 }
1728 for (i = 0; i < seed_size; i++) {
1729 if (i > 0 && i % 3 == 0)
1730 putchar('-');
1731 printf("%02x", ((uint8_t*) seed)[i]);
1732 }
1733
baed47c3
LP
1734 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1735
8481248b 1736 if (on_tty()) {
f6a971bc 1737 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1738
baed47c3 1739 fprintf(stderr,
54f8c958 1740 "%s\n"
baed47c3 1741 "The sealing key is automatically changed every %s.\n",
54f8c958 1742 ansi_normal(),
2fa4092c 1743 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1744
1745 hn = gethostname_malloc();
1746
1747 if (hn) {
ae691c1d 1748 hostname_cleanup(hn);
adac1c93 1749 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1750 } else
adac1c93 1751 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc 1752
349cc4a5 1753#if HAVE_QRENCODE
cf5a3432 1754 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1755 if (is_locale_utf8()) {
cf5a3432
LP
1756 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1757 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1758 }
f6a971bc
LP
1759#endif
1760 free(hn);
baed47c3 1761 }
7560fffc
LP
1762
1763 r = 0;
1764
1765finish:
03e334a1 1766 safe_close(fd);
7560fffc
LP
1767
1768 if (k) {
1769 unlink(k);
1770 free(k);
1771 }
1772
1773 free(p);
1774
1775 return r;
1776#else
feb12d3e 1777 log_error("Forward-secure sealing not available.");
15411c0c 1778 return -EOPNOTSUPP;
7560fffc
LP
1779#endif
1780}
1781
beec0085
LP
1782static int verify(sd_journal *j) {
1783 int r = 0;
1784 Iterator i;
1785 JournalFile *f;
1786
1787 assert(j);
1788
cedb42bb
LP
1789 log_show_color(true);
1790
c1f906bd 1791 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
beec0085 1792 int k;
a7f7d1bd 1793 usec_t first = 0, validated = 0, last = 0;
beec0085 1794
349cc4a5 1795#if HAVE_GCRYPT
feb12d3e 1796 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1797 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1798#endif
4da416aa 1799
2a7b539a 1800 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1801 if (k == -EINVAL) {
baed47c3 1802 /* If the key was invalid give up right-away. */
56e81f7c
LP
1803 return k;
1804 } else if (k < 0) {
e53fc357 1805 log_warning_errno(k, "FAIL: %s (%m)", f->path);
56e81f7c 1806 r = k;
6c7be122
LP
1807 } else {
1808 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1809 log_info("PASS: %s", f->path);
6c7be122 1810
c0ca7aee 1811 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1812 if (validated > 0) {
c0ca7aee 1813 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1814 format_timestamp_maybe_utc(a, sizeof(a), first),
1815 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1816 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1817 } else if (last > 0)
c0ca7aee 1818 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1819 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1820 else
1821 log_info("=> No sealing yet, no entries in file.");
1822 }
6c7be122 1823 }
beec0085
LP
1824 }
1825
1826 return r;
1827}
1828
74055aa7 1829static int flush_to_var(void) {
4afd3348
LP
1830 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1831 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
74055aa7
LP
1832 _cleanup_close_ int watch_fd = -1;
1833 int r;
1834
176ee07b
LP
1835 if (arg_machine) {
1836 log_error("--flush is not supported in conjunction with --machine=.");
1837 return -EOPNOTSUPP;
1838 }
1839
74055aa7
LP
1840 /* Quick exit */
1841 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1842 return 0;
1843
1844 /* OK, let's actually do the full logic, send SIGUSR1 to the
1845 * daemon and set up inotify to wait for the flushed file to appear */
266f3e26 1846 r = bus_connect_system_systemd(&bus);
23bbb0de
MS
1847 if (r < 0)
1848 return log_error_errno(r, "Failed to get D-Bus connection: %m");
74055aa7
LP
1849
1850 r = sd_bus_call_method(
1851 bus,
1852 "org.freedesktop.systemd1",
1853 "/org/freedesktop/systemd1",
1854 "org.freedesktop.systemd1.Manager",
1855 "KillUnit",
1856 &error,
1857 NULL,
1858 "ssi", "systemd-journald.service", "main", SIGUSR1);
94b65516
LP
1859 if (r < 0)
1860 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
74055aa7
LP
1861
1862 mkdir_p("/run/systemd/journal", 0755);
1863
1864 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
4a62c710
MS
1865 if (watch_fd < 0)
1866 return log_error_errno(errno, "Failed to create inotify watch: %m");
74055aa7
LP
1867
1868 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
4a62c710
MS
1869 if (r < 0)
1870 return log_error_errno(errno, "Failed to watch journal directory: %m");
74055aa7
LP
1871
1872 for (;;) {
1873 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1874 break;
1875
4a62c710 1876 if (errno != ENOENT)
f131770b 1877 return log_error_errno(errno, "Failed to check for existence of /run/systemd/journal/flushed: %m");
74055aa7
LP
1878
1879 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
23bbb0de
MS
1880 if (r < 0)
1881 return log_error_errno(r, "Failed to wait for event: %m");
74055aa7
LP
1882
1883 r = flush_fd(watch_fd);
23bbb0de
MS
1884 if (r < 0)
1885 return log_error_errno(r, "Failed to flush inotify events: %m");
74055aa7
LP
1886 }
1887
1888 return 0;
1889}
1890
dbd6e31c 1891static int send_signal_and_wait(int sig, const char *watch_path) {
4afd3348 1892 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
94b65516
LP
1893 _cleanup_close_ int watch_fd = -1;
1894 usec_t start;
1895 int r;
1896
176ee07b
LP
1897 if (arg_machine) {
1898 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
1899 return -EOPNOTSUPP;
1900 }
1901
33d52ab9 1902 start = now(CLOCK_MONOTONIC);
94b65516 1903
dbd6e31c
LP
1904 /* This call sends the specified signal to journald, and waits
1905 * for acknowledgment by watching the mtime of the specified
1906 * flag file. This is used to trigger syncing or rotation and
1907 * then wait for the operation to complete. */
94b65516
LP
1908
1909 for (;;) {
33d52ab9 1910 usec_t tstamp;
94b65516
LP
1911
1912 /* See if a sync happened by now. */
33d52ab9
LP
1913 r = read_timestamp_file(watch_path, &tstamp);
1914 if (r < 0 && r != -ENOENT)
1915 return log_error_errno(errno, "Failed to read %s: %m", watch_path);
1916 if (r >= 0 && tstamp >= start)
1917 return 0;
94b65516
LP
1918
1919 /* Let's ask for a sync, but only once. */
1920 if (!bus) {
4afd3348 1921 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
94b65516
LP
1922
1923 r = bus_connect_system_systemd(&bus);
1924 if (r < 0)
1925 return log_error_errno(r, "Failed to get D-Bus connection: %m");
1926
1927 r = sd_bus_call_method(
1928 bus,
1929 "org.freedesktop.systemd1",
1930 "/org/freedesktop/systemd1",
1931 "org.freedesktop.systemd1.Manager",
1932 "KillUnit",
1933 &error,
1934 NULL,
dbd6e31c 1935 "ssi", "systemd-journald.service", "main", sig);
94b65516
LP
1936 if (r < 0)
1937 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
1938
1939 continue;
1940 }
1941
1942 /* Let's install the inotify watch, if we didn't do that yet. */
1943 if (watch_fd < 0) {
1944
1945 mkdir_p("/run/systemd/journal", 0755);
1946
1947 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1948 if (watch_fd < 0)
1949 return log_error_errno(errno, "Failed to create inotify watch: %m");
1950
33d52ab9 1951 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR);
94b65516
LP
1952 if (r < 0)
1953 return log_error_errno(errno, "Failed to watch journal directory: %m");
1954
1955 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
1956 continue;
1957 }
1958
1959 /* OK, all preparatory steps done, let's wait until
1960 * inotify reports an event. */
1961
1962 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
1963 if (r < 0)
1964 return log_error_errno(r, "Failed to wait for event: %m");
1965
1966 r = flush_fd(watch_fd);
1967 if (r < 0)
1968 return log_error_errno(r, "Failed to flush inotify events: %m");
1969 }
1970
1971 return 0;
1972}
1973
dbd6e31c
LP
1974static int rotate(void) {
1975 return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated");
1976}
1977
1978static int sync_journal(void) {
1979 return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced");
1980}
1981
a963990f
LP
1982int main(int argc, char *argv[]) {
1983 int r;
4afd3348 1984 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
a963990f 1985 bool need_seek = false;
14a65d65 1986 sd_id128_t previous_boot_id;
67e04a48
ZJS
1987 bool previous_boot_id_valid = false, first_line = true;
1988 int n_shown = 0;
94e0bd7d 1989 bool ellipsized = false;
a963990f 1990
a9cdc94f 1991 setlocale(LC_ALL, "");
a963990f
LP
1992 log_parse_environment();
1993 log_open();
1994
1995 r = parse_argv(argc, argv);
1996 if (r <= 0)
1997 goto finish;
1998
ed757c0c 1999 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 2000 sigbus_install();
ed757c0c 2001
de45d726
LP
2002 /* Increase max number of open files to 16K if we can, we
2003 * might needs this when browsing journal files, which might
2004 * be split up into many files. */
2005 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
2006
a020b3b3 2007 switch (arg_action) {
94b65516 2008
a020b3b3
LP
2009 case ACTION_NEW_ID128:
2010 r = generate_new_id128();
e3fdfb49 2011 goto finish;
e3fdfb49 2012
a020b3b3 2013 case ACTION_SETUP_KEYS:
7560fffc
LP
2014 r = setup_keys();
2015 goto finish;
844ec79b 2016
a020b3b3
LP
2017 case ACTION_LIST_CATALOG:
2018 case ACTION_DUMP_CATALOG:
2019 case ACTION_UPDATE_CATALOG: {
0c6ea3a4
ZJS
2020 _cleanup_free_ char *database;
2021
2022 database = path_join(arg_root, CATALOG_DATABASE, NULL);
2023 if (!database) {
2024 r = log_oom();
2025 goto finish;
13cbf3a5
ZJS
2026 }
2027
844ec79b 2028 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 2029 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b 2030 if (r < 0)
da927ba9 2031 log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
2032 } else {
2033 bool oneline = arg_action == ACTION_LIST_CATALOG;
2034
ea4b98e6 2035 pager_open(arg_no_pager, arg_pager_end);
a020b3b3 2036
844ec79b 2037 if (optind < argc)
a020b3b3 2038 r = catalog_list_items(stdout, database, oneline, argv + optind);
844ec79b 2039 else
13cbf3a5 2040 r = catalog_list(stdout, database, oneline);
844ec79b 2041 if (r < 0)
da927ba9 2042 log_error_errno(r, "Failed to list catalog: %m");
844ec79b 2043 }
d4205751 2044
d4205751
LP
2045 goto finish;
2046 }
2047
a020b3b3
LP
2048 case ACTION_FLUSH:
2049 r = flush_to_var();
2050 goto finish;
2051
2052 case ACTION_SYNC:
2053 r = sync_journal();
2054 goto finish;
2055
2056 case ACTION_ROTATE:
2057 r = rotate();
2058 goto finish;
2059
2060 case ACTION_SHOW:
2061 case ACTION_PRINT_HEADER:
2062 case ACTION_VERIFY:
2063 case ACTION_DISK_USAGE:
2064 case ACTION_LIST_BOOTS:
2065 case ACTION_VACUUM:
69e714f3
LP
2066 case ACTION_LIST_FIELDS:
2067 case ACTION_LIST_FIELD_NAMES:
a020b3b3
LP
2068 /* These ones require access to the journal files, continue below. */
2069 break;
2070
2071 default:
2072 assert_not_reached("Unknown action");
2073 }
2074
a963990f 2075 if (arg_directory)
3f3a438f 2076 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
0a175093
ZJS
2077 else if (arg_root)
2078 r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
5d1ce257
LP
2079 else if (arg_file_stdin) {
2080 int ifd = STDIN_FILENO;
2081 r = sd_journal_open_files_fd(&j, &ifd, 1, 0);
2082 } else if (arg_file)
8d98da3f 2083 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
d38c62cc
LP
2084 else if (arg_machine) {
2085 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2086 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2087 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2088 int fd;
2089
2090 if (geteuid() != 0) {
2091 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
2092 * the container, thus we need root privileges to override them. */
2093 log_error("Using the --machine= switch requires root privileges.");
2094 r = -EPERM;
2095 goto finish;
2096 }
2097
2098 r = sd_bus_open_system(&bus);
2099 if (r < 0) {
2100 log_error_errno(r, "Failed to open system bus: %m");
2101 goto finish;
2102 }
2103
2104 r = sd_bus_call_method(
2105 bus,
2106 "org.freedesktop.machine1",
2107 "/org/freedesktop/machine1",
2108 "org.freedesktop.machine1.Manager",
2109 "OpenMachineRootDirectory",
2110 &error,
2111 &reply,
2112 "s", arg_machine);
2113 if (r < 0) {
2114 log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
2115 goto finish;
2116 }
2117
2118 r = sd_bus_message_read(reply, "h", &fd);
2119 if (r < 0) {
2120 bus_log_parse_error(r);
2121 goto finish;
2122 }
2123
2124 fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
2125 if (fd < 0) {
2126 r = log_error_errno(errno, "Failed to duplicate file descriptor: %m");
2127 goto finish;
2128 }
2129
2130 r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT);
2131 if (r < 0)
2132 safe_close(fd);
2133 } else
3f3a438f 2134 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 2135 if (r < 0) {
a020b3b3 2136 log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
909dea0c 2137 goto finish;
a963990f
LP
2138 }
2139
4f37cbd9 2140 r = journal_access_check_and_warn(j, arg_quiet);
6fe391c5 2141 if (r < 0)
909dea0c 2142 goto finish;
6fe391c5 2143
a020b3b3 2144 switch (arg_action) {
beec0085 2145
a020b3b3
LP
2146 case ACTION_NEW_ID128:
2147 case ACTION_SETUP_KEYS:
2148 case ACTION_LIST_CATALOG:
2149 case ACTION_DUMP_CATALOG:
2150 case ACTION_UPDATE_CATALOG:
2151 case ACTION_FLUSH:
2152 case ACTION_SYNC:
2153 case ACTION_ROTATE:
2154 assert_not_reached("Unexpected action.");
2155
2156 case ACTION_PRINT_HEADER:
dca6219e 2157 journal_print_header(j);
909dea0c
LP
2158 r = 0;
2159 goto finish;
dca6219e 2160
a020b3b3
LP
2161 case ACTION_VERIFY:
2162 r = verify(j);
2163 goto finish;
2164
2165 case ACTION_DISK_USAGE: {
39883f62 2166 uint64_t bytes = 0;
a1a03e30
LP
2167 char sbytes[FORMAT_BYTES_MAX];
2168
2169 r = sd_journal_get_usage(j, &bytes);
2170 if (r < 0)
909dea0c 2171 goto finish;
a1a03e30 2172
8da830bc 2173 printf("Archived and active journals take up %s in the file system.\n",
763c7aa2 2174 format_bytes(sbytes, sizeof(sbytes), bytes));
909dea0c 2175 goto finish;
a1a03e30
LP
2176 }
2177
a020b3b3
LP
2178 case ACTION_LIST_BOOTS:
2179 r = list_boots(j);
2180 goto finish;
2181
2182 case ACTION_VACUUM: {
dbd2a83f
LP
2183 Directory *d;
2184 Iterator i;
2185
2186 HASHMAP_FOREACH(d, j->directories_by_path, i) {
2187 int q;
2188
2189 if (d->is_root)
2190 continue;
2191
e3695e49 2192 q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, !arg_quiet);
dbd2a83f 2193 if (q < 0) {
8580d1f7 2194 log_error_errno(q, "Failed to vacuum %s: %m", d->path);
dbd2a83f
LP
2195 r = q;
2196 }
2197 }
2198
909dea0c 2199 goto finish;
dbd2a83f
LP
2200 }
2201
69e714f3
LP
2202 case ACTION_LIST_FIELD_NAMES: {
2203 const char *field;
2204
2205 SD_JOURNAL_FOREACH_FIELD(j, field) {
2206 printf("%s\n", field);
313cefa1 2207 n_shown++;
69e714f3
LP
2208 }
2209
2210 r = 0;
2211 goto finish;
2212 }
2213
a020b3b3 2214 case ACTION_SHOW:
69e714f3 2215 case ACTION_LIST_FIELDS:
a020b3b3
LP
2216 break;
2217
2218 default:
2219 assert_not_reached("Unknown action");
f1188074
ZJS
2220 }
2221
0f1a9a83
JS
2222 if (arg_boot_offset != 0 &&
2223 sd_journal_has_runtime_files(j) > 0 &&
2224 sd_journal_has_persistent_files(j) == 0) {
493097ee 2225 log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found.");
0f1a9a83
JS
2226 r = 0;
2227 goto finish;
2228 }
a331b5e6
JJ
2229 /* add_boot() must be called first!
2230 * It may need to seek the journal to find parent boot IDs. */
2231 r = add_boot(j);
a963990f 2232 if (r < 0)
909dea0c 2233 goto finish;
a963990f 2234
99271804
ZJS
2235 r = add_dmesg(j);
2236 if (r < 0)
909dea0c 2237 goto finish;
99271804 2238
b9e40524 2239 r = add_units(j);
ea18a4b5 2240 if (r < 0) {
da927ba9 2241 log_error_errno(r, "Failed to add filter for units: %m");
909dea0c 2242 goto finish;
ea18a4b5 2243 }
c3f60ec5 2244
73083640
HH
2245 r = add_syslog_identifier(j);
2246 if (r < 0) {
da927ba9 2247 log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
909dea0c 2248 goto finish;
73083640
HH
2249 }
2250
cd34b3c6 2251 r = add_priorities(j);
b56d608e 2252 if (r < 0)
909dea0c 2253 goto finish;
a963990f 2254
cd34b3c6 2255 r = add_matches(j, argv + optind);
b56d608e 2256 if (r < 0)
909dea0c 2257 goto finish;
941e990d 2258
553d2243 2259 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
4ad16808
ZJS
2260 _cleanup_free_ char *filter;
2261
2262 filter = journal_make_match_string(j);
b56d608e
LP
2263 if (!filter)
2264 return log_oom();
2265
4ad16808
ZJS
2266 log_debug("Journal filter: %s", filter);
2267 }
67e04a48 2268
69e714f3 2269 if (arg_action == ACTION_LIST_FIELDS) {
15119c16
LP
2270 const void *data;
2271 size_t size;
2272
69e714f3
LP
2273 assert(arg_field);
2274
21ae4593
ZJS
2275 r = sd_journal_set_data_threshold(j, 0);
2276 if (r < 0) {
b56d608e 2277 log_error_errno(r, "Failed to unset data size threshold: %m");
909dea0c 2278 goto finish;
21ae4593
ZJS
2279 }
2280
15119c16
LP
2281 r = sd_journal_query_unique(j, arg_field);
2282 if (r < 0) {
da927ba9 2283 log_error_errno(r, "Failed to query unique data objects: %m");
909dea0c 2284 goto finish;
15119c16
LP
2285 }
2286
2287 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
2288 const void *eq;
2289
67e04a48 2290 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
2291 break;
2292
15119c16
LP
2293 eq = memchr(data, '=', size);
2294 if (eq)
2295 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
2296 else
2297 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875 2298
313cefa1 2299 n_shown++;
15119c16
LP
2300 }
2301
909dea0c
LP
2302 r = 0;
2303 goto finish;
15119c16
LP
2304 }
2305
8d98da3f
ZJS
2306 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2307 if (arg_follow) {
2308 r = sd_journal_get_fd(j);
5d1ce257
LP
2309 if (r == -EMEDIUMTYPE) {
2310 log_error_errno(r, "The --follow switch is not supported in conjunction with reading from STDIN.");
2311 goto finish;
2312 }
b56d608e
LP
2313 if (r < 0) {
2314 log_error_errno(r, "Failed to get journal fd: %m");
909dea0c 2315 goto finish;
b56d608e 2316 }
8d98da3f
ZJS
2317 }
2318
248fc619 2319 if (arg_cursor || arg_after_cursor) {
eacbb4d3 2320 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
08984293 2321 if (r < 0) {
da927ba9 2322 log_error_errno(r, "Failed to seek to cursor: %m");
909dea0c 2323 goto finish;
08984293 2324 }
909dea0c 2325
d89d6c86 2326 if (!arg_reverse)
248fc619 2327 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
d89d6c86 2328 else
248fc619
ZJS
2329 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
2330
8ee8e536 2331 if (arg_after_cursor && r < 2) {
248fc619 2332 /* We couldn't find the next entry after the cursor. */
8ee8e536
WD
2333 if (arg_follow)
2334 need_seek = true;
2335 else
2336 arg_lines = 0;
2337 }
08984293 2338
d89d6c86 2339 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 2340 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 2341 if (r < 0) {
da927ba9 2342 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2343 goto finish;
8f14c832 2344 }
8f14c832
LP
2345 r = sd_journal_next(j);
2346
d89d6c86
LN
2347 } else if (arg_until_set && arg_reverse) {
2348 r = sd_journal_seek_realtime_usec(j, arg_until);
2349 if (r < 0) {
da927ba9 2350 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2351 goto finish;
d89d6c86
LN
2352 }
2353 r = sd_journal_previous(j);
2354
67e04a48 2355 } else if (arg_lines >= 0) {
2100675e
LP
2356 r = sd_journal_seek_tail(j);
2357 if (r < 0) {
da927ba9 2358 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2359 goto finish;
2100675e
LP
2360 }
2361
2362 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 2363
d89d6c86
LN
2364 } else if (arg_reverse) {
2365 r = sd_journal_seek_tail(j);
2366 if (r < 0) {
da927ba9 2367 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2368 goto finish;
d89d6c86
LN
2369 }
2370
2371 r = sd_journal_previous(j);
2372
2100675e
LP
2373 } else {
2374 r = sd_journal_seek_head(j);
2375 if (r < 0) {
da927ba9 2376 log_error_errno(r, "Failed to seek to head: %m");
909dea0c 2377 goto finish;
2100675e 2378 }
6f003b43
LP
2379
2380 r = sd_journal_next(j);
2381 }
2382
2383 if (r < 0) {
da927ba9 2384 log_error_errno(r, "Failed to iterate through journal: %m");
909dea0c 2385 goto finish;
50f20cfd 2386 }
5f42943c
LK
2387 if (r == 0)
2388 need_seek = true;
87d2c1ff 2389
faf5077f 2390 if (!arg_follow)
ea4b98e6 2391 pager_open(arg_no_pager, arg_pager_end);
0d43c694 2392
5f42943c 2393 if (!arg_quiet && (arg_lines != 0 || arg_follow)) {
cfbc22ab
LP
2394 usec_t start, end;
2395 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
2396
2397 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
2398 if (r < 0) {
da927ba9 2399 log_error_errno(r, "Failed to get cutoff: %m");
cfbc22ab
LP
2400 goto finish;
2401 }
2402
2403 if (r > 0) {
2404 if (arg_follow)
9048b11f 2405 printf("-- Logs begin at %s. --\n",
5ab99e07 2406 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2407 else
9048b11f 2408 printf("-- Logs begin at %s, end at %s. --\n",
5ab99e07
LP
2409 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2410 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2411 }
2412 }
2413
50f20cfd 2414 for (;;) {
67e04a48 2415 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab
LP
2416 int flags;
2417
6f003b43 2418 if (need_seek) {
99613ec5 2419 if (!arg_reverse)
d89d6c86
LN
2420 r = sd_journal_next(j);
2421 else
2422 r = sd_journal_previous(j);
6f003b43 2423 if (r < 0) {
da927ba9 2424 log_error_errno(r, "Failed to iterate through journal: %m");
6f003b43
LP
2425 goto finish;
2426 }
a72b6353
ZJS
2427 if (r == 0)
2428 break;
0d43c694
LP
2429 }
2430
d89d6c86 2431 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
2432 usec_t usec;
2433
2434 r = sd_journal_get_realtime_usec(j, &usec);
2435 if (r < 0) {
da927ba9 2436 log_error_errno(r, "Failed to determine timestamp: %m");
cfbc22ab
LP
2437 goto finish;
2438 }
3ba09ee8
PF
2439 if (usec > arg_until)
2440 goto finish;
cfbc22ab
LP
2441 }
2442
d89d6c86
LN
2443 if (arg_since_set && arg_reverse) {
2444 usec_t usec;
2445
2446 r = sd_journal_get_realtime_usec(j, &usec);
2447 if (r < 0) {
da927ba9 2448 log_error_errno(r, "Failed to determine timestamp: %m");
d89d6c86
LN
2449 goto finish;
2450 }
2451 if (usec < arg_since)
2452 goto finish;
2453 }
2454
4bed2485 2455 if (!arg_merge && !arg_quiet) {
cd931c0a 2456 sd_id128_t boot_id;
14a65d65 2457
cd931c0a
LP
2458 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2459 if (r >= 0) {
2460 if (previous_boot_id_valid &&
2461 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c 2462 printf("%s-- Reboot --%s\n",
1fc464f6 2463 ansi_highlight(), ansi_normal());
cd931c0a
LP
2464
2465 previous_boot_id = boot_id;
2466 previous_boot_id_valid = true;
2467 }
14a65d65
LP
2468 }
2469
cfbc22ab 2470 flags =
cd4b13e0 2471 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 2472 arg_full * OUTPUT_FULL_WIDTH |
40c9fe4c 2473 colors_enabled() * OUTPUT_COLOR |
9fd29044 2474 arg_catalog * OUTPUT_CATALOG |
991e274b
LP
2475 arg_utc * OUTPUT_UTC |
2476 arg_no_hostname * OUTPUT_NO_HOSTNAME;
cfbc22ab 2477
cc25a67e 2478 r = output_journal(stdout, j, arg_output, 0, flags, arg_output_fields, &ellipsized);
a72b6353
ZJS
2479 need_seek = true;
2480 if (r == -EADDRNOTAVAIL)
2481 break;
2482 else if (r < 0 || ferror(stdout))
72f59706 2483 goto finish;
6f003b43 2484
cfbc22ab 2485 n_shown++;
87d2c1ff
LP
2486 }
2487
248fc619 2488 if (!arg_follow) {
5f42943c
LK
2489 if (n_shown == 0 && !arg_quiet)
2490 printf("-- No entries --\n");
2491
248fc619
ZJS
2492 if (arg_show_cursor) {
2493 _cleanup_free_ char *cursor = NULL;
2494
2495 r = sd_journal_get_cursor(j, &cursor);
2496 if (r < 0 && r != -EADDRNOTAVAIL)
da927ba9 2497 log_error_errno(r, "Failed to get cursor: %m");
248fc619
ZJS
2498 else if (r >= 0)
2499 printf("-- cursor: %s\n", cursor);
2500 }
2501
50f20cfd 2502 break;
248fc619 2503 }
50f20cfd 2504
b1aa5ced 2505 fflush(stdout);
e02d1cf7 2506 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 2507 if (r < 0) {
da927ba9 2508 log_error_errno(r, "Couldn't wait for journal event: %m");
50f20cfd
LP
2509 goto finish;
2510 }
67e04a48
ZJS
2511
2512 first_line = false;
de190aef 2513 }
87d2c1ff
LP
2514
2515finish:
b1aa5ced 2516 fflush(stdout);
0d43c694
LP
2517 pager_close();
2518
a36b8deb
ZJS
2519 strv_free(arg_file);
2520
d52da205
LP
2521 strv_free(arg_syslog_identifier);
2522 strv_free(arg_system_units);
2523 strv_free(arg_user_units);
cc25a67e 2524 strv_free(arg_output_fields);
d52da205 2525
0f03c2a4 2526 free(arg_root);
6bae9b2a 2527 free(arg_verify_key);
0f03c2a4 2528
3fbf9cbb 2529 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2530}