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