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