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