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