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