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