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