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