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