]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
sd-journal: do not reset sd_j_enumerate_unique position on error
[thirdparty/systemd.git] / src / journal / journalctl.c
CommitLineData
87d2c1ff
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
87d2c1ff
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
87d2c1ff 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
87d2c1ff
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
a9cdc94f 22#include <locale.h>
87d2c1ff 23#include <fcntl.h>
ea18a4b5 24#include <fnmatch.h>
87d2c1ff
LP
25#include <errno.h>
26#include <stddef.h>
3fbf9cbb
LP
27#include <string.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
72f59706 31#include <time.h>
0d43c694 32#include <getopt.h>
585314e8 33#include <signal.h>
50940700 34#include <sys/stat.h>
f982e6f7
LP
35#include <sys/ioctl.h>
36#include <linux/fs.h>
87d2c1ff 37
4468addc
LP
38#ifdef HAVE_ACL
39#include <sys/acl.h>
478c8269 40#include "acl-util.h"
4468addc
LP
41#endif
42
73f860db 43#include "systemd/sd-journal.h"
81527be1 44
3fbf9cbb 45#include "log.h"
7199aa96 46#include "logs-show.h"
72f59706 47#include "util.h"
e5124088 48#include "path-util.h"
68fee104 49#include "fileio.h"
0d43c694
LP
50#include "build.h"
51#include "pager.h"
a963990f 52#include "strv.h"
ea18a4b5 53#include "set.h"
dca6219e 54#include "journal-internal.h"
7560fffc 55#include "journal-def.h"
0284adc6 56#include "journal-verify.h"
4da416aa 57#include "journal-authenticate.h"
f6a971bc 58#include "journal-qrcode.h"
4da416aa 59#include "fsprg.h"
c3f60ec5 60#include "unit-name.h"
d4205751 61#include "catalog.h"
7560fffc 62
baed47c3 63#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
250d54b5 64
df50185b 65static OutputMode arg_output = OUTPUT_SHORT;
9fd29044 66static bool arg_utc = false;
1b12a7b5 67static bool arg_pager_end = false;
72f59706 68static bool arg_follow = false;
2b8f6883 69static bool arg_full = true;
cd4b13e0 70static bool arg_all = false;
0d43c694 71static bool arg_no_pager = false;
48382487 72static int arg_lines = -2;
e91af489 73static bool arg_no_tail = false;
43673799 74static bool arg_quiet = false;
9e8a535f 75static bool arg_merge = false;
d121b396 76static bool arg_boot = false;
442e2def
LP
77static sd_id128_t arg_boot_id = {};
78static int arg_boot_offset = 0;
99271804 79static bool arg_dmesg = false;
8f14c832 80static const char *arg_cursor = NULL;
248fc619
ZJS
81static const char *arg_after_cursor = NULL;
82static bool arg_show_cursor = false;
a963990f 83static const char *arg_directory = NULL;
8d98da3f 84static char **arg_file = NULL;
941e990d 85static int arg_priorities = 0xFF;
baed47c3 86static const char *arg_verify_key = NULL;
feb12d3e 87#ifdef HAVE_GCRYPT
baed47c3 88static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
b8547c10 89static bool arg_force = false;
feb12d3e 90#endif
cfbc22ab
LP
91static usec_t arg_since, arg_until;
92static bool arg_since_set = false, arg_until_set = false;
73083640 93static char **arg_syslog_identifier = NULL;
b9e40524
HH
94static char **arg_system_units = NULL;
95static char **arg_user_units = NULL;
3c1668da 96static const char *arg_field = NULL;
d4205751 97static bool arg_catalog = false;
d89d6c86 98static bool arg_reverse = false;
3f3a438f 99static int arg_journal_type = 0;
13cbf3a5 100static const char *arg_root = NULL;
b6741478 101static const char *arg_machine = NULL;
50f20cfd 102
7560fffc
LP
103static enum {
104 ACTION_SHOW,
105 ACTION_NEW_ID128,
106 ACTION_PRINT_HEADER,
beec0085 107 ACTION_SETUP_KEYS,
a1a03e30
LP
108 ACTION_VERIFY,
109 ACTION_DISK_USAGE,
d4205751 110 ACTION_LIST_CATALOG,
54b7254c 111 ACTION_DUMP_CATALOG,
f1188074
ZJS
112 ACTION_UPDATE_CATALOG,
113 ACTION_LIST_BOOTS,
7560fffc
LP
114} arg_action = ACTION_SHOW;
115
a331b5e6
JJ
116typedef struct boot_id_t {
117 sd_id128_t id;
f1188074
ZJS
118 uint64_t first;
119 uint64_t last;
a331b5e6
JJ
120} boot_id_t;
121
faf5077f
DH
122static void pager_open_if_enabled(void) {
123
124 if (arg_no_pager)
125 return;
126
127 pager_open(arg_pager_end);
128}
129
5ab99e07
LP
130static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
131
132 if (arg_utc)
133 return format_timestamp_utc(buf, l, t);
134
135 return format_timestamp(buf, l, t);
136}
137
442e2def
LP
138static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
139 sd_id128_t id = SD_ID128_NULL;
140 int off = 0, r;
141
142 if (strlen(x) >= 32) {
143 char *t;
144
145 t = strndupa(x, 32);
146 r = sd_id128_from_string(t, &id);
147 if (r >= 0)
148 x += 32;
149
150 if (*x != '-' && *x != '+' && *x != 0)
151 return -EINVAL;
152
153 if (*x != 0) {
154 r = safe_atoi(x, &off);
155 if (r < 0)
156 return r;
157 }
158 } else {
159 r = safe_atoi(x, &off);
160 if (r < 0)
161 return r;
162 }
163
164 if (boot_id)
165 *boot_id = id;
166
167 if (offset)
168 *offset = off;
169
170 return 0;
171}
172
601185b4 173static void help(void) {
0d43c694 174
faf5077f
DH
175 pager_open_if_enabled();
176
cd4b13e0 177 printf("%s [OPTIONS...] [MATCHES...]\n\n"
15119c16
LP
178 "Query the journal.\n\n"
179 "Flags:\n"
eacbb4d3
ZJS
180 " --system Show the system journal\n"
181 " --user Show the user journal for the current user\n"
b6741478 182 " -M --machine=CONTAINER Operate on local container\n"
c736283b
JSJ
183 " --since=DATE Start showing entries on or newer than the specified date\n"
184 " --until=DATE Stop showing entries on or older than the specified date\n"
185 " -c --cursor=CURSOR Start showing entries from the specified cursor\n"
186 " --after-cursor=CURSOR Start showing entries from after the specified cursor\n"
248fc619 187 " --show-cursor Print the cursor after all the entries\n"
c736283b 188 " -b --boot[=ID] Show data only from ID or, if unspecified, the current boot\n"
f1188074 189 " --list-boots Show terse information about recorded boots\n"
c736283b 190 " -k --dmesg Show kernel message log from the current boot\n"
248fc619
ZJS
191 " -u --unit=UNIT Show data only from the specified unit\n"
192 " --user-unit=UNIT Show data only from the specified user session unit\n"
73083640 193 " -t --identifier=STRING Show only messages with the specified syslog identifier\n"
248fc619
ZJS
194 " -p --priority=RANGE Show only messages within the specified priority range\n"
195 " -e --pager-end Immediately jump to end of the journal in the pager\n"
c736283b 196 " -f --follow Follow the journal\n"
248fc619
ZJS
197 " -n --lines[=INTEGER] Number of journal entries to show\n"
198 " --no-tail Show all lines, even in follow mode\n"
199 " -r --reverse Show the newest entries first\n"
f02d8367 200 " -o --output=STRING Change journal output mode (short, short-iso,\n"
c736283b
JSJ
201 " short-precise, short-monotonic, verbose,\n"
202 " export, json, json-pretty, json-sse, cat)\n"
9fd29044 203 " --utc Express time in Coordinated Universal Time (UTC)\n"
248fc619 204 " -x --catalog Add message explanations where available\n"
2b8f6883 205 " --no-full Ellipsize fields\n"
248fc619 206 " -a --all Show all fields, including long and unprintable\n"
c736283b 207 " -q --quiet Do not show privilege warning\n"
248fc619
ZJS
208 " --no-pager Do not pipe output into a pager\n"
209 " -m --merge Show entries from all available journals\n"
210 " -D --directory=PATH Show journal files from directory\n"
211 " --file=PATH Show journal file\n"
212 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
15119c16 213#ifdef HAVE_GCRYPT
248fc619
ZJS
214 " --interval=TIME Time interval for changing the FSS sealing key\n"
215 " --verify-key=KEY Specify FSS verification key\n"
c736283b 216 " --force Force overriding of the FSS key pair with --setup-keys\n"
15119c16
LP
217#endif
218 "\nCommands:\n"
c736283b 219 " -h --help Show this help text\n"
248fc619 220 " --version Show package version\n"
c736283b 221 " --new-id128 Generate a new 128-bit ID\n"
248fc619 222 " --header Show journal header information\n"
c736283b
JSJ
223 " --disk-usage Show total disk usage of all journal files\n"
224 " -F --field=FIELD List all values that a specified field takes\n"
248fc619
ZJS
225 " --list-catalog Show message IDs of all entries in the message catalog\n"
226 " --dump-catalog Show entries in the message catalog\n"
227 " --update-catalog Update the message catalog database\n"
feb12d3e 228#ifdef HAVE_GCRYPT
c736283b 229 " --setup-keys Generate a new FSS key pair\n"
248fc619 230 " --verify Verify journal file consistency\n"
feb12d3e
LP
231#endif
232 , program_invocation_short_name);
0d43c694
LP
233}
234
235static int parse_argv(int argc, char *argv[]) {
236
237 enum {
238 ARG_VERSION = 0x100,
e91af489 239 ARG_NO_PAGER,
2b8f6883 240 ARG_NO_FULL,
55ee336c 241 ARG_NO_TAIL,
dca6219e 242 ARG_NEW_ID128,
f1188074 243 ARG_LIST_BOOTS,
3f3a438f
ZJS
244 ARG_USER,
245 ARG_SYSTEM,
13cbf3a5 246 ARG_ROOT,
7560fffc 247 ARG_HEADER,
beec0085 248 ARG_SETUP_KEYS,
8d98da3f 249 ARG_FILE,
baed47c3 250 ARG_INTERVAL,
4da416aa 251 ARG_VERIFY,
a1a03e30 252 ARG_VERIFY_KEY,
cfbc22ab
LP
253 ARG_DISK_USAGE,
254 ARG_SINCE,
d4205751 255 ARG_UNTIL,
248fc619
ZJS
256 ARG_AFTER_CURSOR,
257 ARG_SHOW_CURSOR,
ffa7cd15 258 ARG_USER_UNIT,
d4205751 259 ARG_LIST_CATALOG,
54b7254c 260 ARG_DUMP_CATALOG,
3f3a438f 261 ARG_UPDATE_CATALOG,
b8547c10 262 ARG_FORCE,
9fd29044 263 ARG_UTC,
0d43c694
LP
264 };
265
266 static const struct option options[] = {
248fc619
ZJS
267 { "help", no_argument, NULL, 'h' },
268 { "version" , no_argument, NULL, ARG_VERSION },
269 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
270 { "pager-end", no_argument, NULL, 'e' },
271 { "follow", no_argument, NULL, 'f' },
272 { "force", no_argument, NULL, ARG_FORCE },
273 { "output", required_argument, NULL, 'o' },
274 { "all", no_argument, NULL, 'a' },
275 { "full", no_argument, NULL, 'l' },
2b8f6883 276 { "no-full", no_argument, NULL, ARG_NO_FULL },
248fc619
ZJS
277 { "lines", optional_argument, NULL, 'n' },
278 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
279 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
280 { "quiet", no_argument, NULL, 'q' },
281 { "merge", no_argument, NULL, 'm' },
282 { "boot", optional_argument, NULL, 'b' },
f1188074 283 { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
248fc619
ZJS
284 { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */
285 { "dmesg", no_argument, NULL, 'k' },
286 { "system", no_argument, NULL, ARG_SYSTEM },
287 { "user", no_argument, NULL, ARG_USER },
288 { "directory", required_argument, NULL, 'D' },
289 { "file", required_argument, NULL, ARG_FILE },
290 { "root", required_argument, NULL, ARG_ROOT },
291 { "header", no_argument, NULL, ARG_HEADER },
73083640 292 { "identifier", required_argument, NULL, 't' },
248fc619
ZJS
293 { "priority", required_argument, NULL, 'p' },
294 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
295 { "interval", required_argument, NULL, ARG_INTERVAL },
296 { "verify", no_argument, NULL, ARG_VERIFY },
297 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
298 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
299 { "cursor", required_argument, NULL, 'c' },
300 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
301 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
302 { "since", required_argument, NULL, ARG_SINCE },
303 { "until", required_argument, NULL, ARG_UNTIL },
304 { "unit", required_argument, NULL, 'u' },
305 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
306 { "field", required_argument, NULL, 'F' },
307 { "catalog", no_argument, NULL, 'x' },
308 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
309 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
310 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
311 { "reverse", no_argument, NULL, 'r' },
b6741478 312 { "machine", required_argument, NULL, 'M' },
9fd29044 313 { "utc", no_argument, NULL, ARG_UTC },
eb9da376 314 {}
0d43c694
LP
315 };
316
2100675e 317 int c, r;
0d43c694
LP
318
319 assert(argc >= 0);
320 assert(argv);
321
73083640 322 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
0d43c694
LP
323
324 switch (c) {
325
326 case 'h':
601185b4
ZJS
327 help();
328 return 0;
0d43c694
LP
329
330 case ARG_VERSION:
331 puts(PACKAGE_STRING);
0d43c694
LP
332 puts(SYSTEMD_FEATURES);
333 return 0;
334
335 case ARG_NO_PAGER:
336 arg_no_pager = true;
337 break;
338
1b12a7b5
HH
339 case 'e':
340 arg_pager_end = true;
fe59e38b 341
48382487 342 if (arg_lines < -1)
fe59e38b
LP
343 arg_lines = 1000;
344
1b12a7b5
HH
345 break;
346
0d43c694
LP
347 case 'f':
348 arg_follow = true;
349 break;
350
351 case 'o':
1705594f 352 arg_output = output_mode_from_string(optarg);
df50185b 353 if (arg_output < 0) {
edfb521a 354 log_error("Unknown output format '%s'.", optarg);
0d43c694
LP
355 return -EINVAL;
356 }
df50185b 357
edfb521a
ZJS
358 if (arg_output == OUTPUT_EXPORT ||
359 arg_output == OUTPUT_JSON ||
360 arg_output == OUTPUT_JSON_PRETTY ||
361 arg_output == OUTPUT_JSON_SSE ||
362 arg_output == OUTPUT_CAT)
363 arg_quiet = true;
364
0d43c694
LP
365 break;
366
98a6e132 367 case 'l':
e3657ecd
ZJS
368 arg_full = true;
369 break;
370
2b8f6883
ZJS
371 case ARG_NO_FULL:
372 arg_full = false;
373 break;
374
0d43c694 375 case 'a':
cd4b13e0 376 arg_all = true;
0d43c694
LP
377 break;
378
2100675e 379 case 'n':
1705594f 380 if (optarg) {
48382487
JJ
381 if (streq(optarg, "all"))
382 arg_lines = -1;
383 else {
384 r = safe_atoi(optarg, &arg_lines);
385 if (r < 0 || arg_lines < 0) {
386 log_error("Failed to parse lines '%s'", optarg);
387 return -EINVAL;
388 }
1705594f 389 }
96088db0 390 } else {
48382487 391 arg_lines = 10;
96088db0
LP
392
393 /* Hmm, no argument? Maybe the next
394 * word on the command line is
395 * supposed to be the argument? Let's
396 * see if there is one, and is
48382487
JJ
397 * parsable. */
398 if (optind < argc) {
399 int n;
400 if (streq(argv[optind], "all")) {
401 arg_lines = -1;
402 optind++;
403 } else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) {
404 arg_lines = n;
405 optind++;
406 }
407 }
96088db0 408 }
1705594f 409
2100675e
LP
410 break;
411
e91af489
LP
412 case ARG_NO_TAIL:
413 arg_no_tail = true;
414 break;
415
39f7f5c1 416 case ARG_NEW_ID128:
7560fffc 417 arg_action = ACTION_NEW_ID128;
55ee336c
LP
418 break;
419
43673799
LP
420 case 'q':
421 arg_quiet = true;
490e567d 422 break;
43673799 423
9e8a535f
LP
424 case 'm':
425 arg_merge = true;
2bd3c38a
LP
426 break;
427
59cea26a 428 case 'b':
d121b396 429 arg_boot = true;
6cebe83c 430
442e2def
LP
431 if (optarg) {
432 r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
433 if (r < 0) {
434 log_error("Failed to parse boot descriptor '%s'", optarg);
435 return -EINVAL;
436 }
437 } else {
6cebe83c 438
442e2def
LP
439 /* Hmm, no argument? Maybe the next
440 * word on the command line is
441 * supposed to be the argument? Let's
442 * see if there is one and is parsable
443 * as a boot descriptor... */
444
445 if (optind < argc &&
446 parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0)
6cebe83c 447 optind++;
6cebe83c 448 }
d121b396 449
59cea26a
LP
450 break;
451
f1188074
ZJS
452 case ARG_LIST_BOOTS:
453 arg_action = ACTION_LIST_BOOTS;
454 break;
455
99271804 456 case 'k':
d121b396 457 arg_boot = arg_dmesg = true;
99271804
ZJS
458 break;
459
3f3a438f
ZJS
460 case ARG_SYSTEM:
461 arg_journal_type |= SD_JOURNAL_SYSTEM;
462 break;
463
464 case ARG_USER:
465 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
466 break;
467
b6741478
LP
468 case 'M':
469 arg_machine = optarg;
470 break;
471
a963990f
LP
472 case 'D':
473 arg_directory = optarg;
474 break;
475
8d98da3f
ZJS
476 case ARG_FILE:
477 r = glob_extend(&arg_file, optarg);
478 if (r < 0) {
479 log_error("Failed to add paths: %s", strerror(-r));
480 return r;
481 };
482 break;
483
13cbf3a5
ZJS
484 case ARG_ROOT:
485 arg_root = optarg;
486 break;
487
8f14c832
LP
488 case 'c':
489 arg_cursor = optarg;
490 break;
491
248fc619
ZJS
492 case ARG_AFTER_CURSOR:
493 arg_after_cursor = optarg;
494 break;
495
496 case ARG_SHOW_CURSOR:
497 arg_show_cursor = true;
498 break;
499
dca6219e 500 case ARG_HEADER:
7560fffc
LP
501 arg_action = ACTION_PRINT_HEADER;
502 break;
503
feb12d3e
LP
504 case ARG_VERIFY:
505 arg_action = ACTION_VERIFY;
506 break;
507
a1a03e30
LP
508 case ARG_DISK_USAGE:
509 arg_action = ACTION_DISK_USAGE;
510 break;
511
feb12d3e 512#ifdef HAVE_GCRYPT
b8547c10
SL
513 case ARG_FORCE:
514 arg_force = true;
515 break;
516
7560fffc
LP
517 case ARG_SETUP_KEYS:
518 arg_action = ACTION_SETUP_KEYS;
dca6219e
LP
519 break;
520
beec0085 521
baed47c3 522 case ARG_VERIFY_KEY:
4da416aa 523 arg_action = ACTION_VERIFY;
baed47c3 524 arg_verify_key = optarg;
9e8a535f 525 arg_merge = false;
4da416aa
LP
526 break;
527
baed47c3 528 case ARG_INTERVAL:
7f602784 529 r = parse_sec(optarg, &arg_interval);
baed47c3
LP
530 if (r < 0 || arg_interval <= 0) {
531 log_error("Failed to parse sealing key change interval: %s", optarg);
14d10188
LP
532 return -EINVAL;
533 }
534 break;
feb12d3e
LP
535#else
536 case ARG_SETUP_KEYS:
537 case ARG_VERIFY_KEY:
538 case ARG_INTERVAL:
b8547c10 539 case ARG_FORCE:
feb12d3e
LP
540 log_error("Forward-secure sealing not available.");
541 return -ENOTSUP;
542#endif
14d10188 543
941e990d
LP
544 case 'p': {
545 const char *dots;
546
547 dots = strstr(optarg, "..");
548 if (dots) {
549 char *a;
550 int from, to, i;
551
552 /* a range */
553 a = strndup(optarg, dots - optarg);
554 if (!a)
555 return log_oom();
556
557 from = log_level_from_string(a);
558 to = log_level_from_string(dots + 2);
559 free(a);
560
561 if (from < 0 || to < 0) {
562 log_error("Failed to parse log level range %s", optarg);
563 return -EINVAL;
564 }
565
566 arg_priorities = 0;
567
568 if (from < to) {
569 for (i = from; i <= to; i++)
570 arg_priorities |= 1 << i;
571 } else {
572 for (i = to; i <= from; i++)
573 arg_priorities |= 1 << i;
574 }
575
576 } else {
577 int p, i;
578
579 p = log_level_from_string(optarg);
580 if (p < 0) {
581 log_error("Unknown log level %s", optarg);
582 return -EINVAL;
583 }
584
585 arg_priorities = 0;
586
587 for (i = 0; i <= p; i++)
588 arg_priorities |= 1 << i;
589 }
590
591 break;
592 }
593
cfbc22ab
LP
594 case ARG_SINCE:
595 r = parse_timestamp(optarg, &arg_since);
596 if (r < 0) {
597 log_error("Failed to parse timestamp: %s", optarg);
598 return -EINVAL;
599 }
600 arg_since_set = true;
601 break;
602
603 case ARG_UNTIL:
604 r = parse_timestamp(optarg, &arg_until);
605 if (r < 0) {
606 log_error("Failed to parse timestamp: %s", optarg);
607 return -EINVAL;
608 }
609 arg_until_set = true;
610 break;
611
73083640
HH
612 case 't':
613 r = strv_extend(&arg_syslog_identifier, optarg);
614 if (r < 0)
615 return log_oom();
616 break;
617
7199aa96 618 case 'u':
b9e40524
HH
619 r = strv_extend(&arg_system_units, optarg);
620 if (r < 0)
621 return log_oom();
ffa7cd15
DW
622 break;
623
7199aa96 624 case ARG_USER_UNIT:
b9e40524
HH
625 r = strv_extend(&arg_user_units, optarg);
626 if (r < 0)
627 return log_oom();
c3f60ec5
LP
628 break;
629
15119c16
LP
630 case 'F':
631 arg_field = optarg;
632 break;
633
d4205751
LP
634 case 'x':
635 arg_catalog = true;
636 break;
637
638 case ARG_LIST_CATALOG:
639 arg_action = ACTION_LIST_CATALOG;
640 break;
641
54b7254c
ZJS
642 case ARG_DUMP_CATALOG:
643 arg_action = ACTION_DUMP_CATALOG;
644 break;
645
d4205751
LP
646 case ARG_UPDATE_CATALOG:
647 arg_action = ACTION_UPDATE_CATALOG;
648 break;
649
d89d6c86
LN
650 case 'r':
651 arg_reverse = true;
652 break;
653
9fd29044
JS
654 case ARG_UTC:
655 arg_utc = true;
656 break;
657
eb9da376 658 case '?':
0d43c694 659 return -EINVAL;
eb9da376
LP
660
661 default:
662 assert_not_reached("Unhandled option");
0d43c694 663 }
0d43c694 664
48382487 665 if (arg_follow && !arg_no_tail && arg_lines < -1)
e91af489
LP
666 arg_lines = 10;
667
b6741478
LP
668 if (!!arg_directory + !!arg_file + !!arg_machine > 1) {
669 log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one.");
8d98da3f
ZJS
670 return -EINVAL;
671 }
672
3ba09ee8 673 if (arg_since_set && arg_until_set && arg_since > arg_until) {
cfbc22ab
LP
674 log_error("--since= must be before --until=.");
675 return -EINVAL;
676 }
677
248fc619
ZJS
678 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
679 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
cfbc22ab
LP
680 return -EINVAL;
681 }
682
d89d6c86
LN
683 if (arg_follow && arg_reverse) {
684 log_error("Please specify either --reverse= or --follow=, not both.");
685 return -EINVAL;
686 }
687
0b6b7c20
ZJS
688 if (arg_action != ACTION_SHOW && optind < argc) {
689 log_error("Extraneous arguments starting with '%s'", argv[optind]);
690 return -EINVAL;
691 }
692
0d43c694
LP
693 return 1;
694}
695
39f7f5c1 696static int generate_new_id128(void) {
55ee336c
LP
697 sd_id128_t id;
698 int r;
699 unsigned i;
700
701 r = sd_id128_randomize(&id);
702 if (r < 0) {
703 log_error("Failed to generate ID: %s", strerror(-r));
704 return r;
705 }
706
707 printf("As string:\n"
708 SD_ID128_FORMAT_STR "\n\n"
709 "As UUID:\n"
710 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
711 "As macro:\n"
d489071f 712 "#define MESSAGE_XYZ SD_ID128_MAKE(",
55ee336c
LP
713 SD_ID128_FORMAT_VAL(id),
714 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
715 for (i = 0; i < 16; i++)
716 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
d489071f 717 fputs(")\n\n", stdout);
55ee336c 718
d489071f
ZJS
719 printf("As Python constant:\n"
720 ">>> import uuid\n"
721 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
722 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
723
724 return 0;
725}
726
a963990f
LP
727static int add_matches(sd_journal *j, char **args) {
728 char **i;
4e602943 729 bool have_term = false;
59cea26a 730
a963990f 731 assert(j);
59cea26a 732
a963990f 733 STRV_FOREACH(i, args) {
52aeb63c 734 int r;
59cea26a 735
4e602943
ZJS
736 if (streq(*i, "+")) {
737 if (!have_term)
738 break;
cbdca852 739 r = sd_journal_add_disjunction(j);
4e602943
ZJS
740 have_term = false;
741
742 } else if (path_is_absolute(*i)) {
68fee104 743 _cleanup_free_ char *p, *t = NULL, *t2 = NULL;
e5124088 744 const char *path;
68fee104 745 _cleanup_free_ char *interpreter = NULL;
a963990f 746 struct stat st;
e5124088 747
a963990f
LP
748 p = canonicalize_file_name(*i);
749 path = p ? p : *i;
e5124088
LP
750
751 if (stat(path, &st) < 0) {
e5124088 752 log_error("Couldn't stat file: %m");
a963990f 753 return -errno;
e5124088
LP
754 }
755
68fee104
ZJS
756 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
757 if (executable_is_script(path, &interpreter) > 0) {
758 _cleanup_free_ char *comm;
759
2b6bf07d 760 comm = strndup(basename(path), 15);
68fee104
ZJS
761 if (!comm)
762 return log_oom();
763
764 t = strappend("_COMM=", comm);
765
766 /* Append _EXE only if the interpreter is not a link.
73e231ab 767 Otherwise, it might be outdated often. */
68fee104
ZJS
768 if (lstat(interpreter, &st) == 0 &&
769 !S_ISLNK(st.st_mode)) {
770 t2 = strappend("_EXE=", interpreter);
771 if (!t2)
772 return log_oom();
773 }
774 } else
775 t = strappend("_EXE=", path);
7de80bfe
KZ
776 } else if (S_ISCHR(st.st_mode)) {
777 if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u",
778 major(st.st_rdev),
779 minor(st.st_rdev)) < 0)
780 return -ENOMEM;
781 } else if (S_ISBLK(st.st_mode)) {
782 if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u",
783 major(st.st_rdev),
784 minor(st.st_rdev)) < 0)
785 return -ENOMEM;
786 } else {
fb93cf73 787 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
a963990f 788 return -EINVAL;
50940700 789 }
e5124088 790
b6a34514
LP
791 if (!t)
792 return log_oom();
793
794 r = sd_journal_add_match(j, t, 0);
68fee104
ZJS
795 if (t2)
796 r = sd_journal_add_match(j, t2, 0);
4e602943
ZJS
797 have_term = true;
798
799 } else {
cbdca852 800 r = sd_journal_add_match(j, *i, 0);
4e602943
ZJS
801 have_term = true;
802 }
e5124088 803
de7b95cd 804 if (r < 0) {
cbdca852 805 log_error("Failed to add match '%s': %s", *i, strerror(-r));
a963990f 806 return r;
de7b95cd
LP
807 }
808 }
809
4e602943
ZJS
810 if (!strv_isempty(args) && !have_term) {
811 log_error("\"+\" can only be used between terms");
812 return -EINVAL;
813 }
814
a963990f
LP
815 return 0;
816}
817
a331b5e6
JJ
818static int boot_id_cmp(const void *a, const void *b) {
819 uint64_t _a, _b;
820
f1188074
ZJS
821 _a = ((const boot_id_t *)a)->first;
822 _b = ((const boot_id_t *)b)->first;
a331b5e6
JJ
823
824 return _a < _b ? -1 : (_a > _b ? 1 : 0);
825}
826
f1188074
ZJS
827static int list_boots(sd_journal *j) {
828 int r;
829 const void *data;
830 unsigned int count = 0;
831 int w, i;
832 size_t length, allocated = 0;
833 boot_id_t *id;
834 _cleanup_free_ boot_id_t *all_ids = NULL;
835
836 r = sd_journal_query_unique(j, "_BOOT_ID");
837 if (r < 0)
838 return r;
839
840 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
841 if (length < strlen("_BOOT_ID="))
842 continue;
843
844 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
845 return log_oom();
846
847 id = &all_ids[count];
848
849 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
850 if (r < 0)
851 continue;
852
853 r = sd_journal_add_match(j, data, length);
854 if (r < 0)
855 return r;
856
857 r = sd_journal_seek_head(j);
858 if (r < 0)
859 return r;
860
861 r = sd_journal_next(j);
862 if (r < 0)
863 return r;
864 else if (r == 0)
865 goto flush;
866
867 r = sd_journal_get_realtime_usec(j, &id->first);
868 if (r < 0)
869 return r;
870
871 r = sd_journal_seek_tail(j);
872 if (r < 0)
873 return r;
874
875 r = sd_journal_previous(j);
876 if (r < 0)
877 return r;
878 else if (r == 0)
879 goto flush;
880
881 r = sd_journal_get_realtime_usec(j, &id->last);
882 if (r < 0)
883 return r;
884
885 count++;
886 flush:
887 sd_journal_flush_matches(j);
888 }
889
890 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
891
892 /* numbers are one less, but we need an extra char for the sign */
893 w = DECIMAL_STR_WIDTH(count - 1) + 1;
894
895 for (id = all_ids, i = 0; id < all_ids + count; id++, i++) {
896 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
897
898 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
899 w, i - count + 1,
900 SD_ID128_FORMAT_VAL(id->id),
5ab99e07
LP
901 format_timestamp_maybe_utc(a, sizeof(a), id->first),
902 format_timestamp_maybe_utc(b, sizeof(b), id->last));
f1188074
ZJS
903 }
904
905 return 0;
906}
907
a331b5e6
JJ
908static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
909 int r;
910 const void *data;
d121b396 911 unsigned int count = 0;
a331b5e6 912 size_t length, allocated = 0;
d121b396 913 boot_id_t ref_boot_id = {SD_ID128_NULL}, *id;
a331b5e6 914 _cleanup_free_ boot_id_t *all_ids = NULL;
a331b5e6
JJ
915
916 assert(j);
917 assert(boot_id);
918
a331b5e6
JJ
919 r = sd_journal_query_unique(j, "_BOOT_ID");
920 if (r < 0)
921 return r;
922
923 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
924 if (length < strlen("_BOOT_ID="))
925 continue;
926
d121b396 927 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
a331b5e6
JJ
928 return log_oom();
929
d121b396 930 id = &all_ids[count];
a331b5e6
JJ
931
932 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
d121b396 933 if (r < 0)
a331b5e6 934 continue;
a331b5e6 935
a331b5e6
JJ
936 r = sd_journal_add_match(j, data, length);
937 if (r < 0)
d121b396 938 return r;
a331b5e6
JJ
939
940 r = sd_journal_seek_head(j);
941 if (r < 0)
d121b396 942 return r;
a331b5e6
JJ
943
944 r = sd_journal_next(j);
d121b396
ZJS
945 if (r < 0)
946 return r;
947 else if (r == 0)
948 goto flush;
a331b5e6 949
f1188074 950 r = sd_journal_get_realtime_usec(j, &id->first);
a331b5e6 951 if (r < 0)
d121b396 952 return r;
a331b5e6 953
d121b396 954 if (sd_id128_equal(id->id, *boot_id))
a331b5e6 955 ref_boot_id = *id;
a331b5e6 956
d121b396
ZJS
957 count++;
958 flush:
959 sd_journal_flush_matches(j);
a331b5e6
JJ
960 }
961
7ff7394d 962 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
a331b5e6 963
d121b396
ZJS
964 if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
965 if (relative > (int) count || relative <= -(int)count)
966 return -EADDRNOTAVAIL;
a331b5e6 967
d121b396
ZJS
968 *boot_id = all_ids[(relative <= 0)*count + relative - 1].id;
969 } else {
970 id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp);
a331b5e6 971
d121b396
ZJS
972 if (!id ||
973 relative <= 0 ? (id - all_ids) + relative < 0 :
a54e3b3d 974 (id - all_ids) + relative >= (int) count)
d121b396
ZJS
975 return -EADDRNOTAVAIL;
976
977 *boot_id = (id + relative)->id;
978 }
a963990f 979
a331b5e6
JJ
980 return 0;
981}
982
983static int add_boot(sd_journal *j) {
984 char match[9+32+1] = "_BOOT_ID=";
442e2def 985 int r;
a331b5e6
JJ
986
987 assert(j);
988
d121b396 989 if (!arg_boot)
a331b5e6
JJ
990 return 0;
991
442e2def 992 if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
b6741478 993 return add_match_this_boot(j, arg_machine);
a331b5e6 994
442e2def 995 r = get_relative_boot_id(j, &arg_boot_id, arg_boot_offset);
a331b5e6 996 if (r < 0) {
442e2def
LP
997 if (sd_id128_equal(arg_boot_id, SD_ID128_NULL))
998 log_error("Failed to look up boot %+i: %s", arg_boot_offset, strerror(-r));
d121b396 999 else
442e2def
LP
1000 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
1001 SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r));
a331b5e6 1002 return r;
a331b5e6
JJ
1003 }
1004
442e2def 1005 sd_id128_to_string(arg_boot_id, match + 9);
d121b396
ZJS
1006
1007 r = sd_journal_add_match(j, match, sizeof(match) - 1);
a331b5e6
JJ
1008 if (r < 0) {
1009 log_error("Failed to add match: %s", strerror(-r));
1010 return r;
1011 }
1012
1013 r = sd_journal_add_conjunction(j);
1014 if (r < 0)
1015 return r;
1016
1017 return 0;
a963990f
LP
1018}
1019
99271804
ZJS
1020static int add_dmesg(sd_journal *j) {
1021 int r;
1022 assert(j);
1023
1024 if (!arg_dmesg)
1025 return 0;
1026
1027 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
1028 if (r < 0) {
1029 log_error("Failed to add match: %s", strerror(-r));
1030 return r;
1031 }
1032
1033 r = sd_journal_add_conjunction(j);
1034 if (r < 0)
1035 return r;
1036
1037 return 0;
1038}
1039
ea18a4b5
ZJS
1040static int get_possible_units(sd_journal *j,
1041 const char *fields,
1042 char **patterns,
1043 Set **units) {
1044 _cleanup_set_free_free_ Set *found;
1045 const char *field;
c3f60ec5 1046 int r;
ea18a4b5 1047
d5099efc 1048 found = set_new(&string_hash_ops);
ea18a4b5
ZJS
1049 if (!found)
1050 return log_oom();
1051
1052 NULSTR_FOREACH(field, fields) {
1053 const void *data;
1054 size_t size;
1055
1056 r = sd_journal_query_unique(j, field);
1057 if (r < 0)
1058 return r;
1059
1060 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1061 char **pattern, *eq;
1062 size_t prefix;
1063 _cleanup_free_ char *u = NULL;
1064
1065 eq = memchr(data, '=', size);
1066 if (eq)
1067 prefix = eq - (char*) data + 1;
1068 else
1069 prefix = 0;
1070
1071 u = strndup((char*) data + prefix, size - prefix);
1072 if (!u)
1073 return log_oom();
1074
1075 STRV_FOREACH(pattern, patterns)
1076 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1077 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1078
1079 r = set_consume(found, u);
1080 u = NULL;
1081 if (r < 0 && r != -EEXIST)
1082 return r;
1083
1084 break;
1085 }
1086 }
1087 }
1088
1089 *units = found;
1090 found = NULL;
1091 return 0;
1092}
1093
1094/* This list is supposed to return the superset of unit names
1095 * possibly matched by rules added with add_matches_for_unit... */
1096#define SYSTEM_UNITS \
1097 "_SYSTEMD_UNIT\0" \
1098 "COREDUMP_UNIT\0" \
1099 "UNIT\0" \
1100 "OBJECT_SYSTEMD_UNIT\0" \
1101 "_SYSTEMD_SLICE\0"
1102
1103/* ... and add_matches_for_user_unit */
1104#define USER_UNITS \
1105 "_SYSTEMD_USER_UNIT\0" \
1106 "USER_UNIT\0" \
1107 "COREDUMP_USER_UNIT\0" \
1108 "OBJECT_SYSTEMD_USER_UNIT\0"
1109
1110static int add_units(sd_journal *j) {
1111 _cleanup_strv_free_ char **patterns = NULL;
1112 int r, count = 0;
b9e40524 1113 char **i;
c3f60ec5
LP
1114
1115 assert(j);
1116
b9e40524 1117 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1118 _cleanup_free_ char *u = NULL;
1119
1120 u = unit_name_mangle(*i, MANGLE_GLOB);
b9e40524
HH
1121 if (!u)
1122 return log_oom();
ea18a4b5
ZJS
1123
1124 if (string_is_glob(u)) {
1125 r = strv_push(&patterns, u);
1126 if (r < 0)
1127 return r;
1128 u = NULL;
1129 } else {
1130 r = add_matches_for_unit(j, u);
1131 if (r < 0)
1132 return r;
1133 r = sd_journal_add_disjunction(j);
1134 if (r < 0)
1135 return r;
1136 count ++;
1137 }
1138 }
1139
1140 if (!strv_isempty(patterns)) {
1141 _cleanup_set_free_free_ Set *units = NULL;
1142 Iterator it;
1143 char *u;
1144
1145 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1146 if (r < 0)
1147 return r;
ea18a4b5
ZJS
1148
1149 SET_FOREACH(u, units, it) {
1150 r = add_matches_for_unit(j, u);
1151 if (r < 0)
1152 return r;
1153 r = sd_journal_add_disjunction(j);
1154 if (r < 0)
1155 return r;
1156 count ++;
1157 }
b9e40524 1158 }
c3f60ec5 1159
ea18a4b5
ZJS
1160 strv_free(patterns);
1161 patterns = NULL;
1162
b9e40524 1163 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1164 _cleanup_free_ char *u = NULL;
1165
1166 u = unit_name_mangle(*i, MANGLE_GLOB);
b9e40524
HH
1167 if (!u)
1168 return log_oom();
c3f60ec5 1169
ea18a4b5
ZJS
1170 if (string_is_glob(u)) {
1171 r = strv_push(&patterns, u);
1172 if (r < 0)
1173 return r;
1174 u = NULL;
1175 } else {
1176 r = add_matches_for_user_unit(j, u, getuid());
1177 if (r < 0)
1178 return r;
1179 r = sd_journal_add_disjunction(j);
1180 if (r < 0)
1181 return r;
1182 count ++;
1183 }
1184 }
1185
1186 if (!strv_isempty(patterns)) {
1187 _cleanup_set_free_free_ Set *units = NULL;
1188 Iterator it;
1189 char *u;
b9e40524 1190
ea18a4b5 1191 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1192 if (r < 0)
1193 return r;
1194
ea18a4b5
ZJS
1195 SET_FOREACH(u, units, it) {
1196 r = add_matches_for_user_unit(j, u, getuid());
1197 if (r < 0)
1198 return r;
1199 r = sd_journal_add_disjunction(j);
1200 if (r < 0)
1201 return r;
1202 count ++;
1203 }
b9e40524 1204 }
c3f60ec5 1205
ea18a4b5
ZJS
1206 /* Complain if the user request matches but nothing whatsoever was
1207 * found, since otherwise everything would be matched. */
1208 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1209 return -ENODATA;
1210
cd34b3c6
HH
1211 r = sd_journal_add_conjunction(j);
1212 if (r < 0)
1213 return r;
1214
c3f60ec5
LP
1215 return 0;
1216}
1217
941e990d
LP
1218static int add_priorities(sd_journal *j) {
1219 char match[] = "PRIORITY=0";
1220 int i, r;
941e990d
LP
1221 assert(j);
1222
1223 if (arg_priorities == 0xFF)
1224 return 0;
1225
1226 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1227 if (arg_priorities & (1 << i)) {
1228 match[sizeof(match)-2] = '0' + i;
1229
941e990d
LP
1230 r = sd_journal_add_match(j, match, strlen(match));
1231 if (r < 0) {
1232 log_error("Failed to add match: %s", strerror(-r));
1233 return r;
1234 }
1235 }
1236
cd34b3c6
HH
1237 r = sd_journal_add_conjunction(j);
1238 if (r < 0)
1239 return r;
1240
941e990d
LP
1241 return 0;
1242}
1243
73083640
HH
1244
1245static int add_syslog_identifier(sd_journal *j) {
1246 int r;
1247 char **i;
1248
1249 assert(j);
1250
1251 STRV_FOREACH(i, arg_syslog_identifier) {
1252 char *u;
1253
1254 u = strappenda("SYSLOG_IDENTIFIER=", *i);
1255 r = sd_journal_add_match(j, u, 0);
1256 if (r < 0)
1257 return r;
1258 r = sd_journal_add_disjunction(j);
1259 if (r < 0)
1260 return r;
1261 }
1262
1263 r = sd_journal_add_conjunction(j);
1264 if (r < 0)
1265 return r;
1266
1267 return 0;
1268}
1269
7560fffc
LP
1270static int setup_keys(void) {
1271#ifdef HAVE_GCRYPT
1272 size_t mpk_size, seed_size, state_size, i;
1273 uint8_t *mpk, *seed, *state;
1274 ssize_t l;
f982e6f7 1275 int fd = -1, r, attr = 0;
7560fffc
LP
1276 sd_id128_t machine, boot;
1277 char *p = NULL, *k = NULL;
baed47c3 1278 struct FSSHeader h;
14d10188 1279 uint64_t n;
b98e3866
SL
1280 struct stat st;
1281
1282 r = stat("/var/log/journal", &st);
1283 if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
1284 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
1285 return -errno;
1286 }
1287
1288 if (r < 0 || !S_ISDIR(st.st_mode)) {
1289 log_error("%s is not a directory, must be using persistent logging for FSS.",
1290 "/var/log/journal");
1291 return r < 0 ? -errno : -ENOTDIR;
1292 }
7560fffc
LP
1293
1294 r = sd_id128_get_machine(&machine);
1295 if (r < 0) {
1296 log_error("Failed to get machine ID: %s", strerror(-r));
1297 return r;
1298 }
1299
1300 r = sd_id128_get_boot(&boot);
1301 if (r < 0) {
1302 log_error("Failed to get boot ID: %s", strerror(-r));
1303 return r;
1304 }
1305
baed47c3 1306 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1307 SD_ID128_FORMAT_VAL(machine)) < 0)
1308 return log_oom();
1309
1310 if (access(p, F_OK) >= 0) {
b8547c10
SL
1311 if (arg_force) {
1312 r = unlink(p);
1313 if (r < 0) {
1314 log_error("unlink(\"%s\") failed: %m", p);
1315 r = -errno;
1316 goto finish;
1317 }
1318 } else {
1319 log_error("Sealing key file %s exists already. (--force to recreate)", p);
1320 r = -EEXIST;
1321 goto finish;
1322 }
7560fffc
LP
1323 }
1324
baed47c3 1325 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1326 SD_ID128_FORMAT_VAL(machine)) < 0) {
1327 r = log_oom();
1328 goto finish;
1329 }
1330
1331 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1332 mpk = alloca(mpk_size);
1333
1334 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1335 seed = alloca(seed_size);
1336
1337 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1338 state = alloca(state_size);
1339
1340 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1341 if (fd < 0) {
1342 log_error("Failed to open /dev/random: %m");
1343 r = -errno;
1344 goto finish;
1345 }
1346
1347 log_info("Generating seed...");
1348 l = loop_read(fd, seed, seed_size, true);
1349 if (l < 0 || (size_t) l != seed_size) {
1350 log_error("Failed to read random seed: %s", strerror(EIO));
1351 r = -EIO;
1352 goto finish;
1353 }
1354
1355 log_info("Generating key pair...");
1356 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1357
baed47c3 1358 log_info("Generating sealing key...");
7560fffc
LP
1359 FSPRG_GenState0(state, mpk, seed, seed_size);
1360
baed47c3
LP
1361 assert(arg_interval > 0);
1362
7560fffc 1363 n = now(CLOCK_REALTIME);
baed47c3 1364 n /= arg_interval;
7560fffc 1365
03e334a1 1366 safe_close(fd);
2d5bdf5b 1367 fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
7560fffc
LP
1368 if (fd < 0) {
1369 log_error("Failed to open %s: %m", k);
1370 r = -errno;
1371 goto finish;
1372 }
1373
f982e6f7
LP
1374 /* Enable secure remove, exclusion from dump, synchronous
1375 * writing and in-place updating */
1376 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
1377 log_warning("FS_IOC_GETFLAGS failed: %m");
1378
1379 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
1380
1381 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
1382 log_warning("FS_IOC_SETFLAGS failed: %m");
1383
7560fffc
LP
1384 zero(h);
1385 memcpy(h.signature, "KSHHRHLP", 8);
1386 h.machine_id = machine;
1387 h.boot_id = boot;
1388 h.header_size = htole64(sizeof(h));
baed47c3
LP
1389 h.start_usec = htole64(n * arg_interval);
1390 h.interval_usec = htole64(arg_interval);
1391 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1392 h.fsprg_state_size = htole64(state_size);
7560fffc
LP
1393
1394 l = loop_write(fd, &h, sizeof(h), false);
1395 if (l < 0 || (size_t) l != sizeof(h)) {
1396 log_error("Failed to write header: %s", strerror(EIO));
1397 r = -EIO;
1398 goto finish;
1399 }
1400
1401 l = loop_write(fd, state, state_size, false);
1402 if (l < 0 || (size_t) l != state_size) {
1403 log_error("Failed to write state: %s", strerror(EIO));
1404 r = -EIO;
1405 goto finish;
1406 }
1407
1408 if (link(k, p) < 0) {
1409 log_error("Failed to link file: %m");
1410 r = -errno;
1411 goto finish;
1412 }
1413
8481248b 1414 if (on_tty()) {
7560fffc
LP
1415 fprintf(stderr,
1416 "\n"
baed47c3 1417 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
c05276f2
LP
1418 "the following local file. This key file is automatically updated when the\n"
1419 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1420 "\n"
1421 "\t%s\n"
1422 "\n"
baed47c3
LP
1423 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1424 "at a safe location and should not be saved locally on disk.\n"
7560fffc
LP
1425 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1426 fflush(stderr);
1427 }
1428 for (i = 0; i < seed_size; i++) {
1429 if (i > 0 && i % 3 == 0)
1430 putchar('-');
1431 printf("%02x", ((uint8_t*) seed)[i]);
1432 }
1433
baed47c3
LP
1434 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1435
8481248b 1436 if (on_tty()) {
f6a971bc 1437 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1438
baed47c3
LP
1439 fprintf(stderr,
1440 ANSI_HIGHLIGHT_OFF "\n"
1441 "The sealing key is automatically changed every %s.\n",
2fa4092c 1442 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1443
1444 hn = gethostname_malloc();
1445
1446 if (hn) {
e724b063 1447 hostname_cleanup(hn, false);
adac1c93 1448 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1449 } else
adac1c93 1450 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc
LP
1451
1452#ifdef HAVE_QRENCODE
cf5a3432 1453 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1454 if (is_locale_utf8()) {
cf5a3432
LP
1455 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1456 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1457 }
f6a971bc
LP
1458#endif
1459 free(hn);
baed47c3 1460 }
7560fffc
LP
1461
1462 r = 0;
1463
1464finish:
03e334a1 1465 safe_close(fd);
7560fffc
LP
1466
1467 if (k) {
1468 unlink(k);
1469 free(k);
1470 }
1471
1472 free(p);
1473
1474 return r;
1475#else
feb12d3e
LP
1476 log_error("Forward-secure sealing not available.");
1477 return -ENOTSUP;
7560fffc
LP
1478#endif
1479}
1480
beec0085
LP
1481static int verify(sd_journal *j) {
1482 int r = 0;
1483 Iterator i;
1484 JournalFile *f;
1485
1486 assert(j);
1487
cedb42bb
LP
1488 log_show_color(true);
1489
beec0085
LP
1490 HASHMAP_FOREACH(f, j->files, i) {
1491 int k;
2a7b539a 1492 usec_t first, validated, last;
beec0085 1493
56e81f7c 1494#ifdef HAVE_GCRYPT
feb12d3e 1495 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1496 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1497#endif
4da416aa 1498
2a7b539a 1499 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1500 if (k == -EINVAL) {
baed47c3 1501 /* If the key was invalid give up right-away. */
56e81f7c
LP
1502 return k;
1503 } else if (k < 0) {
beec0085 1504 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
56e81f7c 1505 r = k;
6c7be122
LP
1506 } else {
1507 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1508 log_info("PASS: %s", f->path);
6c7be122 1509
c0ca7aee 1510 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1511 if (validated > 0) {
c0ca7aee 1512 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1513 format_timestamp_maybe_utc(a, sizeof(a), first),
1514 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1515 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1516 } else if (last > 0)
c0ca7aee 1517 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1518 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1519 else
1520 log_info("=> No sealing yet, no entries in file.");
1521 }
6c7be122 1522 }
beec0085
LP
1523 }
1524
1525 return r;
1526}
1527
15804ceb 1528#ifdef HAVE_ACL
6fe391c5
ZJS
1529static int access_check_var_log_journal(sd_journal *j) {
1530 _cleanup_strv_free_ char **g = NULL;
1531 bool have_access;
1532 int r;
1533
1534 assert(j);
1535
1536 have_access = in_group("systemd-journal") > 0;
1537
1538 if (!have_access) {
1539 /* Let's enumerate all groups from the default ACL of
1540 * the directory, which generally should allow access
1541 * to most journal files too */
1542 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
1543 if (r < 0)
1544 return r;
15804ceb
LP
1545 }
1546
6fe391c5 1547 if (!have_access) {
4468addc 1548
6fe391c5 1549 if (strv_isempty(g))
3ac251b8
LP
1550 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1551 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1552 " turn off this notice.");
6fe391c5
ZJS
1553 else {
1554 _cleanup_free_ char *s = NULL;
4468addc 1555
6fe391c5 1556 r = strv_extend(&g, "systemd-journal");
478c8269 1557 if (r < 0)
6fe391c5
ZJS
1558 return log_oom();
1559
1560 strv_sort(g);
1561 strv_uniq(g);
1562
1563 s = strv_join(g, "', '");
1564 if (!s)
1565 return log_oom();
1566
1567 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
3ac251b8
LP
1568 " Users in the groups '%s' can see all messages.\n"
1569 " Pass -q to turn off this notice.", s);
4468addc 1570 }
6fe391c5 1571 }
4468addc 1572
6fe391c5
ZJS
1573 return 0;
1574}
1575#endif
4468addc 1576
6fe391c5 1577static int access_check(sd_journal *j) {
6fe391c5 1578 Iterator it;
3ac251b8 1579 void *code;
6fe391c5 1580 int r = 0;
4468addc 1581
6fe391c5 1582 assert(j);
4468addc 1583
6fe391c5
ZJS
1584 if (set_isempty(j->errors)) {
1585 if (hashmap_isempty(j->files))
3ac251b8 1586 log_notice("No journal files were found.");
6fe391c5
ZJS
1587 return 0;
1588 }
4468addc 1589
3ac251b8 1590 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
6fe391c5
ZJS
1591#ifdef HAVE_ACL
1592 /* If /var/log/journal doesn't even exist,
3ac251b8 1593 * unprivileged users have no access at all */
6fe391c5
ZJS
1594 if (access("/var/log/journal", F_OK) < 0 &&
1595 geteuid() != 0 &&
1596 in_group("systemd-journal") <= 0) {
3ac251b8
LP
1597 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1598 "enabled. Users in the 'systemd-journal' group may always access messages.");
6fe391c5
ZJS
1599 return -EACCES;
1600 }
4468addc 1601
6fe391c5
ZJS
1602 /* If /var/log/journal exists, try to pring a nice
1603 notice if the user lacks access to it */
1604 if (!arg_quiet && geteuid() != 0) {
1605 r = access_check_var_log_journal(j);
1606 if (r < 0)
1607 return r;
4468addc 1608 }
15804ceb 1609#else
3ac251b8
LP
1610 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1611 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1612 "group may access messages.");
1613 return -EACCES;
1614 }
15804ceb 1615#endif
3ac251b8 1616
6fe391c5 1617 if (hashmap_isempty(j->files)) {
3ac251b8 1618 log_error("No journal files were opened due to insufficient permissions.");
6fe391c5
ZJS
1619 r = -EACCES;
1620 }
1621 }
15804ceb 1622
6fe391c5 1623 SET_FOREACH(code, j->errors, it) {
3ac251b8
LP
1624 int err;
1625
1626 err = -PTR_TO_INT(code);
6fe391c5 1627 assert(err > 0);
3ac251b8 1628
6fe391c5
ZJS
1629 if (err != EACCES)
1630 log_warning("Error was encountered while opening journal files: %s",
1631 strerror(err));
1632 }
1633
6fe391c5 1634 return r;
15804ceb
LP
1635}
1636
a963990f
LP
1637int main(int argc, char *argv[]) {
1638 int r;
289f910e 1639 _cleanup_journal_close_ sd_journal *j = NULL;
a963990f 1640 bool need_seek = false;
14a65d65 1641 sd_id128_t previous_boot_id;
67e04a48
ZJS
1642 bool previous_boot_id_valid = false, first_line = true;
1643 int n_shown = 0;
94e0bd7d 1644 bool ellipsized = false;
a963990f 1645
a9cdc94f 1646 setlocale(LC_ALL, "");
a963990f
LP
1647 log_parse_environment();
1648 log_open();
1649
1650 r = parse_argv(argc, argv);
1651 if (r <= 0)
1652 goto finish;
1653
ed757c0c
LP
1654 signal(SIGWINCH, columns_lines_cache_reset);
1655
7560fffc 1656 if (arg_action == ACTION_NEW_ID128) {
a963990f
LP
1657 r = generate_new_id128();
1658 goto finish;
1659 }
1660
7560fffc
LP
1661 if (arg_action == ACTION_SETUP_KEYS) {
1662 r = setup_keys();
1663 goto finish;
1664 }
1665
844ec79b
ZJS
1666 if (arg_action == ACTION_UPDATE_CATALOG ||
1667 arg_action == ACTION_LIST_CATALOG ||
1668 arg_action == ACTION_DUMP_CATALOG) {
1669
0c6ea3a4
ZJS
1670 _cleanup_free_ char *database;
1671
1672 database = path_join(arg_root, CATALOG_DATABASE, NULL);
1673 if (!database) {
1674 r = log_oom();
1675 goto finish;
13cbf3a5
ZJS
1676 }
1677
844ec79b 1678 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 1679 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b
ZJS
1680 if (r < 0)
1681 log_error("Failed to list catalog: %s", strerror(-r));
1682 } else {
1683 bool oneline = arg_action == ACTION_LIST_CATALOG;
1684
1685 if (optind < argc)
13cbf3a5 1686 r = catalog_list_items(stdout, database,
844ec79b
ZJS
1687 oneline, argv + optind);
1688 else
13cbf3a5 1689 r = catalog_list(stdout, database, oneline);
844ec79b
ZJS
1690 if (r < 0)
1691 log_error("Failed to list catalog: %s", strerror(-r));
1692 }
d4205751 1693
d4205751
LP
1694 goto finish;
1695 }
1696
a963990f 1697 if (arg_directory)
3f3a438f 1698 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
8d98da3f
ZJS
1699 else if (arg_file)
1700 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
b6741478
LP
1701 else if (arg_machine)
1702 r = sd_journal_open_container(&j, arg_machine, 0);
a963990f 1703 else
3f3a438f 1704 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 1705 if (r < 0) {
8d98da3f
ZJS
1706 log_error("Failed to open %s: %s",
1707 arg_directory ? arg_directory : arg_file ? "files" : "journal",
1708 strerror(-r));
763c7aa2 1709 return EXIT_FAILURE;
a963990f
LP
1710 }
1711
6fe391c5
ZJS
1712 r = access_check(j);
1713 if (r < 0)
1714 return EXIT_FAILURE;
1715
beec0085
LP
1716 if (arg_action == ACTION_VERIFY) {
1717 r = verify(j);
1718 goto finish;
1719 }
1720
7560fffc 1721 if (arg_action == ACTION_PRINT_HEADER) {
dca6219e 1722 journal_print_header(j);
763c7aa2 1723 return EXIT_SUCCESS;
dca6219e
LP
1724 }
1725
a1a03e30 1726 if (arg_action == ACTION_DISK_USAGE) {
39883f62 1727 uint64_t bytes = 0;
a1a03e30
LP
1728 char sbytes[FORMAT_BYTES_MAX];
1729
1730 r = sd_journal_get_usage(j, &bytes);
1731 if (r < 0)
763c7aa2 1732 return EXIT_FAILURE;
a1a03e30 1733
763c7aa2
ZJS
1734 printf("Journals take up %s on disk.\n",
1735 format_bytes(sbytes, sizeof(sbytes), bytes));
1736 return EXIT_SUCCESS;
a1a03e30
LP
1737 }
1738
f1188074
ZJS
1739 if (arg_action == ACTION_LIST_BOOTS) {
1740 r = list_boots(j);
1741 goto finish;
1742 }
1743
a331b5e6
JJ
1744 /* add_boot() must be called first!
1745 * It may need to seek the journal to find parent boot IDs. */
1746 r = add_boot(j);
a963990f 1747 if (r < 0)
763c7aa2 1748 return EXIT_FAILURE;
a963990f 1749
99271804
ZJS
1750 r = add_dmesg(j);
1751 if (r < 0)
1752 return EXIT_FAILURE;
1753
b9e40524
HH
1754 r = add_units(j);
1755 strv_free(arg_system_units);
1756 strv_free(arg_user_units);
1757
ea18a4b5
ZJS
1758 if (r < 0) {
1759 log_error("Failed to add filter for units: %s", strerror(-r));
763c7aa2 1760 return EXIT_FAILURE;
ea18a4b5 1761 }
c3f60ec5 1762
73083640
HH
1763 r = add_syslog_identifier(j);
1764 if (r < 0) {
1765 log_error("Failed to add filter for syslog identifiers: %s", strerror(-r));
1766 return EXIT_FAILURE;
1767 }
1768
cd34b3c6 1769 r = add_priorities(j);
ea18a4b5
ZJS
1770 if (r < 0) {
1771 log_error("Failed to add filter for priorities: %s", strerror(-r));
763c7aa2 1772 return EXIT_FAILURE;
ea18a4b5 1773 }
a963990f 1774
cd34b3c6 1775 r = add_matches(j, argv + optind);
ea18a4b5
ZJS
1776 if (r < 0) {
1777 log_error("Failed to add filters: %s", strerror(-r));
763c7aa2 1778 return EXIT_FAILURE;
ea18a4b5 1779 }
941e990d 1780
4ad16808
ZJS
1781 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1782 _cleanup_free_ char *filter;
1783
1784 filter = journal_make_match_string(j);
1785 log_debug("Journal filter: %s", filter);
1786 }
67e04a48 1787
15119c16
LP
1788 if (arg_field) {
1789 const void *data;
1790 size_t size;
1791
21ae4593
ZJS
1792 r = sd_journal_set_data_threshold(j, 0);
1793 if (r < 0) {
1794 log_error("Failed to unset data size threshold");
1795 return EXIT_FAILURE;
1796 }
1797
15119c16
LP
1798 r = sd_journal_query_unique(j, arg_field);
1799 if (r < 0) {
1800 log_error("Failed to query unique data objects: %s", strerror(-r));
763c7aa2 1801 return EXIT_FAILURE;
15119c16
LP
1802 }
1803
1804 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1805 const void *eq;
1806
67e04a48 1807 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
1808 break;
1809
15119c16
LP
1810 eq = memchr(data, '=', size);
1811 if (eq)
1812 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1813 else
1814 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875
LP
1815
1816 n_shown ++;
15119c16
LP
1817 }
1818
763c7aa2 1819 return EXIT_SUCCESS;
15119c16
LP
1820 }
1821
8d98da3f
ZJS
1822 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1823 if (arg_follow) {
1824 r = sd_journal_get_fd(j);
1825 if (r < 0)
1826 return EXIT_FAILURE;
1827 }
1828
248fc619 1829 if (arg_cursor || arg_after_cursor) {
eacbb4d3 1830 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
08984293 1831 if (r < 0) {
cfbc22ab 1832 log_error("Failed to seek to cursor: %s", strerror(-r));
763c7aa2 1833 return EXIT_FAILURE;
08984293 1834 }
d89d6c86 1835 if (!arg_reverse)
248fc619 1836 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
d89d6c86 1837 else
248fc619
ZJS
1838 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
1839
1840 if (arg_after_cursor && r < 2 && !arg_follow)
1841 /* We couldn't find the next entry after the cursor. */
1842 arg_lines = 0;
08984293 1843
d89d6c86 1844 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 1845 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 1846 if (r < 0) {
cfbc22ab 1847 log_error("Failed to seek to date: %s", strerror(-r));
763c7aa2 1848 return EXIT_FAILURE;
8f14c832 1849 }
8f14c832
LP
1850 r = sd_journal_next(j);
1851
d89d6c86
LN
1852 } else if (arg_until_set && arg_reverse) {
1853 r = sd_journal_seek_realtime_usec(j, arg_until);
1854 if (r < 0) {
1855 log_error("Failed to seek to date: %s", strerror(-r));
763c7aa2 1856 return EXIT_FAILURE;
d89d6c86
LN
1857 }
1858 r = sd_journal_previous(j);
1859
67e04a48 1860 } else if (arg_lines >= 0) {
2100675e
LP
1861 r = sd_journal_seek_tail(j);
1862 if (r < 0) {
1863 log_error("Failed to seek to tail: %s", strerror(-r));
763c7aa2 1864 return EXIT_FAILURE;
2100675e
LP
1865 }
1866
1867 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 1868
d89d6c86
LN
1869 } else if (arg_reverse) {
1870 r = sd_journal_seek_tail(j);
1871 if (r < 0) {
1872 log_error("Failed to seek to tail: %s", strerror(-r));
763c7aa2 1873 return EXIT_FAILURE;
d89d6c86
LN
1874 }
1875
1876 r = sd_journal_previous(j);
1877
2100675e
LP
1878 } else {
1879 r = sd_journal_seek_head(j);
1880 if (r < 0) {
1881 log_error("Failed to seek to head: %s", strerror(-r));
763c7aa2 1882 return EXIT_FAILURE;
2100675e 1883 }
6f003b43
LP
1884
1885 r = sd_journal_next(j);
1886 }
1887
1888 if (r < 0) {
1889 log_error("Failed to iterate through journal: %s", strerror(-r));
763c7aa2 1890 return EXIT_FAILURE;
50f20cfd 1891 }
87d2c1ff 1892
faf5077f
DH
1893 if (!arg_follow)
1894 pager_open_if_enabled();
0d43c694 1895
cfbc22ab
LP
1896 if (!arg_quiet) {
1897 usec_t start, end;
1898 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1899
1900 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1901 if (r < 0) {
1902 log_error("Failed to get cutoff: %s", strerror(-r));
1903 goto finish;
1904 }
1905
1906 if (r > 0) {
1907 if (arg_follow)
9048b11f 1908 printf("-- Logs begin at %s. --\n",
5ab99e07 1909 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 1910 else
9048b11f 1911 printf("-- Logs begin at %s, end at %s. --\n",
5ab99e07
LP
1912 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
1913 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
1914 }
1915 }
1916
50f20cfd 1917 for (;;) {
67e04a48 1918 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab
LP
1919 int flags;
1920
6f003b43 1921 if (need_seek) {
99613ec5 1922 if (!arg_reverse)
d89d6c86
LN
1923 r = sd_journal_next(j);
1924 else
1925 r = sd_journal_previous(j);
6f003b43
LP
1926 if (r < 0) {
1927 log_error("Failed to iterate through journal: %s", strerror(-r));
1928 goto finish;
1929 }
a72b6353
ZJS
1930 if (r == 0)
1931 break;
0d43c694
LP
1932 }
1933
d89d6c86 1934 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
1935 usec_t usec;
1936
1937 r = sd_journal_get_realtime_usec(j, &usec);
1938 if (r < 0) {
1939 log_error("Failed to determine timestamp: %s", strerror(-r));
1940 goto finish;
1941 }
3ba09ee8
PF
1942 if (usec > arg_until)
1943 goto finish;
cfbc22ab
LP
1944 }
1945
d89d6c86
LN
1946 if (arg_since_set && arg_reverse) {
1947 usec_t usec;
1948
1949 r = sd_journal_get_realtime_usec(j, &usec);
1950 if (r < 0) {
1951 log_error("Failed to determine timestamp: %s", strerror(-r));
1952 goto finish;
1953 }
1954 if (usec < arg_since)
1955 goto finish;
1956 }
1957
4bed2485 1958 if (!arg_merge && !arg_quiet) {
cd931c0a 1959 sd_id128_t boot_id;
14a65d65 1960
cd931c0a
LP
1961 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1962 if (r >= 0) {
1963 if (previous_boot_id_valid &&
1964 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c
DS
1965 printf("%s-- Reboot --%s\n",
1966 ansi_highlight(), ansi_highlight_off());
cd931c0a
LP
1967
1968 previous_boot_id = boot_id;
1969 previous_boot_id_valid = true;
1970 }
14a65d65
LP
1971 }
1972
cfbc22ab 1973 flags =
cd4b13e0 1974 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 1975 arg_full * OUTPUT_FULL_WIDTH |
d4205751 1976 on_tty() * OUTPUT_COLOR |
9fd29044
JS
1977 arg_catalog * OUTPUT_CATALOG |
1978 arg_utc * OUTPUT_UTC;
cfbc22ab 1979
94e0bd7d 1980 r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
a72b6353
ZJS
1981 need_seek = true;
1982 if (r == -EADDRNOTAVAIL)
1983 break;
1984 else if (r < 0 || ferror(stdout))
72f59706 1985 goto finish;
6f003b43 1986
cfbc22ab 1987 n_shown++;
87d2c1ff
LP
1988 }
1989
248fc619
ZJS
1990 if (!arg_follow) {
1991 if (arg_show_cursor) {
1992 _cleanup_free_ char *cursor = NULL;
1993
1994 r = sd_journal_get_cursor(j, &cursor);
1995 if (r < 0 && r != -EADDRNOTAVAIL)
1996 log_error("Failed to get cursor: %s", strerror(-r));
1997 else if (r >= 0)
1998 printf("-- cursor: %s\n", cursor);
1999 }
2000
50f20cfd 2001 break;
248fc619 2002 }
50f20cfd 2003
e02d1cf7 2004 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 2005 if (r < 0) {
7a69007a 2006 log_error("Couldn't wait for journal event: %s", strerror(-r));
50f20cfd
LP
2007 goto finish;
2008 }
67e04a48
ZJS
2009
2010 first_line = false;
de190aef 2011 }
87d2c1ff
LP
2012
2013finish:
0d43c694
LP
2014 pager_close();
2015
a36b8deb
ZJS
2016 strv_free(arg_file);
2017
3fbf9cbb 2018 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2019}