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