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