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