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