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