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