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