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