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