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