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