]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
udev: do NOT re-label smack
[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
f1188074
ZJS
847static int list_boots(sd_journal *j) {
848 int r;
849 const void *data;
850 unsigned int count = 0;
851 int w, i;
852 size_t length, allocated = 0;
853 boot_id_t *id;
854 _cleanup_free_ boot_id_t *all_ids = NULL;
855
856 r = sd_journal_query_unique(j, "_BOOT_ID");
857 if (r < 0)
858 return r;
859
cab9b000
ZJS
860 pager_open_if_enabled();
861
f1188074 862 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
853bd5cc 863 assert(startswith(data, "_BOOT_ID="));
f1188074
ZJS
864
865 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
866 return log_oom();
867
868 id = &all_ids[count];
869
870 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
871 if (r < 0)
872 continue;
873
874 r = sd_journal_add_match(j, data, length);
875 if (r < 0)
876 return r;
877
878 r = sd_journal_seek_head(j);
879 if (r < 0)
880 return r;
881
882 r = sd_journal_next(j);
883 if (r < 0)
884 return r;
885 else if (r == 0)
886 goto flush;
887
888 r = sd_journal_get_realtime_usec(j, &id->first);
889 if (r < 0)
890 return r;
891
892 r = sd_journal_seek_tail(j);
893 if (r < 0)
894 return r;
895
896 r = sd_journal_previous(j);
897 if (r < 0)
898 return r;
899 else if (r == 0)
900 goto flush;
901
902 r = sd_journal_get_realtime_usec(j, &id->last);
903 if (r < 0)
904 return r;
905
906 count++;
907 flush:
908 sd_journal_flush_matches(j);
909 }
910
911 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
912
913 /* numbers are one less, but we need an extra char for the sign */
914 w = DECIMAL_STR_WIDTH(count - 1) + 1;
915
916 for (id = all_ids, i = 0; id < all_ids + count; id++, i++) {
917 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
918
919 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
920 w, i - count + 1,
921 SD_ID128_FORMAT_VAL(id->id),
5ab99e07
LP
922 format_timestamp_maybe_utc(a, sizeof(a), id->first),
923 format_timestamp_maybe_utc(b, sizeof(b), id->last));
f1188074
ZJS
924 }
925
926 return 0;
927}
928
a331b5e6
JJ
929static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
930 int r;
931 const void *data;
d121b396 932 unsigned int count = 0;
a331b5e6 933 size_t length, allocated = 0;
d121b396 934 boot_id_t ref_boot_id = {SD_ID128_NULL}, *id;
a331b5e6 935 _cleanup_free_ boot_id_t *all_ids = NULL;
a331b5e6
JJ
936
937 assert(j);
938 assert(boot_id);
939
a331b5e6
JJ
940 r = sd_journal_query_unique(j, "_BOOT_ID");
941 if (r < 0)
942 return r;
943
944 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
945 if (length < strlen("_BOOT_ID="))
946 continue;
947
d121b396 948 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
a331b5e6
JJ
949 return log_oom();
950
d121b396 951 id = &all_ids[count];
a331b5e6
JJ
952
953 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
d121b396 954 if (r < 0)
a331b5e6 955 continue;
a331b5e6 956
a331b5e6
JJ
957 r = sd_journal_add_match(j, data, length);
958 if (r < 0)
d121b396 959 return r;
a331b5e6
JJ
960
961 r = sd_journal_seek_head(j);
962 if (r < 0)
d121b396 963 return r;
a331b5e6
JJ
964
965 r = sd_journal_next(j);
d121b396
ZJS
966 if (r < 0)
967 return r;
968 else if (r == 0)
969 goto flush;
a331b5e6 970
f1188074 971 r = sd_journal_get_realtime_usec(j, &id->first);
a331b5e6 972 if (r < 0)
d121b396 973 return r;
a331b5e6 974
d121b396 975 if (sd_id128_equal(id->id, *boot_id))
a331b5e6 976 ref_boot_id = *id;
a331b5e6 977
d121b396
ZJS
978 count++;
979 flush:
980 sd_journal_flush_matches(j);
a331b5e6
JJ
981 }
982
7ff7394d 983 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
a331b5e6 984
d121b396
ZJS
985 if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
986 if (relative > (int) count || relative <= -(int)count)
987 return -EADDRNOTAVAIL;
a331b5e6 988
d121b396
ZJS
989 *boot_id = all_ids[(relative <= 0)*count + relative - 1].id;
990 } else {
991 id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp);
a331b5e6 992
d121b396
ZJS
993 if (!id ||
994 relative <= 0 ? (id - all_ids) + relative < 0 :
a54e3b3d 995 (id - all_ids) + relative >= (int) count)
d121b396
ZJS
996 return -EADDRNOTAVAIL;
997
998 *boot_id = (id + relative)->id;
999 }
a963990f 1000
a331b5e6
JJ
1001 return 0;
1002}
1003
1004static int add_boot(sd_journal *j) {
1005 char match[9+32+1] = "_BOOT_ID=";
442e2def 1006 int r;
a331b5e6
JJ
1007
1008 assert(j);
1009
d121b396 1010 if (!arg_boot)
a331b5e6
JJ
1011 return 0;
1012
442e2def 1013 if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
b6741478 1014 return add_match_this_boot(j, arg_machine);
a331b5e6 1015
442e2def 1016 r = get_relative_boot_id(j, &arg_boot_id, arg_boot_offset);
a331b5e6 1017 if (r < 0) {
442e2def
LP
1018 if (sd_id128_equal(arg_boot_id, SD_ID128_NULL))
1019 log_error("Failed to look up boot %+i: %s", arg_boot_offset, strerror(-r));
d121b396 1020 else
442e2def
LP
1021 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
1022 SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r));
a331b5e6 1023 return r;
a331b5e6
JJ
1024 }
1025
442e2def 1026 sd_id128_to_string(arg_boot_id, match + 9);
d121b396
ZJS
1027
1028 r = sd_journal_add_match(j, match, sizeof(match) - 1);
a331b5e6
JJ
1029 if (r < 0) {
1030 log_error("Failed to add match: %s", strerror(-r));
1031 return r;
1032 }
1033
1034 r = sd_journal_add_conjunction(j);
1035 if (r < 0)
1036 return r;
1037
1038 return 0;
a963990f
LP
1039}
1040
99271804
ZJS
1041static int add_dmesg(sd_journal *j) {
1042 int r;
1043 assert(j);
1044
1045 if (!arg_dmesg)
1046 return 0;
1047
1048 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
1049 if (r < 0) {
1050 log_error("Failed to add match: %s", strerror(-r));
1051 return r;
1052 }
1053
1054 r = sd_journal_add_conjunction(j);
1055 if (r < 0)
1056 return r;
1057
1058 return 0;
1059}
1060
ea18a4b5
ZJS
1061static int get_possible_units(sd_journal *j,
1062 const char *fields,
1063 char **patterns,
1064 Set **units) {
1065 _cleanup_set_free_free_ Set *found;
1066 const char *field;
c3f60ec5 1067 int r;
ea18a4b5 1068
d5099efc 1069 found = set_new(&string_hash_ops);
ea18a4b5
ZJS
1070 if (!found)
1071 return log_oom();
1072
1073 NULSTR_FOREACH(field, fields) {
1074 const void *data;
1075 size_t size;
1076
1077 r = sd_journal_query_unique(j, field);
1078 if (r < 0)
1079 return r;
1080
1081 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1082 char **pattern, *eq;
1083 size_t prefix;
1084 _cleanup_free_ char *u = NULL;
1085
1086 eq = memchr(data, '=', size);
1087 if (eq)
1088 prefix = eq - (char*) data + 1;
1089 else
1090 prefix = 0;
1091
1092 u = strndup((char*) data + prefix, size - prefix);
1093 if (!u)
1094 return log_oom();
1095
1096 STRV_FOREACH(pattern, patterns)
1097 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1098 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1099
1100 r = set_consume(found, u);
1101 u = NULL;
1102 if (r < 0 && r != -EEXIST)
1103 return r;
1104
1105 break;
1106 }
1107 }
1108 }
1109
1110 *units = found;
1111 found = NULL;
1112 return 0;
1113}
1114
1115/* This list is supposed to return the superset of unit names
1116 * possibly matched by rules added with add_matches_for_unit... */
1117#define SYSTEM_UNITS \
1118 "_SYSTEMD_UNIT\0" \
1119 "COREDUMP_UNIT\0" \
1120 "UNIT\0" \
1121 "OBJECT_SYSTEMD_UNIT\0" \
1122 "_SYSTEMD_SLICE\0"
1123
1124/* ... and add_matches_for_user_unit */
1125#define USER_UNITS \
1126 "_SYSTEMD_USER_UNIT\0" \
1127 "USER_UNIT\0" \
1128 "COREDUMP_USER_UNIT\0" \
1129 "OBJECT_SYSTEMD_USER_UNIT\0"
1130
1131static int add_units(sd_journal *j) {
1132 _cleanup_strv_free_ char **patterns = NULL;
1133 int r, count = 0;
b9e40524 1134 char **i;
c3f60ec5
LP
1135
1136 assert(j);
1137
b9e40524 1138 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1139 _cleanup_free_ char *u = NULL;
1140
1141 u = unit_name_mangle(*i, MANGLE_GLOB);
b9e40524
HH
1142 if (!u)
1143 return log_oom();
ea18a4b5
ZJS
1144
1145 if (string_is_glob(u)) {
1146 r = strv_push(&patterns, u);
1147 if (r < 0)
1148 return r;
1149 u = NULL;
1150 } else {
1151 r = add_matches_for_unit(j, u);
1152 if (r < 0)
1153 return r;
1154 r = sd_journal_add_disjunction(j);
1155 if (r < 0)
1156 return r;
1157 count ++;
1158 }
1159 }
1160
1161 if (!strv_isempty(patterns)) {
1162 _cleanup_set_free_free_ Set *units = NULL;
1163 Iterator it;
1164 char *u;
1165
1166 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1167 if (r < 0)
1168 return r;
ea18a4b5
ZJS
1169
1170 SET_FOREACH(u, units, it) {
1171 r = add_matches_for_unit(j, u);
1172 if (r < 0)
1173 return r;
1174 r = sd_journal_add_disjunction(j);
1175 if (r < 0)
1176 return r;
1177 count ++;
1178 }
b9e40524 1179 }
c3f60ec5 1180
ea18a4b5
ZJS
1181 strv_free(patterns);
1182 patterns = NULL;
1183
b9e40524 1184 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1185 _cleanup_free_ char *u = NULL;
1186
1187 u = unit_name_mangle(*i, MANGLE_GLOB);
b9e40524
HH
1188 if (!u)
1189 return log_oom();
c3f60ec5 1190
ea18a4b5
ZJS
1191 if (string_is_glob(u)) {
1192 r = strv_push(&patterns, u);
1193 if (r < 0)
1194 return r;
1195 u = NULL;
1196 } else {
1197 r = add_matches_for_user_unit(j, u, getuid());
1198 if (r < 0)
1199 return r;
1200 r = sd_journal_add_disjunction(j);
1201 if (r < 0)
1202 return r;
1203 count ++;
1204 }
1205 }
1206
1207 if (!strv_isempty(patterns)) {
1208 _cleanup_set_free_free_ Set *units = NULL;
1209 Iterator it;
1210 char *u;
b9e40524 1211
ea18a4b5 1212 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1213 if (r < 0)
1214 return r;
1215
ea18a4b5
ZJS
1216 SET_FOREACH(u, units, it) {
1217 r = add_matches_for_user_unit(j, u, getuid());
1218 if (r < 0)
1219 return r;
1220 r = sd_journal_add_disjunction(j);
1221 if (r < 0)
1222 return r;
1223 count ++;
1224 }
b9e40524 1225 }
c3f60ec5 1226
ea18a4b5
ZJS
1227 /* Complain if the user request matches but nothing whatsoever was
1228 * found, since otherwise everything would be matched. */
1229 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1230 return -ENODATA;
1231
cd34b3c6
HH
1232 r = sd_journal_add_conjunction(j);
1233 if (r < 0)
1234 return r;
1235
c3f60ec5
LP
1236 return 0;
1237}
1238
941e990d
LP
1239static int add_priorities(sd_journal *j) {
1240 char match[] = "PRIORITY=0";
1241 int i, r;
941e990d
LP
1242 assert(j);
1243
1244 if (arg_priorities == 0xFF)
1245 return 0;
1246
1247 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1248 if (arg_priorities & (1 << i)) {
1249 match[sizeof(match)-2] = '0' + i;
1250
941e990d
LP
1251 r = sd_journal_add_match(j, match, strlen(match));
1252 if (r < 0) {
1253 log_error("Failed to add match: %s", strerror(-r));
1254 return r;
1255 }
1256 }
1257
cd34b3c6
HH
1258 r = sd_journal_add_conjunction(j);
1259 if (r < 0)
1260 return r;
1261
941e990d
LP
1262 return 0;
1263}
1264
73083640
HH
1265
1266static int add_syslog_identifier(sd_journal *j) {
1267 int r;
1268 char **i;
1269
1270 assert(j);
1271
1272 STRV_FOREACH(i, arg_syslog_identifier) {
1273 char *u;
1274
1275 u = strappenda("SYSLOG_IDENTIFIER=", *i);
1276 r = sd_journal_add_match(j, u, 0);
1277 if (r < 0)
1278 return r;
1279 r = sd_journal_add_disjunction(j);
1280 if (r < 0)
1281 return r;
1282 }
1283
1284 r = sd_journal_add_conjunction(j);
1285 if (r < 0)
1286 return r;
1287
1288 return 0;
1289}
1290
7560fffc
LP
1291static int setup_keys(void) {
1292#ifdef HAVE_GCRYPT
1293 size_t mpk_size, seed_size, state_size, i;
1294 uint8_t *mpk, *seed, *state;
1295 ssize_t l;
f982e6f7 1296 int fd = -1, r, attr = 0;
7560fffc
LP
1297 sd_id128_t machine, boot;
1298 char *p = NULL, *k = NULL;
baed47c3 1299 struct FSSHeader h;
14d10188 1300 uint64_t n;
b98e3866
SL
1301 struct stat st;
1302
1303 r = stat("/var/log/journal", &st);
1304 if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
1305 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
1306 return -errno;
1307 }
1308
1309 if (r < 0 || !S_ISDIR(st.st_mode)) {
1310 log_error("%s is not a directory, must be using persistent logging for FSS.",
1311 "/var/log/journal");
1312 return r < 0 ? -errno : -ENOTDIR;
1313 }
7560fffc
LP
1314
1315 r = sd_id128_get_machine(&machine);
1316 if (r < 0) {
1317 log_error("Failed to get machine ID: %s", strerror(-r));
1318 return r;
1319 }
1320
1321 r = sd_id128_get_boot(&boot);
1322 if (r < 0) {
1323 log_error("Failed to get boot ID: %s", strerror(-r));
1324 return r;
1325 }
1326
baed47c3 1327 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1328 SD_ID128_FORMAT_VAL(machine)) < 0)
1329 return log_oom();
1330
1331 if (access(p, F_OK) >= 0) {
b8547c10
SL
1332 if (arg_force) {
1333 r = unlink(p);
1334 if (r < 0) {
1335 log_error("unlink(\"%s\") failed: %m", p);
1336 r = -errno;
1337 goto finish;
1338 }
1339 } else {
1340 log_error("Sealing key file %s exists already. (--force to recreate)", p);
1341 r = -EEXIST;
1342 goto finish;
1343 }
7560fffc
LP
1344 }
1345
baed47c3 1346 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1347 SD_ID128_FORMAT_VAL(machine)) < 0) {
1348 r = log_oom();
1349 goto finish;
1350 }
1351
1352 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1353 mpk = alloca(mpk_size);
1354
1355 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1356 seed = alloca(seed_size);
1357
1358 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1359 state = alloca(state_size);
1360
1361 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1362 if (fd < 0) {
1363 log_error("Failed to open /dev/random: %m");
1364 r = -errno;
1365 goto finish;
1366 }
1367
1368 log_info("Generating seed...");
1369 l = loop_read(fd, seed, seed_size, true);
1370 if (l < 0 || (size_t) l != seed_size) {
1371 log_error("Failed to read random seed: %s", strerror(EIO));
1372 r = -EIO;
1373 goto finish;
1374 }
1375
1376 log_info("Generating key pair...");
1377 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1378
baed47c3 1379 log_info("Generating sealing key...");
7560fffc
LP
1380 FSPRG_GenState0(state, mpk, seed, seed_size);
1381
baed47c3
LP
1382 assert(arg_interval > 0);
1383
7560fffc 1384 n = now(CLOCK_REALTIME);
baed47c3 1385 n /= arg_interval;
7560fffc 1386
03e334a1 1387 safe_close(fd);
2d5bdf5b 1388 fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
7560fffc
LP
1389 if (fd < 0) {
1390 log_error("Failed to open %s: %m", k);
1391 r = -errno;
1392 goto finish;
1393 }
1394
f982e6f7
LP
1395 /* Enable secure remove, exclusion from dump, synchronous
1396 * writing and in-place updating */
1397 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
1398 log_warning("FS_IOC_GETFLAGS failed: %m");
1399
1400 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
1401
1402 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
1403 log_warning("FS_IOC_SETFLAGS failed: %m");
1404
7560fffc
LP
1405 zero(h);
1406 memcpy(h.signature, "KSHHRHLP", 8);
1407 h.machine_id = machine;
1408 h.boot_id = boot;
1409 h.header_size = htole64(sizeof(h));
baed47c3
LP
1410 h.start_usec = htole64(n * arg_interval);
1411 h.interval_usec = htole64(arg_interval);
1412 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1413 h.fsprg_state_size = htole64(state_size);
7560fffc
LP
1414
1415 l = loop_write(fd, &h, sizeof(h), false);
1416 if (l < 0 || (size_t) l != sizeof(h)) {
1417 log_error("Failed to write header: %s", strerror(EIO));
1418 r = -EIO;
1419 goto finish;
1420 }
1421
1422 l = loop_write(fd, state, state_size, false);
1423 if (l < 0 || (size_t) l != state_size) {
1424 log_error("Failed to write state: %s", strerror(EIO));
1425 r = -EIO;
1426 goto finish;
1427 }
1428
1429 if (link(k, p) < 0) {
1430 log_error("Failed to link file: %m");
1431 r = -errno;
1432 goto finish;
1433 }
1434
8481248b 1435 if (on_tty()) {
7560fffc
LP
1436 fprintf(stderr,
1437 "\n"
baed47c3 1438 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
c05276f2
LP
1439 "the following local file. This key file is automatically updated when the\n"
1440 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1441 "\n"
1442 "\t%s\n"
1443 "\n"
baed47c3
LP
1444 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1445 "at a safe location and should not be saved locally on disk.\n"
7560fffc
LP
1446 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1447 fflush(stderr);
1448 }
1449 for (i = 0; i < seed_size; i++) {
1450 if (i > 0 && i % 3 == 0)
1451 putchar('-');
1452 printf("%02x", ((uint8_t*) seed)[i]);
1453 }
1454
baed47c3
LP
1455 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1456
8481248b 1457 if (on_tty()) {
f6a971bc 1458 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1459
baed47c3
LP
1460 fprintf(stderr,
1461 ANSI_HIGHLIGHT_OFF "\n"
1462 "The sealing key is automatically changed every %s.\n",
2fa4092c 1463 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1464
1465 hn = gethostname_malloc();
1466
1467 if (hn) {
e724b063 1468 hostname_cleanup(hn, false);
adac1c93 1469 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1470 } else
adac1c93 1471 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc
LP
1472
1473#ifdef HAVE_QRENCODE
cf5a3432 1474 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1475 if (is_locale_utf8()) {
cf5a3432
LP
1476 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1477 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1478 }
f6a971bc
LP
1479#endif
1480 free(hn);
baed47c3 1481 }
7560fffc
LP
1482
1483 r = 0;
1484
1485finish:
03e334a1 1486 safe_close(fd);
7560fffc
LP
1487
1488 if (k) {
1489 unlink(k);
1490 free(k);
1491 }
1492
1493 free(p);
1494
1495 return r;
1496#else
feb12d3e
LP
1497 log_error("Forward-secure sealing not available.");
1498 return -ENOTSUP;
7560fffc
LP
1499#endif
1500}
1501
beec0085
LP
1502static int verify(sd_journal *j) {
1503 int r = 0;
1504 Iterator i;
1505 JournalFile *f;
1506
1507 assert(j);
1508
cedb42bb
LP
1509 log_show_color(true);
1510
c1f906bd 1511 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
beec0085 1512 int k;
2a7b539a 1513 usec_t first, validated, last;
beec0085 1514
56e81f7c 1515#ifdef HAVE_GCRYPT
feb12d3e 1516 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1517 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1518#endif
4da416aa 1519
2a7b539a 1520 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1521 if (k == -EINVAL) {
baed47c3 1522 /* If the key was invalid give up right-away. */
56e81f7c
LP
1523 return k;
1524 } else if (k < 0) {
beec0085 1525 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
56e81f7c 1526 r = k;
6c7be122
LP
1527 } else {
1528 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1529 log_info("PASS: %s", f->path);
6c7be122 1530
c0ca7aee 1531 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1532 if (validated > 0) {
c0ca7aee 1533 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1534 format_timestamp_maybe_utc(a, sizeof(a), first),
1535 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1536 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1537 } else if (last > 0)
c0ca7aee 1538 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1539 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1540 else
1541 log_info("=> No sealing yet, no entries in file.");
1542 }
6c7be122 1543 }
beec0085
LP
1544 }
1545
1546 return r;
1547}
1548
15804ceb 1549#ifdef HAVE_ACL
6fe391c5
ZJS
1550static int access_check_var_log_journal(sd_journal *j) {
1551 _cleanup_strv_free_ char **g = NULL;
1552 bool have_access;
1553 int r;
1554
1555 assert(j);
1556
1557 have_access = in_group("systemd-journal") > 0;
1558
1559 if (!have_access) {
1560 /* Let's enumerate all groups from the default ACL of
1561 * the directory, which generally should allow access
1562 * to most journal files too */
1563 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
1564 if (r < 0)
1565 return r;
15804ceb
LP
1566 }
1567
6fe391c5 1568 if (!have_access) {
4468addc 1569
6fe391c5 1570 if (strv_isempty(g))
3ac251b8
LP
1571 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1572 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1573 " turn off this notice.");
6fe391c5
ZJS
1574 else {
1575 _cleanup_free_ char *s = NULL;
4468addc 1576
6fe391c5 1577 r = strv_extend(&g, "systemd-journal");
478c8269 1578 if (r < 0)
6fe391c5
ZJS
1579 return log_oom();
1580
1581 strv_sort(g);
1582 strv_uniq(g);
1583
1584 s = strv_join(g, "', '");
1585 if (!s)
1586 return log_oom();
1587
1588 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
3ac251b8
LP
1589 " Users in the groups '%s' can see all messages.\n"
1590 " Pass -q to turn off this notice.", s);
4468addc 1591 }
6fe391c5 1592 }
4468addc 1593
6fe391c5
ZJS
1594 return 0;
1595}
1596#endif
4468addc 1597
6fe391c5 1598static int access_check(sd_journal *j) {
6fe391c5 1599 Iterator it;
3ac251b8 1600 void *code;
6fe391c5 1601 int r = 0;
4468addc 1602
6fe391c5 1603 assert(j);
4468addc 1604
6fe391c5 1605 if (set_isempty(j->errors)) {
c1f906bd 1606 if (ordered_hashmap_isempty(j->files))
3ac251b8 1607 log_notice("No journal files were found.");
6fe391c5
ZJS
1608 return 0;
1609 }
4468addc 1610
3ac251b8 1611 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
6fe391c5
ZJS
1612#ifdef HAVE_ACL
1613 /* If /var/log/journal doesn't even exist,
3ac251b8 1614 * unprivileged users have no access at all */
6fe391c5
ZJS
1615 if (access("/var/log/journal", F_OK) < 0 &&
1616 geteuid() != 0 &&
1617 in_group("systemd-journal") <= 0) {
3ac251b8
LP
1618 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1619 "enabled. Users in the 'systemd-journal' group may always access messages.");
6fe391c5
ZJS
1620 return -EACCES;
1621 }
4468addc 1622
6fe391c5
ZJS
1623 /* If /var/log/journal exists, try to pring a nice
1624 notice if the user lacks access to it */
1625 if (!arg_quiet && geteuid() != 0) {
1626 r = access_check_var_log_journal(j);
1627 if (r < 0)
1628 return r;
4468addc 1629 }
15804ceb 1630#else
3ac251b8
LP
1631 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1632 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1633 "group may access messages.");
1634 return -EACCES;
1635 }
15804ceb 1636#endif
3ac251b8 1637
c1f906bd 1638 if (ordered_hashmap_isempty(j->files)) {
3ac251b8 1639 log_error("No journal files were opened due to insufficient permissions.");
6fe391c5
ZJS
1640 r = -EACCES;
1641 }
1642 }
15804ceb 1643
6fe391c5 1644 SET_FOREACH(code, j->errors, it) {
3ac251b8
LP
1645 int err;
1646
1647 err = -PTR_TO_INT(code);
6fe391c5 1648 assert(err > 0);
3ac251b8 1649
6fe391c5
ZJS
1650 if (err != EACCES)
1651 log_warning("Error was encountered while opening journal files: %s",
1652 strerror(err));
1653 }
1654
6fe391c5 1655 return r;
15804ceb
LP
1656}
1657
74055aa7
LP
1658static int flush_to_var(void) {
1659 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1660 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1661 _cleanup_close_ int watch_fd = -1;
1662 int r;
1663
1664 /* Quick exit */
1665 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1666 return 0;
1667
1668 /* OK, let's actually do the full logic, send SIGUSR1 to the
1669 * daemon and set up inotify to wait for the flushed file to appear */
1670 r = bus_open_system_systemd(&bus);
1671 if (r < 0) {
1672 log_error("Failed to get D-Bus connection: %s", strerror(-r));
1673 return r;
1674 }
1675
1676 r = sd_bus_call_method(
1677 bus,
1678 "org.freedesktop.systemd1",
1679 "/org/freedesktop/systemd1",
1680 "org.freedesktop.systemd1.Manager",
1681 "KillUnit",
1682 &error,
1683 NULL,
1684 "ssi", "systemd-journald.service", "main", SIGUSR1);
1685 if (r < 0) {
1686 log_error("Failed to kill journal service: %s", bus_error_message(&error, r));
1687 return r;
1688 }
1689
1690 mkdir_p("/run/systemd/journal", 0755);
1691
1692 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1693 if (watch_fd < 0) {
1694 log_error("Failed to create inotify watch: %m");
1695 return -errno;
1696 }
1697
1698 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
1699 if (r < 0) {
1700 log_error("Failed to watch journal directory: %m");
1701 return -errno;
1702 }
1703
1704 for (;;) {
1705 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1706 break;
1707
1708 if (errno != ENOENT) {
1709 log_error("Failed to check for existance of /run/systemd/journal/flushed: %m");
1710 return -errno;
1711 }
1712
1713 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
1714 if (r < 0) {
1715 log_error("Failed to wait for event: %s", strerror(-r));
1716 return r;
1717 }
1718
1719 r = flush_fd(watch_fd);
1720 if (r < 0) {
1721 log_error("Failed to flush inotify events: %s", strerror(-r));
1722 return r;
1723 }
1724 }
1725
1726 return 0;
1727}
1728
a963990f
LP
1729int main(int argc, char *argv[]) {
1730 int r;
289f910e 1731 _cleanup_journal_close_ sd_journal *j = NULL;
a963990f 1732 bool need_seek = false;
14a65d65 1733 sd_id128_t previous_boot_id;
67e04a48
ZJS
1734 bool previous_boot_id_valid = false, first_line = true;
1735 int n_shown = 0;
94e0bd7d 1736 bool ellipsized = false;
a963990f 1737
a9cdc94f 1738 setlocale(LC_ALL, "");
a963990f
LP
1739 log_parse_environment();
1740 log_open();
1741
1742 r = parse_argv(argc, argv);
1743 if (r <= 0)
1744 goto finish;
1745
ed757c0c
LP
1746 signal(SIGWINCH, columns_lines_cache_reset);
1747
7560fffc 1748 if (arg_action == ACTION_NEW_ID128) {
a963990f
LP
1749 r = generate_new_id128();
1750 goto finish;
1751 }
1752
74055aa7
LP
1753 if (arg_action == ACTION_FLUSH) {
1754 r = flush_to_var();
1755 goto finish;
1756 }
1757
7560fffc
LP
1758 if (arg_action == ACTION_SETUP_KEYS) {
1759 r = setup_keys();
1760 goto finish;
1761 }
1762
844ec79b
ZJS
1763 if (arg_action == ACTION_UPDATE_CATALOG ||
1764 arg_action == ACTION_LIST_CATALOG ||
1765 arg_action == ACTION_DUMP_CATALOG) {
1766
0c6ea3a4
ZJS
1767 _cleanup_free_ char *database;
1768
1769 database = path_join(arg_root, CATALOG_DATABASE, NULL);
1770 if (!database) {
1771 r = log_oom();
1772 goto finish;
13cbf3a5
ZJS
1773 }
1774
844ec79b 1775 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 1776 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b
ZJS
1777 if (r < 0)
1778 log_error("Failed to list catalog: %s", strerror(-r));
1779 } else {
1780 bool oneline = arg_action == ACTION_LIST_CATALOG;
1781
1782 if (optind < argc)
13cbf3a5 1783 r = catalog_list_items(stdout, database,
844ec79b
ZJS
1784 oneline, argv + optind);
1785 else
13cbf3a5 1786 r = catalog_list(stdout, database, oneline);
844ec79b
ZJS
1787 if (r < 0)
1788 log_error("Failed to list catalog: %s", strerror(-r));
1789 }
d4205751 1790
d4205751
LP
1791 goto finish;
1792 }
1793
a963990f 1794 if (arg_directory)
3f3a438f 1795 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
8d98da3f
ZJS
1796 else if (arg_file)
1797 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
b6741478
LP
1798 else if (arg_machine)
1799 r = sd_journal_open_container(&j, arg_machine, 0);
a963990f 1800 else
3f3a438f 1801 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 1802 if (r < 0) {
8d98da3f
ZJS
1803 log_error("Failed to open %s: %s",
1804 arg_directory ? arg_directory : arg_file ? "files" : "journal",
1805 strerror(-r));
763c7aa2 1806 return EXIT_FAILURE;
a963990f
LP
1807 }
1808
6fe391c5
ZJS
1809 r = access_check(j);
1810 if (r < 0)
1811 return EXIT_FAILURE;
1812
beec0085
LP
1813 if (arg_action == ACTION_VERIFY) {
1814 r = verify(j);
1815 goto finish;
1816 }
1817
7560fffc 1818 if (arg_action == ACTION_PRINT_HEADER) {
dca6219e 1819 journal_print_header(j);
763c7aa2 1820 return EXIT_SUCCESS;
dca6219e
LP
1821 }
1822
a1a03e30 1823 if (arg_action == ACTION_DISK_USAGE) {
39883f62 1824 uint64_t bytes = 0;
a1a03e30
LP
1825 char sbytes[FORMAT_BYTES_MAX];
1826
1827 r = sd_journal_get_usage(j, &bytes);
1828 if (r < 0)
763c7aa2 1829 return EXIT_FAILURE;
a1a03e30 1830
763c7aa2
ZJS
1831 printf("Journals take up %s on disk.\n",
1832 format_bytes(sbytes, sizeof(sbytes), bytes));
1833 return EXIT_SUCCESS;
a1a03e30
LP
1834 }
1835
f1188074
ZJS
1836 if (arg_action == ACTION_LIST_BOOTS) {
1837 r = list_boots(j);
1838 goto finish;
1839 }
1840
a331b5e6
JJ
1841 /* add_boot() must be called first!
1842 * It may need to seek the journal to find parent boot IDs. */
1843 r = add_boot(j);
a963990f 1844 if (r < 0)
763c7aa2 1845 return EXIT_FAILURE;
a963990f 1846
99271804
ZJS
1847 r = add_dmesg(j);
1848 if (r < 0)
1849 return EXIT_FAILURE;
1850
b9e40524
HH
1851 r = add_units(j);
1852 strv_free(arg_system_units);
1853 strv_free(arg_user_units);
1854
ea18a4b5
ZJS
1855 if (r < 0) {
1856 log_error("Failed to add filter for units: %s", strerror(-r));
763c7aa2 1857 return EXIT_FAILURE;
ea18a4b5 1858 }
c3f60ec5 1859
73083640
HH
1860 r = add_syslog_identifier(j);
1861 if (r < 0) {
1862 log_error("Failed to add filter for syslog identifiers: %s", strerror(-r));
1863 return EXIT_FAILURE;
1864 }
1865
cd34b3c6 1866 r = add_priorities(j);
ea18a4b5
ZJS
1867 if (r < 0) {
1868 log_error("Failed to add filter for priorities: %s", strerror(-r));
763c7aa2 1869 return EXIT_FAILURE;
ea18a4b5 1870 }
a963990f 1871
cd34b3c6 1872 r = add_matches(j, argv + optind);
ea18a4b5
ZJS
1873 if (r < 0) {
1874 log_error("Failed to add filters: %s", strerror(-r));
763c7aa2 1875 return EXIT_FAILURE;
ea18a4b5 1876 }
941e990d 1877
4ad16808
ZJS
1878 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1879 _cleanup_free_ char *filter;
1880
1881 filter = journal_make_match_string(j);
1882 log_debug("Journal filter: %s", filter);
1883 }
67e04a48 1884
15119c16
LP
1885 if (arg_field) {
1886 const void *data;
1887 size_t size;
1888
21ae4593
ZJS
1889 r = sd_journal_set_data_threshold(j, 0);
1890 if (r < 0) {
1891 log_error("Failed to unset data size threshold");
1892 return EXIT_FAILURE;
1893 }
1894
15119c16
LP
1895 r = sd_journal_query_unique(j, arg_field);
1896 if (r < 0) {
1897 log_error("Failed to query unique data objects: %s", strerror(-r));
763c7aa2 1898 return EXIT_FAILURE;
15119c16
LP
1899 }
1900
1901 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1902 const void *eq;
1903
67e04a48 1904 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
1905 break;
1906
15119c16
LP
1907 eq = memchr(data, '=', size);
1908 if (eq)
1909 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1910 else
1911 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875
LP
1912
1913 n_shown ++;
15119c16
LP
1914 }
1915
763c7aa2 1916 return EXIT_SUCCESS;
15119c16
LP
1917 }
1918
8d98da3f
ZJS
1919 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1920 if (arg_follow) {
1921 r = sd_journal_get_fd(j);
1922 if (r < 0)
1923 return EXIT_FAILURE;
1924 }
1925
248fc619 1926 if (arg_cursor || arg_after_cursor) {
eacbb4d3 1927 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
08984293 1928 if (r < 0) {
cfbc22ab 1929 log_error("Failed to seek to cursor: %s", strerror(-r));
763c7aa2 1930 return EXIT_FAILURE;
08984293 1931 }
d89d6c86 1932 if (!arg_reverse)
248fc619 1933 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
d89d6c86 1934 else
248fc619
ZJS
1935 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
1936
1937 if (arg_after_cursor && r < 2 && !arg_follow)
1938 /* We couldn't find the next entry after the cursor. */
1939 arg_lines = 0;
08984293 1940
d89d6c86 1941 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 1942 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 1943 if (r < 0) {
cfbc22ab 1944 log_error("Failed to seek to date: %s", strerror(-r));
763c7aa2 1945 return EXIT_FAILURE;
8f14c832 1946 }
8f14c832
LP
1947 r = sd_journal_next(j);
1948
d89d6c86
LN
1949 } else if (arg_until_set && arg_reverse) {
1950 r = sd_journal_seek_realtime_usec(j, arg_until);
1951 if (r < 0) {
1952 log_error("Failed to seek to date: %s", strerror(-r));
763c7aa2 1953 return EXIT_FAILURE;
d89d6c86
LN
1954 }
1955 r = sd_journal_previous(j);
1956
67e04a48 1957 } else if (arg_lines >= 0) {
2100675e
LP
1958 r = sd_journal_seek_tail(j);
1959 if (r < 0) {
1960 log_error("Failed to seek to tail: %s", strerror(-r));
763c7aa2 1961 return EXIT_FAILURE;
2100675e
LP
1962 }
1963
1964 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 1965
d89d6c86
LN
1966 } else if (arg_reverse) {
1967 r = sd_journal_seek_tail(j);
1968 if (r < 0) {
1969 log_error("Failed to seek to tail: %s", strerror(-r));
763c7aa2 1970 return EXIT_FAILURE;
d89d6c86
LN
1971 }
1972
1973 r = sd_journal_previous(j);
1974
2100675e
LP
1975 } else {
1976 r = sd_journal_seek_head(j);
1977 if (r < 0) {
1978 log_error("Failed to seek to head: %s", strerror(-r));
763c7aa2 1979 return EXIT_FAILURE;
2100675e 1980 }
6f003b43
LP
1981
1982 r = sd_journal_next(j);
1983 }
1984
1985 if (r < 0) {
1986 log_error("Failed to iterate through journal: %s", strerror(-r));
763c7aa2 1987 return EXIT_FAILURE;
50f20cfd 1988 }
87d2c1ff 1989
faf5077f
DH
1990 if (!arg_follow)
1991 pager_open_if_enabled();
0d43c694 1992
cfbc22ab
LP
1993 if (!arg_quiet) {
1994 usec_t start, end;
1995 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1996
1997 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1998 if (r < 0) {
1999 log_error("Failed to get cutoff: %s", strerror(-r));
2000 goto finish;
2001 }
2002
2003 if (r > 0) {
2004 if (arg_follow)
9048b11f 2005 printf("-- Logs begin at %s. --\n",
5ab99e07 2006 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2007 else
9048b11f 2008 printf("-- Logs begin at %s, end at %s. --\n",
5ab99e07
LP
2009 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2010 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2011 }
2012 }
2013
50f20cfd 2014 for (;;) {
67e04a48 2015 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab
LP
2016 int flags;
2017
6f003b43 2018 if (need_seek) {
99613ec5 2019 if (!arg_reverse)
d89d6c86
LN
2020 r = sd_journal_next(j);
2021 else
2022 r = sd_journal_previous(j);
6f003b43
LP
2023 if (r < 0) {
2024 log_error("Failed to iterate through journal: %s", strerror(-r));
2025 goto finish;
2026 }
a72b6353
ZJS
2027 if (r == 0)
2028 break;
0d43c694
LP
2029 }
2030
d89d6c86 2031 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
2032 usec_t usec;
2033
2034 r = sd_journal_get_realtime_usec(j, &usec);
2035 if (r < 0) {
2036 log_error("Failed to determine timestamp: %s", strerror(-r));
2037 goto finish;
2038 }
3ba09ee8
PF
2039 if (usec > arg_until)
2040 goto finish;
cfbc22ab
LP
2041 }
2042
d89d6c86
LN
2043 if (arg_since_set && arg_reverse) {
2044 usec_t usec;
2045
2046 r = sd_journal_get_realtime_usec(j, &usec);
2047 if (r < 0) {
2048 log_error("Failed to determine timestamp: %s", strerror(-r));
2049 goto finish;
2050 }
2051 if (usec < arg_since)
2052 goto finish;
2053 }
2054
4bed2485 2055 if (!arg_merge && !arg_quiet) {
cd931c0a 2056 sd_id128_t boot_id;
14a65d65 2057
cd931c0a
LP
2058 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2059 if (r >= 0) {
2060 if (previous_boot_id_valid &&
2061 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c
DS
2062 printf("%s-- Reboot --%s\n",
2063 ansi_highlight(), ansi_highlight_off());
cd931c0a
LP
2064
2065 previous_boot_id = boot_id;
2066 previous_boot_id_valid = true;
2067 }
14a65d65
LP
2068 }
2069
cfbc22ab 2070 flags =
cd4b13e0 2071 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 2072 arg_full * OUTPUT_FULL_WIDTH |
d4205751 2073 on_tty() * OUTPUT_COLOR |
9fd29044
JS
2074 arg_catalog * OUTPUT_CATALOG |
2075 arg_utc * OUTPUT_UTC;
cfbc22ab 2076
94e0bd7d 2077 r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
a72b6353
ZJS
2078 need_seek = true;
2079 if (r == -EADDRNOTAVAIL)
2080 break;
2081 else if (r < 0 || ferror(stdout))
72f59706 2082 goto finish;
6f003b43 2083
cfbc22ab 2084 n_shown++;
87d2c1ff
LP
2085 }
2086
248fc619
ZJS
2087 if (!arg_follow) {
2088 if (arg_show_cursor) {
2089 _cleanup_free_ char *cursor = NULL;
2090
2091 r = sd_journal_get_cursor(j, &cursor);
2092 if (r < 0 && r != -EADDRNOTAVAIL)
2093 log_error("Failed to get cursor: %s", strerror(-r));
2094 else if (r >= 0)
2095 printf("-- cursor: %s\n", cursor);
2096 }
2097
50f20cfd 2098 break;
248fc619 2099 }
50f20cfd 2100
e02d1cf7 2101 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 2102 if (r < 0) {
7a69007a 2103 log_error("Couldn't wait for journal event: %s", strerror(-r));
50f20cfd
LP
2104 goto finish;
2105 }
67e04a48
ZJS
2106
2107 first_line = false;
de190aef 2108 }
87d2c1ff
LP
2109
2110finish:
0d43c694
LP
2111 pager_close();
2112
a36b8deb
ZJS
2113 strv_free(arg_file);
2114
3fbf9cbb 2115 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2116}