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