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