]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
journalctl: lstat() should suffice if we call canonicalize_file_name() first
[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
a331b5e6
JJ
128typedef struct boot_id_t {
129 sd_id128_t id;
f1188074
ZJS
130 uint64_t first;
131 uint64_t last;
596a2329 132 LIST_FIELDS(struct boot_id_t, boot_list);
a331b5e6
JJ
133} boot_id_t;
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
596a2329
JJ
861static int discover_next_boot(sd_journal *j,
862 boot_id_t **boot,
863 bool advance_older,
864 bool read_realtime) {
f1188074 865 int r;
596a2329
JJ
866 char match[9+32+1] = "_BOOT_ID=";
867 _cleanup_free_ boot_id_t *next_boot = NULL;
ea7061e4
JJ
868
869 assert(j);
596a2329
JJ
870 assert(boot);
871
872 /* We expect the journal to be on the last position of a boot
873 * (in relation to the direction we are going), so that the next
874 * invocation of sd_journal_next/previous will be from a different
875 * boot. We then collect any information we desire and then jump
876 * to the last location of the new boot by using a _BOOT_ID match
877 * coming from the other journal direction. */
878
879 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
880 * we can actually advance to a *different* boot. */
881 sd_journal_flush_matches(j);
882
883 if (advance_older)
884 r = sd_journal_previous(j);
885 else
886 r = sd_journal_next(j);
887 if (r < 0)
888 return r;
889 else if (r == 0)
890 return 0; /* End of journal, yay. */
891
892 next_boot = new0(boot_id_t, 1);
893 if (!next_boot)
894 return log_oom();
f1188074 895
596a2329 896 r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id);
f1188074
ZJS
897 if (r < 0)
898 return r;
899
596a2329
JJ
900 if (read_realtime) {
901 r = sd_journal_get_realtime_usec(j, &next_boot->first);
902 if (r < 0)
903 return r;
904 }
ea7061e4 905
596a2329
JJ
906 /* Now seek to the last occurrence of this boot ID. */
907 sd_id128_to_string(next_boot->id, match + 9);
908 r = sd_journal_add_match(j, match, sizeof(match) - 1);
909 if (r < 0)
910 return r;
f1188074 911
596a2329
JJ
912 if (advance_older)
913 r = sd_journal_seek_head(j);
914 else
915 r = sd_journal_seek_tail(j);
916 if (r < 0)
917 return r;
f1188074 918
596a2329
JJ
919 if (advance_older)
920 r = sd_journal_next(j);
921 else
922 r = sd_journal_previous(j);
923 if (r < 0)
924 return r;
925 else if (r == 0)
926 return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */
f1188074 927
596a2329
JJ
928 if (read_realtime) {
929 r = sd_journal_get_realtime_usec(j, &next_boot->last);
f1188074 930 if (r < 0)
596a2329
JJ
931 return r;
932 }
933
934 *boot = next_boot;
935 next_boot = NULL;
936 return 0;
937}
938
939static int get_boots(sd_journal *j,
940 boot_id_t **boots,
941 boot_id_t *query_ref_boot,
942 int ref_boot_offset) {
943 bool skip_once;
944 int r, count = 0;
945 boot_id_t *head = NULL, *tail = NULL;
946 const bool advance_older = query_ref_boot && ref_boot_offset <= 0;
947
948 assert(j);
f1188074 949
596a2329
JJ
950 /* Adjust for the asymmetry that offset 0 is
951 * the last (and current) boot, while 1 is considered the
952 * (chronological) first boot in the journal. */
953 skip_once = query_ref_boot && sd_id128_is_null(query_ref_boot->id) && ref_boot_offset < 0;
954
955 /* Advance to the earliest/latest occurrence of our reference
956 * boot ID (taking our lookup direction into account), so that
957 * discover_next_boot() can do its job.
958 * If no reference is given, the journal head/tail will do,
959 * they're "virtual" boots after all. */
960 if (query_ref_boot && !sd_id128_is_null(query_ref_boot->id)) {
961 char match[9+32+1] = "_BOOT_ID=";
962
963 sd_journal_flush_matches(j);
964
965 sd_id128_to_string(query_ref_boot->id, match + 9);
966 r = sd_journal_add_match(j, match, sizeof(match) - 1);
f1188074
ZJS
967 if (r < 0)
968 return r;
969
596a2329
JJ
970 if (advance_older)
971 r = sd_journal_seek_head(j);
972 else
973 r = sd_journal_seek_tail(j);
f1188074
ZJS
974 if (r < 0)
975 return r;
976
596a2329
JJ
977 if (advance_older)
978 r = sd_journal_next(j);
979 else
980 r = sd_journal_previous(j);
f1188074
ZJS
981 if (r < 0)
982 return r;
983 else if (r == 0)
596a2329
JJ
984 goto finish;
985 else if (ref_boot_offset == 0) {
986 count = 1;
987 goto finish;
988 }
989 } else {
990 if (advance_older)
991 r = sd_journal_seek_tail(j);
992 else
993 r = sd_journal_seek_head(j);
f1188074
ZJS
994 if (r < 0)
995 return r;
996
596a2329
JJ
997 /* No sd_journal_next/previous here. */
998 }
f1188074 999
596a2329
JJ
1000 while (true) {
1001 _cleanup_free_ boot_id_t *current = NULL;
f1188074 1002
596a2329
JJ
1003 r = discover_next_boot(j, &current, advance_older, !query_ref_boot);
1004 if (r < 0) {
1005 boot_id_t *id, *id_next;
1006 LIST_FOREACH_SAFE(boot_list, id, id_next, head)
1007 free(id);
1008 return r;
ea7061e4 1009 }
f1188074 1010
596a2329
JJ
1011 if (!current)
1012 break;
1013
1014 if (query_ref_boot) {
1015 if (!skip_once)
1016 ref_boot_offset += advance_older ? 1 : -1;
1017 skip_once = false;
1018
1019 if (ref_boot_offset == 0) {
1020 count = 1;
1021 query_ref_boot->id = current->id;
1022 break;
1023 }
1024 } else {
1025 LIST_INSERT_AFTER(boot_list, head, tail, current);
1026 tail = current;
1027 current = NULL;
1028 count++;
1029 }
f1188074
ZJS
1030 }
1031
596a2329
JJ
1032finish:
1033 if (boots)
1034 *boots = head;
1035
1036 sd_journal_flush_matches(j);
1037
1038 return count;
ea7061e4
JJ
1039}
1040
1041static int list_boots(sd_journal *j) {
596a2329
JJ
1042 int w, i, count;
1043 boot_id_t *id, *id_next, *all_ids;
ea7061e4
JJ
1044
1045 assert(j);
1046
596a2329
JJ
1047 count = get_boots(j, &all_ids, NULL, 0);
1048 if (count <= 0)
1049 return count;
ea7061e4
JJ
1050
1051 pager_open_if_enabled();
f1188074
ZJS
1052
1053 /* numbers are one less, but we need an extra char for the sign */
1054 w = DECIMAL_STR_WIDTH(count - 1) + 1;
1055
596a2329
JJ
1056 i = 0;
1057 LIST_FOREACH_SAFE(boot_list, id, id_next, all_ids) {
f1188074
ZJS
1058 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
1059
1060 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
1061 w, i - count + 1,
1062 SD_ID128_FORMAT_VAL(id->id),
5ab99e07
LP
1063 format_timestamp_maybe_utc(a, sizeof(a), id->first),
1064 format_timestamp_maybe_utc(b, sizeof(b), id->last));
596a2329
JJ
1065 i++;
1066 free(id);
d121b396 1067 }
a963990f 1068
a331b5e6
JJ
1069 return 0;
1070}
1071
1072static int add_boot(sd_journal *j) {
1073 char match[9+32+1] = "_BOOT_ID=";
442e2def 1074 int r;
596a2329 1075 boot_id_t ref_boot_id = {};
a331b5e6
JJ
1076
1077 assert(j);
1078
d121b396 1079 if (!arg_boot)
a331b5e6
JJ
1080 return 0;
1081
442e2def 1082 if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
b6741478 1083 return add_match_this_boot(j, arg_machine);
a331b5e6 1084
596a2329
JJ
1085 ref_boot_id.id = arg_boot_id;
1086 r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset);
1087 assert(r <= 1);
1088 if (r <= 0) {
1089 const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r);
1090
1091 if (sd_id128_is_null(arg_boot_id))
1092 log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason);
d121b396 1093 else
442e2def 1094 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
596a2329
JJ
1095 SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason);
1096
1097 return r == 0 ? -ENODATA : r;
a331b5e6
JJ
1098 }
1099
596a2329 1100 sd_id128_to_string(ref_boot_id.id, match + 9);
d121b396
ZJS
1101
1102 r = sd_journal_add_match(j, match, sizeof(match) - 1);
23bbb0de
MS
1103 if (r < 0)
1104 return log_error_errno(r, "Failed to add match: %m");
a331b5e6
JJ
1105
1106 r = sd_journal_add_conjunction(j);
1107 if (r < 0)
1108 return r;
1109
1110 return 0;
a963990f
LP
1111}
1112
99271804
ZJS
1113static int add_dmesg(sd_journal *j) {
1114 int r;
1115 assert(j);
1116
1117 if (!arg_dmesg)
1118 return 0;
1119
1120 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
23bbb0de
MS
1121 if (r < 0)
1122 return log_error_errno(r, "Failed to add match: %m");
99271804
ZJS
1123
1124 r = sd_journal_add_conjunction(j);
1125 if (r < 0)
1126 return r;
1127
1128 return 0;
1129}
1130
ea18a4b5
ZJS
1131static int get_possible_units(sd_journal *j,
1132 const char *fields,
1133 char **patterns,
1134 Set **units) {
1135 _cleanup_set_free_free_ Set *found;
1136 const char *field;
c3f60ec5 1137 int r;
ea18a4b5 1138
d5099efc 1139 found = set_new(&string_hash_ops);
ea18a4b5
ZJS
1140 if (!found)
1141 return log_oom();
1142
1143 NULSTR_FOREACH(field, fields) {
1144 const void *data;
1145 size_t size;
1146
1147 r = sd_journal_query_unique(j, field);
1148 if (r < 0)
1149 return r;
1150
1151 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1152 char **pattern, *eq;
1153 size_t prefix;
1154 _cleanup_free_ char *u = NULL;
1155
1156 eq = memchr(data, '=', size);
1157 if (eq)
1158 prefix = eq - (char*) data + 1;
1159 else
1160 prefix = 0;
1161
1162 u = strndup((char*) data + prefix, size - prefix);
1163 if (!u)
1164 return log_oom();
1165
1166 STRV_FOREACH(pattern, patterns)
1167 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1168 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1169
1170 r = set_consume(found, u);
1171 u = NULL;
1172 if (r < 0 && r != -EEXIST)
1173 return r;
1174
1175 break;
1176 }
1177 }
1178 }
1179
1180 *units = found;
1181 found = NULL;
1182 return 0;
1183}
1184
1185/* This list is supposed to return the superset of unit names
1186 * possibly matched by rules added with add_matches_for_unit... */
1187#define SYSTEM_UNITS \
1188 "_SYSTEMD_UNIT\0" \
1189 "COREDUMP_UNIT\0" \
1190 "UNIT\0" \
1191 "OBJECT_SYSTEMD_UNIT\0" \
1192 "_SYSTEMD_SLICE\0"
1193
1194/* ... and add_matches_for_user_unit */
1195#define USER_UNITS \
1196 "_SYSTEMD_USER_UNIT\0" \
1197 "USER_UNIT\0" \
1198 "COREDUMP_USER_UNIT\0" \
1199 "OBJECT_SYSTEMD_USER_UNIT\0"
1200
1201static int add_units(sd_journal *j) {
1202 _cleanup_strv_free_ char **patterns = NULL;
1203 int r, count = 0;
b9e40524 1204 char **i;
c3f60ec5
LP
1205
1206 assert(j);
1207
b9e40524 1208 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1209 _cleanup_free_ char *u = NULL;
1210
7410616c
LP
1211 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1212 if (r < 0)
1213 return r;
ea18a4b5
ZJS
1214
1215 if (string_is_glob(u)) {
1216 r = strv_push(&patterns, u);
1217 if (r < 0)
1218 return r;
1219 u = NULL;
1220 } else {
1221 r = add_matches_for_unit(j, u);
1222 if (r < 0)
1223 return r;
1224 r = sd_journal_add_disjunction(j);
1225 if (r < 0)
1226 return r;
1227 count ++;
1228 }
1229 }
1230
1231 if (!strv_isempty(patterns)) {
1232 _cleanup_set_free_free_ Set *units = NULL;
1233 Iterator it;
1234 char *u;
1235
1236 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1237 if (r < 0)
1238 return r;
ea18a4b5
ZJS
1239
1240 SET_FOREACH(u, units, it) {
1241 r = add_matches_for_unit(j, u);
1242 if (r < 0)
1243 return r;
1244 r = sd_journal_add_disjunction(j);
1245 if (r < 0)
1246 return r;
1247 count ++;
1248 }
b9e40524 1249 }
c3f60ec5 1250
ea18a4b5
ZJS
1251 strv_free(patterns);
1252 patterns = NULL;
1253
b9e40524 1254 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1255 _cleanup_free_ char *u = NULL;
1256
7410616c
LP
1257 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1258 if (r < 0)
1259 return r;
c3f60ec5 1260
ea18a4b5
ZJS
1261 if (string_is_glob(u)) {
1262 r = strv_push(&patterns, u);
1263 if (r < 0)
1264 return r;
1265 u = NULL;
1266 } else {
1267 r = add_matches_for_user_unit(j, u, getuid());
1268 if (r < 0)
1269 return r;
1270 r = sd_journal_add_disjunction(j);
1271 if (r < 0)
1272 return r;
1273 count ++;
1274 }
1275 }
1276
1277 if (!strv_isempty(patterns)) {
1278 _cleanup_set_free_free_ Set *units = NULL;
1279 Iterator it;
1280 char *u;
b9e40524 1281
ea18a4b5 1282 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1283 if (r < 0)
1284 return r;
1285
ea18a4b5
ZJS
1286 SET_FOREACH(u, units, it) {
1287 r = add_matches_for_user_unit(j, u, getuid());
1288 if (r < 0)
1289 return r;
1290 r = sd_journal_add_disjunction(j);
1291 if (r < 0)
1292 return r;
1293 count ++;
1294 }
b9e40524 1295 }
c3f60ec5 1296
ea18a4b5
ZJS
1297 /* Complain if the user request matches but nothing whatsoever was
1298 * found, since otherwise everything would be matched. */
1299 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1300 return -ENODATA;
1301
cd34b3c6
HH
1302 r = sd_journal_add_conjunction(j);
1303 if (r < 0)
1304 return r;
1305
c3f60ec5
LP
1306 return 0;
1307}
1308
941e990d
LP
1309static int add_priorities(sd_journal *j) {
1310 char match[] = "PRIORITY=0";
1311 int i, r;
941e990d
LP
1312 assert(j);
1313
1314 if (arg_priorities == 0xFF)
1315 return 0;
1316
1317 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1318 if (arg_priorities & (1 << i)) {
1319 match[sizeof(match)-2] = '0' + i;
1320
941e990d 1321 r = sd_journal_add_match(j, match, strlen(match));
23bbb0de
MS
1322 if (r < 0)
1323 return log_error_errno(r, "Failed to add match: %m");
941e990d
LP
1324 }
1325
cd34b3c6
HH
1326 r = sd_journal_add_conjunction(j);
1327 if (r < 0)
1328 return r;
1329
941e990d
LP
1330 return 0;
1331}
1332
73083640
HH
1333
1334static int add_syslog_identifier(sd_journal *j) {
1335 int r;
1336 char **i;
1337
1338 assert(j);
1339
1340 STRV_FOREACH(i, arg_syslog_identifier) {
1341 char *u;
1342
63c372cb 1343 u = strjoina("SYSLOG_IDENTIFIER=", *i);
73083640
HH
1344 r = sd_journal_add_match(j, u, 0);
1345 if (r < 0)
1346 return r;
1347 r = sd_journal_add_disjunction(j);
1348 if (r < 0)
1349 return r;
1350 }
1351
1352 r = sd_journal_add_conjunction(j);
1353 if (r < 0)
1354 return r;
1355
1356 return 0;
1357}
1358
7560fffc
LP
1359static int setup_keys(void) {
1360#ifdef HAVE_GCRYPT
1361 size_t mpk_size, seed_size, state_size, i;
1362 uint8_t *mpk, *seed, *state;
11689d2a 1363 int fd = -1, r;
7560fffc
LP
1364 sd_id128_t machine, boot;
1365 char *p = NULL, *k = NULL;
baed47c3 1366 struct FSSHeader h;
14d10188 1367 uint64_t n;
b98e3866
SL
1368 struct stat st;
1369
1370 r = stat("/var/log/journal", &st);
4a62c710
MS
1371 if (r < 0 && errno != ENOENT && errno != ENOTDIR)
1372 return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
b98e3866
SL
1373
1374 if (r < 0 || !S_ISDIR(st.st_mode)) {
1375 log_error("%s is not a directory, must be using persistent logging for FSS.",
1376 "/var/log/journal");
1377 return r < 0 ? -errno : -ENOTDIR;
1378 }
7560fffc
LP
1379
1380 r = sd_id128_get_machine(&machine);
23bbb0de
MS
1381 if (r < 0)
1382 return log_error_errno(r, "Failed to get machine ID: %m");
7560fffc
LP
1383
1384 r = sd_id128_get_boot(&boot);
23bbb0de
MS
1385 if (r < 0)
1386 return log_error_errno(r, "Failed to get boot ID: %m");
7560fffc 1387
baed47c3 1388 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1389 SD_ID128_FORMAT_VAL(machine)) < 0)
1390 return log_oom();
1391
faf9da01
ZJS
1392 if (arg_force) {
1393 r = unlink(p);
1394 if (r < 0 && errno != ENOENT) {
1395 r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
b8547c10
SL
1396 goto finish;
1397 }
faf9da01
ZJS
1398 } else if (access(p, F_OK) >= 0) {
1399 log_error("Sealing key file %s exists already. Use --force to recreate.", p);
1400 r = -EEXIST;
1401 goto finish;
7560fffc
LP
1402 }
1403
baed47c3 1404 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1405 SD_ID128_FORMAT_VAL(machine)) < 0) {
1406 r = log_oom();
1407 goto finish;
1408 }
1409
1410 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1411 mpk = alloca(mpk_size);
1412
1413 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1414 seed = alloca(seed_size);
1415
1416 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1417 state = alloca(state_size);
1418
1419 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1420 if (fd < 0) {
56f64d95 1421 log_error_errno(errno, "Failed to open /dev/random: %m");
7560fffc
LP
1422 r = -errno;
1423 goto finish;
1424 }
1425
1426 log_info("Generating seed...");
a6dcc7e5
ZJS
1427 r = loop_read_exact(fd, seed, seed_size, true);
1428 if (r < 0) {
1429 log_error_errno(r, "Failed to read random seed: %m");
7560fffc
LP
1430 goto finish;
1431 }
1432
1433 log_info("Generating key pair...");
1434 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1435
baed47c3 1436 log_info("Generating sealing key...");
7560fffc
LP
1437 FSPRG_GenState0(state, mpk, seed, seed_size);
1438
baed47c3
LP
1439 assert(arg_interval > 0);
1440
7560fffc 1441 n = now(CLOCK_REALTIME);
baed47c3 1442 n /= arg_interval;
7560fffc 1443
03e334a1 1444 safe_close(fd);
2d5bdf5b 1445 fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
7560fffc 1446 if (fd < 0) {
56f64d95 1447 log_error_errno(errno, "Failed to open %s: %m", k);
7560fffc
LP
1448 r = -errno;
1449 goto finish;
1450 }
1451
f982e6f7
LP
1452 /* Enable secure remove, exclusion from dump, synchronous
1453 * writing and in-place updating */
1ed8f8c1 1454 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
1455 if (r < 0)
1456 log_warning_errno(errno, "Failed to set file attributes: %m");
f982e6f7 1457
7560fffc
LP
1458 zero(h);
1459 memcpy(h.signature, "KSHHRHLP", 8);
1460 h.machine_id = machine;
1461 h.boot_id = boot;
1462 h.header_size = htole64(sizeof(h));
baed47c3
LP
1463 h.start_usec = htole64(n * arg_interval);
1464 h.interval_usec = htole64(arg_interval);
1465 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1466 h.fsprg_state_size = htole64(state_size);
7560fffc 1467
553acb7b
ZJS
1468 r = loop_write(fd, &h, sizeof(h), false);
1469 if (r < 0) {
1470 log_error_errno(r, "Failed to write header: %m");
7560fffc
LP
1471 goto finish;
1472 }
1473
553acb7b
ZJS
1474 r = loop_write(fd, state, state_size, false);
1475 if (r < 0) {
1476 log_error_errno(r, "Failed to write state: %m");
7560fffc
LP
1477 goto finish;
1478 }
1479
1480 if (link(k, p) < 0) {
56f64d95 1481 log_error_errno(errno, "Failed to link file: %m");
7560fffc
LP
1482 r = -errno;
1483 goto finish;
1484 }
1485
8481248b 1486 if (on_tty()) {
7560fffc
LP
1487 fprintf(stderr,
1488 "\n"
baed47c3 1489 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
c05276f2
LP
1490 "the following local file. This key file is automatically updated when the\n"
1491 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1492 "\n"
1493 "\t%s\n"
1494 "\n"
baed47c3
LP
1495 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1496 "at a safe location and should not be saved locally on disk.\n"
7560fffc
LP
1497 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1498 fflush(stderr);
1499 }
1500 for (i = 0; i < seed_size; i++) {
1501 if (i > 0 && i % 3 == 0)
1502 putchar('-');
1503 printf("%02x", ((uint8_t*) seed)[i]);
1504 }
1505
baed47c3
LP
1506 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1507
8481248b 1508 if (on_tty()) {
f6a971bc 1509 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1510
baed47c3
LP
1511 fprintf(stderr,
1512 ANSI_HIGHLIGHT_OFF "\n"
1513 "The sealing key is automatically changed every %s.\n",
2fa4092c 1514 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1515
1516 hn = gethostname_malloc();
1517
1518 if (hn) {
e724b063 1519 hostname_cleanup(hn, false);
adac1c93 1520 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1521 } else
adac1c93 1522 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc
LP
1523
1524#ifdef HAVE_QRENCODE
cf5a3432 1525 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1526 if (is_locale_utf8()) {
cf5a3432
LP
1527 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1528 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1529 }
f6a971bc
LP
1530#endif
1531 free(hn);
baed47c3 1532 }
7560fffc
LP
1533
1534 r = 0;
1535
1536finish:
03e334a1 1537 safe_close(fd);
7560fffc
LP
1538
1539 if (k) {
1540 unlink(k);
1541 free(k);
1542 }
1543
1544 free(p);
1545
1546 return r;
1547#else
feb12d3e 1548 log_error("Forward-secure sealing not available.");
15411c0c 1549 return -EOPNOTSUPP;
7560fffc
LP
1550#endif
1551}
1552
beec0085
LP
1553static int verify(sd_journal *j) {
1554 int r = 0;
1555 Iterator i;
1556 JournalFile *f;
1557
1558 assert(j);
1559
cedb42bb
LP
1560 log_show_color(true);
1561
c1f906bd 1562 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
beec0085 1563 int k;
a7f7d1bd 1564 usec_t first = 0, validated = 0, last = 0;
beec0085 1565
56e81f7c 1566#ifdef HAVE_GCRYPT
feb12d3e 1567 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1568 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1569#endif
4da416aa 1570
2a7b539a 1571 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1572 if (k == -EINVAL) {
baed47c3 1573 /* If the key was invalid give up right-away. */
56e81f7c
LP
1574 return k;
1575 } else if (k < 0) {
beec0085 1576 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
56e81f7c 1577 r = k;
6c7be122
LP
1578 } else {
1579 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1580 log_info("PASS: %s", f->path);
6c7be122 1581
c0ca7aee 1582 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1583 if (validated > 0) {
c0ca7aee 1584 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1585 format_timestamp_maybe_utc(a, sizeof(a), first),
1586 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1587 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1588 } else if (last > 0)
c0ca7aee 1589 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1590 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1591 else
1592 log_info("=> No sealing yet, no entries in file.");
1593 }
6c7be122 1594 }
beec0085
LP
1595 }
1596
1597 return r;
1598}
1599
6fe391c5 1600static int access_check_var_log_journal(sd_journal *j) {
e346512c 1601#ifdef HAVE_ACL
6fe391c5 1602 _cleanup_strv_free_ char **g = NULL;
e346512c
LP
1603 const char* dir;
1604#endif
6fe391c5
ZJS
1605 int r;
1606
1607 assert(j);
1608
e346512c
LP
1609 if (arg_quiet)
1610 return 0;
05c18530 1611
e346512c
LP
1612 /* If we are root, we should have access, don't warn. */
1613 if (getuid() == 0)
1614 return 0;
05c18530 1615
e346512c
LP
1616 /* If we are in the 'systemd-journal' group, we should have
1617 * access too. */
1618 r = in_group("systemd-journal");
1619 if (r < 0)
1620 return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m");
1621 if (r > 0)
1622 return 0;
15804ceb 1623
e346512c
LP
1624#ifdef HAVE_ACL
1625 if (laccess("/run/log/journal", F_OK) >= 0)
1626 dir = "/run/log/journal";
1627 else
1628 dir = "/var/log/journal";
1629
1630 /* If we are in any of the groups listed in the journal ACLs,
1631 * then all is good, too. Let's enumerate all groups from the
1632 * default ACL of the directory, which generally should allow
1633 * access to most journal files too. */
1634 r = acl_search_groups(dir, &g);
1635 if (r < 0)
1636 return log_error_errno(r, "Failed to search journal ACL: %m");
1637 if (r > 0)
1638 return 0;
4468addc 1639
e346512c
LP
1640 /* Print a pretty list, if there were ACLs set. */
1641 if (!strv_isempty(g)) {
1642 _cleanup_free_ char *s = NULL;
4468addc 1643
e346512c
LP
1644 /* Thre are groups in the ACL, let's list them */
1645 r = strv_extend(&g, "systemd-journal");
1646 if (r < 0)
1647 return log_oom();
6fe391c5 1648
e346512c
LP
1649 strv_sort(g);
1650 strv_uniq(g);
6fe391c5 1651
e346512c
LP
1652 s = strv_join(g, "', '");
1653 if (!s)
1654 return log_oom();
6fe391c5 1655
e346512c
LP
1656 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1657 " Users in groups '%s' can see all messages.\n"
1658 " Pass -q to turn off this notice.", s);
1659 return 1;
6fe391c5 1660 }
e346512c 1661#endif
4468addc 1662
e346512c
LP
1663 /* If no ACLs were found, print a short version of the message. */
1664 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1665 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1666 " turn off this notice.");
1667
1668 return 1;
6fe391c5 1669}
4468addc 1670
6fe391c5 1671static int access_check(sd_journal *j) {
6fe391c5 1672 Iterator it;
3ac251b8 1673 void *code;
6fe391c5 1674 int r = 0;
4468addc 1675
6fe391c5 1676 assert(j);
4468addc 1677
6fe391c5 1678 if (set_isempty(j->errors)) {
c1f906bd 1679 if (ordered_hashmap_isempty(j->files))
3ac251b8 1680 log_notice("No journal files were found.");
e346512c 1681
6fe391c5
ZJS
1682 return 0;
1683 }
4468addc 1684
3ac251b8 1685 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
e346512c 1686 (void) access_check_var_log_journal(j);
3ac251b8 1687
e346512c
LP
1688 if (ordered_hashmap_isempty(j->files))
1689 r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
6fe391c5 1690 }
15804ceb 1691
6fe391c5 1692 SET_FOREACH(code, j->errors, it) {
3ac251b8
LP
1693 int err;
1694
1695 err = -PTR_TO_INT(code);
6fe391c5 1696 assert(err > 0);
3ac251b8 1697
e346512c
LP
1698 if (err == EACCES)
1699 continue;
1700
1701 log_warning_errno(err, "Error was encountered while opening journal files: %m");
1702 if (r == 0)
1703 r = -err;
6fe391c5
ZJS
1704 }
1705
6fe391c5 1706 return r;
15804ceb
LP
1707}
1708
74055aa7
LP
1709static int flush_to_var(void) {
1710 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1711 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1712 _cleanup_close_ int watch_fd = -1;
1713 int r;
1714
1715 /* Quick exit */
1716 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1717 return 0;
1718
1719 /* OK, let's actually do the full logic, send SIGUSR1 to the
1720 * daemon and set up inotify to wait for the flushed file to appear */
1721 r = bus_open_system_systemd(&bus);
23bbb0de
MS
1722 if (r < 0)
1723 return log_error_errno(r, "Failed to get D-Bus connection: %m");
74055aa7
LP
1724
1725 r = sd_bus_call_method(
1726 bus,
1727 "org.freedesktop.systemd1",
1728 "/org/freedesktop/systemd1",
1729 "org.freedesktop.systemd1.Manager",
1730 "KillUnit",
1731 &error,
1732 NULL,
1733 "ssi", "systemd-journald.service", "main", SIGUSR1);
1734 if (r < 0) {
1735 log_error("Failed to kill journal service: %s", bus_error_message(&error, r));
1736 return r;
1737 }
1738
1739 mkdir_p("/run/systemd/journal", 0755);
1740
1741 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
4a62c710
MS
1742 if (watch_fd < 0)
1743 return log_error_errno(errno, "Failed to create inotify watch: %m");
74055aa7
LP
1744
1745 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
4a62c710
MS
1746 if (r < 0)
1747 return log_error_errno(errno, "Failed to watch journal directory: %m");
74055aa7
LP
1748
1749 for (;;) {
1750 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1751 break;
1752
4a62c710 1753 if (errno != ENOENT)
f131770b 1754 return log_error_errno(errno, "Failed to check for existence of /run/systemd/journal/flushed: %m");
74055aa7
LP
1755
1756 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
23bbb0de
MS
1757 if (r < 0)
1758 return log_error_errno(r, "Failed to wait for event: %m");
74055aa7
LP
1759
1760 r = flush_fd(watch_fd);
23bbb0de
MS
1761 if (r < 0)
1762 return log_error_errno(r, "Failed to flush inotify events: %m");
74055aa7
LP
1763 }
1764
1765 return 0;
1766}
1767
a963990f
LP
1768int main(int argc, char *argv[]) {
1769 int r;
289f910e 1770 _cleanup_journal_close_ sd_journal *j = NULL;
a963990f 1771 bool need_seek = false;
14a65d65 1772 sd_id128_t previous_boot_id;
67e04a48
ZJS
1773 bool previous_boot_id_valid = false, first_line = true;
1774 int n_shown = 0;
94e0bd7d 1775 bool ellipsized = false;
a963990f 1776
a9cdc94f 1777 setlocale(LC_ALL, "");
a963990f
LP
1778 log_parse_environment();
1779 log_open();
1780
1781 r = parse_argv(argc, argv);
1782 if (r <= 0)
1783 goto finish;
1784
ed757c0c 1785 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 1786 sigbus_install();
ed757c0c 1787
de45d726
LP
1788 /* Increase max number of open files to 16K if we can, we
1789 * might needs this when browsing journal files, which might
1790 * be split up into many files. */
1791 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
1792
7560fffc 1793 if (arg_action == ACTION_NEW_ID128) {
a963990f
LP
1794 r = generate_new_id128();
1795 goto finish;
1796 }
1797
74055aa7
LP
1798 if (arg_action == ACTION_FLUSH) {
1799 r = flush_to_var();
1800 goto finish;
1801 }
1802
7560fffc
LP
1803 if (arg_action == ACTION_SETUP_KEYS) {
1804 r = setup_keys();
1805 goto finish;
1806 }
1807
844ec79b
ZJS
1808 if (arg_action == ACTION_UPDATE_CATALOG ||
1809 arg_action == ACTION_LIST_CATALOG ||
1810 arg_action == ACTION_DUMP_CATALOG) {
1811
0c6ea3a4
ZJS
1812 _cleanup_free_ char *database;
1813
1814 database = path_join(arg_root, CATALOG_DATABASE, NULL);
1815 if (!database) {
1816 r = log_oom();
1817 goto finish;
13cbf3a5
ZJS
1818 }
1819
844ec79b 1820 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 1821 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b 1822 if (r < 0)
da927ba9 1823 log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
1824 } else {
1825 bool oneline = arg_action == ACTION_LIST_CATALOG;
1826
1827 if (optind < argc)
13cbf3a5 1828 r = catalog_list_items(stdout, database,
844ec79b
ZJS
1829 oneline, argv + optind);
1830 else
13cbf3a5 1831 r = catalog_list(stdout, database, oneline);
844ec79b 1832 if (r < 0)
da927ba9 1833 log_error_errno(r, "Failed to list catalog: %m");
844ec79b 1834 }
d4205751 1835
d4205751
LP
1836 goto finish;
1837 }
1838
a963990f 1839 if (arg_directory)
3f3a438f 1840 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
8d98da3f
ZJS
1841 else if (arg_file)
1842 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
b6741478
LP
1843 else if (arg_machine)
1844 r = sd_journal_open_container(&j, arg_machine, 0);
a963990f 1845 else
3f3a438f 1846 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 1847 if (r < 0) {
c33b3297
MS
1848 log_error_errno(r, "Failed to open %s: %m",
1849 arg_directory ? arg_directory : arg_file ? "files" : "journal");
909dea0c 1850 goto finish;
a963990f
LP
1851 }
1852
6fe391c5
ZJS
1853 r = access_check(j);
1854 if (r < 0)
909dea0c 1855 goto finish;
6fe391c5 1856
beec0085
LP
1857 if (arg_action == ACTION_VERIFY) {
1858 r = verify(j);
1859 goto finish;
1860 }
1861
7560fffc 1862 if (arg_action == ACTION_PRINT_HEADER) {
dca6219e 1863 journal_print_header(j);
909dea0c
LP
1864 r = 0;
1865 goto finish;
dca6219e
LP
1866 }
1867
a1a03e30 1868 if (arg_action == ACTION_DISK_USAGE) {
39883f62 1869 uint64_t bytes = 0;
a1a03e30
LP
1870 char sbytes[FORMAT_BYTES_MAX];
1871
1872 r = sd_journal_get_usage(j, &bytes);
1873 if (r < 0)
909dea0c 1874 goto finish;
a1a03e30 1875
dbd2a83f 1876 printf("Archived and active journals take up %s on disk.\n",
763c7aa2 1877 format_bytes(sbytes, sizeof(sbytes), bytes));
909dea0c 1878 goto finish;
a1a03e30
LP
1879 }
1880
dbd2a83f
LP
1881 if (arg_action == ACTION_VACUUM) {
1882 Directory *d;
1883 Iterator i;
1884
1885 HASHMAP_FOREACH(d, j->directories_by_path, i) {
1886 int q;
1887
1888 if (d->is_root)
1889 continue;
1890
1891 q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_time, NULL, true);
1892 if (q < 0) {
da927ba9 1893 log_error_errno(q, "Failed to vacuum: %m");
dbd2a83f
LP
1894 r = q;
1895 }
1896 }
1897
909dea0c 1898 goto finish;
dbd2a83f
LP
1899 }
1900
f1188074
ZJS
1901 if (arg_action == ACTION_LIST_BOOTS) {
1902 r = list_boots(j);
1903 goto finish;
1904 }
1905
a331b5e6
JJ
1906 /* add_boot() must be called first!
1907 * It may need to seek the journal to find parent boot IDs. */
1908 r = add_boot(j);
a963990f 1909 if (r < 0)
909dea0c 1910 goto finish;
a963990f 1911
99271804
ZJS
1912 r = add_dmesg(j);
1913 if (r < 0)
909dea0c 1914 goto finish;
99271804 1915
b9e40524 1916 r = add_units(j);
ea18a4b5 1917 if (r < 0) {
da927ba9 1918 log_error_errno(r, "Failed to add filter for units: %m");
909dea0c 1919 goto finish;
ea18a4b5 1920 }
c3f60ec5 1921
73083640
HH
1922 r = add_syslog_identifier(j);
1923 if (r < 0) {
da927ba9 1924 log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
909dea0c 1925 goto finish;
73083640
HH
1926 }
1927
cd34b3c6 1928 r = add_priorities(j);
ea18a4b5 1929 if (r < 0) {
da927ba9 1930 log_error_errno(r, "Failed to add filter for priorities: %m");
909dea0c 1931 goto finish;
ea18a4b5 1932 }
a963990f 1933
cd34b3c6 1934 r = add_matches(j, argv + optind);
ea18a4b5 1935 if (r < 0) {
da927ba9 1936 log_error_errno(r, "Failed to add filters: %m");
909dea0c 1937 goto finish;
ea18a4b5 1938 }
941e990d 1939
553d2243 1940 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
4ad16808
ZJS
1941 _cleanup_free_ char *filter;
1942
1943 filter = journal_make_match_string(j);
1944 log_debug("Journal filter: %s", filter);
1945 }
67e04a48 1946
15119c16
LP
1947 if (arg_field) {
1948 const void *data;
1949 size_t size;
1950
21ae4593
ZJS
1951 r = sd_journal_set_data_threshold(j, 0);
1952 if (r < 0) {
1953 log_error("Failed to unset data size threshold");
909dea0c 1954 goto finish;
21ae4593
ZJS
1955 }
1956
15119c16
LP
1957 r = sd_journal_query_unique(j, arg_field);
1958 if (r < 0) {
da927ba9 1959 log_error_errno(r, "Failed to query unique data objects: %m");
909dea0c 1960 goto finish;
15119c16
LP
1961 }
1962
1963 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1964 const void *eq;
1965
67e04a48 1966 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
1967 break;
1968
15119c16
LP
1969 eq = memchr(data, '=', size);
1970 if (eq)
1971 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1972 else
1973 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875
LP
1974
1975 n_shown ++;
15119c16
LP
1976 }
1977
909dea0c
LP
1978 r = 0;
1979 goto finish;
15119c16
LP
1980 }
1981
8d98da3f
ZJS
1982 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1983 if (arg_follow) {
1984 r = sd_journal_get_fd(j);
1985 if (r < 0)
909dea0c 1986 goto finish;
8d98da3f
ZJS
1987 }
1988
248fc619 1989 if (arg_cursor || arg_after_cursor) {
eacbb4d3 1990 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
08984293 1991 if (r < 0) {
da927ba9 1992 log_error_errno(r, "Failed to seek to cursor: %m");
909dea0c 1993 goto finish;
08984293 1994 }
909dea0c 1995
d89d6c86 1996 if (!arg_reverse)
248fc619 1997 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
d89d6c86 1998 else
248fc619
ZJS
1999 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
2000
8ee8e536 2001 if (arg_after_cursor && r < 2) {
248fc619 2002 /* We couldn't find the next entry after the cursor. */
8ee8e536
WD
2003 if (arg_follow)
2004 need_seek = true;
2005 else
2006 arg_lines = 0;
2007 }
08984293 2008
d89d6c86 2009 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 2010 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 2011 if (r < 0) {
da927ba9 2012 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2013 goto finish;
8f14c832 2014 }
8f14c832
LP
2015 r = sd_journal_next(j);
2016
d89d6c86
LN
2017 } else if (arg_until_set && arg_reverse) {
2018 r = sd_journal_seek_realtime_usec(j, arg_until);
2019 if (r < 0) {
da927ba9 2020 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2021 goto finish;
d89d6c86
LN
2022 }
2023 r = sd_journal_previous(j);
2024
67e04a48 2025 } else if (arg_lines >= 0) {
2100675e
LP
2026 r = sd_journal_seek_tail(j);
2027 if (r < 0) {
da927ba9 2028 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2029 goto finish;
2100675e
LP
2030 }
2031
2032 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 2033
d89d6c86
LN
2034 } else if (arg_reverse) {
2035 r = sd_journal_seek_tail(j);
2036 if (r < 0) {
da927ba9 2037 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2038 goto finish;
d89d6c86
LN
2039 }
2040
2041 r = sd_journal_previous(j);
2042
2100675e
LP
2043 } else {
2044 r = sd_journal_seek_head(j);
2045 if (r < 0) {
da927ba9 2046 log_error_errno(r, "Failed to seek to head: %m");
909dea0c 2047 goto finish;
2100675e 2048 }
6f003b43
LP
2049
2050 r = sd_journal_next(j);
2051 }
2052
2053 if (r < 0) {
da927ba9 2054 log_error_errno(r, "Failed to iterate through journal: %m");
909dea0c 2055 goto finish;
50f20cfd 2056 }
87d2c1ff 2057
faf5077f
DH
2058 if (!arg_follow)
2059 pager_open_if_enabled();
0d43c694 2060
cfbc22ab
LP
2061 if (!arg_quiet) {
2062 usec_t start, end;
2063 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
2064
2065 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
2066 if (r < 0) {
da927ba9 2067 log_error_errno(r, "Failed to get cutoff: %m");
cfbc22ab
LP
2068 goto finish;
2069 }
2070
2071 if (r > 0) {
2072 if (arg_follow)
9048b11f 2073 printf("-- Logs begin at %s. --\n",
5ab99e07 2074 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2075 else
9048b11f 2076 printf("-- Logs begin at %s, end at %s. --\n",
5ab99e07
LP
2077 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2078 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2079 }
2080 }
2081
50f20cfd 2082 for (;;) {
67e04a48 2083 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab
LP
2084 int flags;
2085
6f003b43 2086 if (need_seek) {
99613ec5 2087 if (!arg_reverse)
d89d6c86
LN
2088 r = sd_journal_next(j);
2089 else
2090 r = sd_journal_previous(j);
6f003b43 2091 if (r < 0) {
da927ba9 2092 log_error_errno(r, "Failed to iterate through journal: %m");
6f003b43
LP
2093 goto finish;
2094 }
a72b6353
ZJS
2095 if (r == 0)
2096 break;
0d43c694
LP
2097 }
2098
d89d6c86 2099 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
2100 usec_t usec;
2101
2102 r = sd_journal_get_realtime_usec(j, &usec);
2103 if (r < 0) {
da927ba9 2104 log_error_errno(r, "Failed to determine timestamp: %m");
cfbc22ab
LP
2105 goto finish;
2106 }
3ba09ee8
PF
2107 if (usec > arg_until)
2108 goto finish;
cfbc22ab
LP
2109 }
2110
d89d6c86
LN
2111 if (arg_since_set && arg_reverse) {
2112 usec_t usec;
2113
2114 r = sd_journal_get_realtime_usec(j, &usec);
2115 if (r < 0) {
da927ba9 2116 log_error_errno(r, "Failed to determine timestamp: %m");
d89d6c86
LN
2117 goto finish;
2118 }
2119 if (usec < arg_since)
2120 goto finish;
2121 }
2122
4bed2485 2123 if (!arg_merge && !arg_quiet) {
cd931c0a 2124 sd_id128_t boot_id;
14a65d65 2125
cd931c0a
LP
2126 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2127 if (r >= 0) {
2128 if (previous_boot_id_valid &&
2129 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c
DS
2130 printf("%s-- Reboot --%s\n",
2131 ansi_highlight(), ansi_highlight_off());
cd931c0a
LP
2132
2133 previous_boot_id = boot_id;
2134 previous_boot_id_valid = true;
2135 }
14a65d65
LP
2136 }
2137
cfbc22ab 2138 flags =
cd4b13e0 2139 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 2140 arg_full * OUTPUT_FULL_WIDTH |
d4205751 2141 on_tty() * OUTPUT_COLOR |
9fd29044
JS
2142 arg_catalog * OUTPUT_CATALOG |
2143 arg_utc * OUTPUT_UTC;
cfbc22ab 2144
94e0bd7d 2145 r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
a72b6353
ZJS
2146 need_seek = true;
2147 if (r == -EADDRNOTAVAIL)
2148 break;
2149 else if (r < 0 || ferror(stdout))
72f59706 2150 goto finish;
6f003b43 2151
cfbc22ab 2152 n_shown++;
87d2c1ff
LP
2153 }
2154
248fc619
ZJS
2155 if (!arg_follow) {
2156 if (arg_show_cursor) {
2157 _cleanup_free_ char *cursor = NULL;
2158
2159 r = sd_journal_get_cursor(j, &cursor);
2160 if (r < 0 && r != -EADDRNOTAVAIL)
da927ba9 2161 log_error_errno(r, "Failed to get cursor: %m");
248fc619
ZJS
2162 else if (r >= 0)
2163 printf("-- cursor: %s\n", cursor);
2164 }
2165
50f20cfd 2166 break;
248fc619 2167 }
50f20cfd 2168
e02d1cf7 2169 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 2170 if (r < 0) {
da927ba9 2171 log_error_errno(r, "Couldn't wait for journal event: %m");
50f20cfd
LP
2172 goto finish;
2173 }
67e04a48
ZJS
2174
2175 first_line = false;
de190aef 2176 }
87d2c1ff
LP
2177
2178finish:
0d43c694
LP
2179 pager_close();
2180
a36b8deb
ZJS
2181 strv_free(arg_file);
2182
d52da205
LP
2183 strv_free(arg_syslog_identifier);
2184 strv_free(arg_system_units);
2185 strv_free(arg_user_units);
2186
3fbf9cbb 2187 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2188}