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