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