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