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