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