]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
Merge branch 'python-systemd-reader'
[thirdparty/systemd.git] / src / journal / journalctl.c
CommitLineData
87d2c1ff
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
87d2c1ff
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
87d2c1ff 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
87d2c1ff
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
a9cdc94f 22#include <locale.h>
87d2c1ff
LP
23#include <fcntl.h>
24#include <errno.h>
25#include <stddef.h>
3fbf9cbb
LP
26#include <string.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <stdlib.h>
50f20cfd 30#include <sys/poll.h>
72f59706 31#include <time.h>
0d43c694 32#include <getopt.h>
585314e8 33#include <signal.h>
50940700 34#include <sys/stat.h>
f982e6f7
LP
35#include <sys/ioctl.h>
36#include <linux/fs.h>
87d2c1ff 37
81527be1
LP
38#include <systemd/sd-journal.h>
39
3fbf9cbb 40#include "log.h"
72f59706 41#include "util.h"
e5124088 42#include "path-util.h"
0d43c694
LP
43#include "build.h"
44#include "pager.h"
86aa7ba4 45#include "logs-show.h"
a963990f 46#include "strv.h"
dca6219e 47#include "journal-internal.h"
7560fffc 48#include "journal-def.h"
0284adc6 49#include "journal-verify.h"
4da416aa 50#include "journal-authenticate.h"
f6a971bc 51#include "journal-qrcode.h"
4da416aa 52#include "fsprg.h"
c3f60ec5 53#include "unit-name.h"
d4205751 54#include "catalog.h"
7560fffc 55
baed47c3 56#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
250d54b5 57
df50185b 58static OutputMode arg_output = OUTPUT_SHORT;
72f59706 59static bool arg_follow = false;
e3657ecd 60static bool arg_full = false;
cd4b13e0 61static bool arg_all = false;
0d43c694 62static bool arg_no_pager = false;
67e04a48 63static int arg_lines = -1;
e91af489 64static bool arg_no_tail = false;
43673799 65static bool arg_quiet = false;
9e8a535f 66static bool arg_merge = false;
59cea26a 67static bool arg_this_boot = false;
8f14c832 68static const char *arg_cursor = NULL;
a963990f 69static const char *arg_directory = NULL;
941e990d 70static int arg_priorities = 0xFF;
baed47c3 71static const char *arg_verify_key = NULL;
feb12d3e 72#ifdef HAVE_GCRYPT
baed47c3 73static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
feb12d3e 74#endif
cfbc22ab
LP
75static usec_t arg_since, arg_until;
76static bool arg_since_set = false, arg_until_set = false;
c3f60ec5 77static const char *arg_unit = NULL;
3c1668da 78static const char *arg_field = NULL;
d4205751 79static bool arg_catalog = false;
50f20cfd 80
7560fffc
LP
81static enum {
82 ACTION_SHOW,
83 ACTION_NEW_ID128,
84 ACTION_PRINT_HEADER,
beec0085 85 ACTION_SETUP_KEYS,
a1a03e30
LP
86 ACTION_VERIFY,
87 ACTION_DISK_USAGE,
d4205751
LP
88 ACTION_LIST_CATALOG,
89 ACTION_UPDATE_CATALOG
7560fffc
LP
90} arg_action = ACTION_SHOW;
91
0d43c694
LP
92static int help(void) {
93
cd4b13e0 94 printf("%s [OPTIONS...] [MATCHES...]\n\n"
15119c16
LP
95 "Query the journal.\n\n"
96 "Flags:\n"
cfbc22ab
LP
97 " --since=DATE Start showing entries newer or of the specified date\n"
98 " --until=DATE Stop showing entries older or of the specified date\n"
cd4b13e0 99 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
c3f60ec5
LP
100 " -b --this-boot Show data only from current boot\n"
101 " -u --unit=UNIT Show data only from the specified unit\n"
cd4b13e0 102 " -p --priority=RANGE Show only messages within the specified priority range\n"
baed47c3 103 " -f --follow Follow journal\n"
1705594f 104 " -n --lines[=INTEGER] Number of journal entries to show\n"
baed47c3
LP
105 " --no-tail Show all lines, even in follow mode\n"
106 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
48383c25 107 " verbose, export, json, json-pretty, json-sse, cat)\n"
d4205751 108 " -x --catalog Add message explanations where available\n"
e3657ecd 109 " --full Do not ellipsize fields\n"
c3f60ec5 110 " -a --all Show all fields, including long and unprintable\n"
baed47c3 111 " -q --quiet Don't show privilege warning\n"
c3f60ec5 112 " --no-pager Do not pipe output into a pager\n"
9e8a535f 113 " -m --merge Show entries from all available journals\n"
baed47c3 114 " -D --directory=PATH Show journal files from directory\n"
15119c16
LP
115#ifdef HAVE_GCRYPT
116 " --interval=TIME Time interval for changing the FSS sealing key\n"
117 " --verify-key=KEY Specify FSS verification key\n"
118#endif
119 "\nCommands:\n"
120 " -h --help Show this help\n"
121 " --version Show package version\n"
baed47c3
LP
122 " --new-id128 Generate a new 128 Bit ID\n"
123 " --header Show journal header information\n"
a1a03e30 124 " --disk-usage Show total disk usage\n"
15119c16 125 " -F --field=FIELD List all values a certain field takes\n"
d4205751
LP
126 " --list-catalog Show message IDs of all entries in the message catalog\n"
127 " --update-catalog Update the message catalog database\n"
feb12d3e 128#ifdef HAVE_GCRYPT
baed47c3 129 " --setup-keys Generate new FSS key pair\n"
baed47c3 130 " --verify Verify journal file consistency\n"
feb12d3e
LP
131#endif
132 , program_invocation_short_name);
0d43c694
LP
133
134 return 0;
135}
136
137static int parse_argv(int argc, char *argv[]) {
138
139 enum {
140 ARG_VERSION = 0x100,
e91af489 141 ARG_NO_PAGER,
55ee336c 142 ARG_NO_TAIL,
dca6219e 143 ARG_NEW_ID128,
7560fffc 144 ARG_HEADER,
e3657ecd 145 ARG_FULL,
beec0085 146 ARG_SETUP_KEYS,
baed47c3 147 ARG_INTERVAL,
4da416aa 148 ARG_VERIFY,
a1a03e30 149 ARG_VERIFY_KEY,
cfbc22ab
LP
150 ARG_DISK_USAGE,
151 ARG_SINCE,
d4205751
LP
152 ARG_UNTIL,
153 ARG_LIST_CATALOG,
154 ARG_UPDATE_CATALOG
0d43c694
LP
155 };
156
157 static const struct option options[] = {
baed47c3
LP
158 { "help", no_argument, NULL, 'h' },
159 { "version" , no_argument, NULL, ARG_VERSION },
160 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
161 { "follow", no_argument, NULL, 'f' },
162 { "output", required_argument, NULL, 'o' },
163 { "all", no_argument, NULL, 'a' },
e3657ecd 164 { "full", no_argument, NULL, ARG_FULL },
1705594f 165 { "lines", optional_argument, NULL, 'n' },
baed47c3
LP
166 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
167 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
168 { "quiet", no_argument, NULL, 'q' },
9e8a535f 169 { "merge", no_argument, NULL, 'm' },
baed47c3
LP
170 { "this-boot", no_argument, NULL, 'b' },
171 { "directory", required_argument, NULL, 'D' },
172 { "header", no_argument, NULL, ARG_HEADER },
71c01596 173 { "priority", required_argument, NULL, 'p' },
baed47c3
LP
174 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
175 { "interval", required_argument, NULL, ARG_INTERVAL },
176 { "verify", no_argument, NULL, ARG_VERIFY },
177 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
a1a03e30 178 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
ad9eafab 179 { "cursor", required_argument, NULL, 'c' },
cfbc22ab
LP
180 { "since", required_argument, NULL, ARG_SINCE },
181 { "until", required_argument, NULL, ARG_UNTIL },
c3f60ec5 182 { "unit", required_argument, NULL, 'u' },
15119c16 183 { "field", required_argument, NULL, 'F' },
d4205751
LP
184 { "catalog", no_argument, NULL, 'x' },
185 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
186 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
baed47c3 187 { NULL, 0, NULL, 0 }
0d43c694
LP
188 };
189
2100675e 190 int c, r;
0d43c694
LP
191
192 assert(argc >= 0);
193 assert(argv);
194
d4205751 195 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:x", options, NULL)) >= 0) {
0d43c694
LP
196
197 switch (c) {
198
199 case 'h':
200 help();
201 return 0;
202
203 case ARG_VERSION:
204 puts(PACKAGE_STRING);
0d43c694
LP
205 puts(SYSTEMD_FEATURES);
206 return 0;
207
208 case ARG_NO_PAGER:
209 arg_no_pager = true;
210 break;
211
212 case 'f':
213 arg_follow = true;
214 break;
215
216 case 'o':
1705594f 217 arg_output = output_mode_from_string(optarg);
df50185b 218 if (arg_output < 0) {
edfb521a 219 log_error("Unknown output format '%s'.", optarg);
0d43c694
LP
220 return -EINVAL;
221 }
df50185b 222
edfb521a
ZJS
223 if (arg_output == OUTPUT_EXPORT ||
224 arg_output == OUTPUT_JSON ||
225 arg_output == OUTPUT_JSON_PRETTY ||
226 arg_output == OUTPUT_JSON_SSE ||
227 arg_output == OUTPUT_CAT)
228 arg_quiet = true;
229
0d43c694
LP
230 break;
231
e3657ecd
ZJS
232 case ARG_FULL:
233 arg_full = true;
234 break;
235
0d43c694 236 case 'a':
cd4b13e0 237 arg_all = true;
0d43c694
LP
238 break;
239
2100675e 240 case 'n':
1705594f 241 if (optarg) {
67e04a48
ZJS
242 r = safe_atoi(optarg, &arg_lines);
243 if (r < 0 || arg_lines < 0) {
1705594f
LP
244 log_error("Failed to parse lines '%s'", optarg);
245 return -EINVAL;
246 }
96088db0
LP
247 } else {
248 int n;
249
250 /* Hmm, no argument? Maybe the next
251 * word on the command line is
252 * supposed to be the argument? Let's
253 * see if there is one, and is
254 * parsable as a positive
255 * integer... */
256
257 if (optind < argc &&
258 safe_atoi(argv[optind], &n) >= 0 &&
259 n >= 0) {
260
261 arg_lines = n;
262 optind++;
263 } else
264 arg_lines = 10;
265 }
1705594f 266
2100675e
LP
267 break;
268
e91af489
LP
269 case ARG_NO_TAIL:
270 arg_no_tail = true;
271 break;
272
39f7f5c1 273 case ARG_NEW_ID128:
7560fffc 274 arg_action = ACTION_NEW_ID128;
55ee336c
LP
275 break;
276
43673799
LP
277 case 'q':
278 arg_quiet = true;
490e567d 279 break;
43673799 280
9e8a535f
LP
281 case 'm':
282 arg_merge = true;
2bd3c38a
LP
283 break;
284
59cea26a
LP
285 case 'b':
286 arg_this_boot = true;
287 break;
288
a963990f
LP
289 case 'D':
290 arg_directory = optarg;
291 break;
292
8f14c832
LP
293 case 'c':
294 arg_cursor = optarg;
295 break;
296
dca6219e 297 case ARG_HEADER:
7560fffc
LP
298 arg_action = ACTION_PRINT_HEADER;
299 break;
300
feb12d3e
LP
301 case ARG_VERIFY:
302 arg_action = ACTION_VERIFY;
303 break;
304
a1a03e30
LP
305 case ARG_DISK_USAGE:
306 arg_action = ACTION_DISK_USAGE;
307 break;
308
feb12d3e 309#ifdef HAVE_GCRYPT
7560fffc
LP
310 case ARG_SETUP_KEYS:
311 arg_action = ACTION_SETUP_KEYS;
dca6219e
LP
312 break;
313
beec0085 314
baed47c3 315 case ARG_VERIFY_KEY:
4da416aa 316 arg_action = ACTION_VERIFY;
baed47c3 317 arg_verify_key = optarg;
9e8a535f 318 arg_merge = false;
4da416aa
LP
319 break;
320
baed47c3
LP
321 case ARG_INTERVAL:
322 r = parse_usec(optarg, &arg_interval);
323 if (r < 0 || arg_interval <= 0) {
324 log_error("Failed to parse sealing key change interval: %s", optarg);
14d10188
LP
325 return -EINVAL;
326 }
327 break;
feb12d3e
LP
328#else
329 case ARG_SETUP_KEYS:
330 case ARG_VERIFY_KEY:
331 case ARG_INTERVAL:
332 log_error("Forward-secure sealing not available.");
333 return -ENOTSUP;
334#endif
14d10188 335
941e990d
LP
336 case 'p': {
337 const char *dots;
338
339 dots = strstr(optarg, "..");
340 if (dots) {
341 char *a;
342 int from, to, i;
343
344 /* a range */
345 a = strndup(optarg, dots - optarg);
346 if (!a)
347 return log_oom();
348
349 from = log_level_from_string(a);
350 to = log_level_from_string(dots + 2);
351 free(a);
352
353 if (from < 0 || to < 0) {
354 log_error("Failed to parse log level range %s", optarg);
355 return -EINVAL;
356 }
357
358 arg_priorities = 0;
359
360 if (from < to) {
361 for (i = from; i <= to; i++)
362 arg_priorities |= 1 << i;
363 } else {
364 for (i = to; i <= from; i++)
365 arg_priorities |= 1 << i;
366 }
367
368 } else {
369 int p, i;
370
371 p = log_level_from_string(optarg);
372 if (p < 0) {
373 log_error("Unknown log level %s", optarg);
374 return -EINVAL;
375 }
376
377 arg_priorities = 0;
378
379 for (i = 0; i <= p; i++)
380 arg_priorities |= 1 << i;
381 }
382
383 break;
384 }
385
cfbc22ab
LP
386 case ARG_SINCE:
387 r = parse_timestamp(optarg, &arg_since);
388 if (r < 0) {
389 log_error("Failed to parse timestamp: %s", optarg);
390 return -EINVAL;
391 }
392 arg_since_set = true;
393 break;
394
395 case ARG_UNTIL:
396 r = parse_timestamp(optarg, &arg_until);
397 if (r < 0) {
398 log_error("Failed to parse timestamp: %s", optarg);
399 return -EINVAL;
400 }
401 arg_until_set = true;
402 break;
403
c3f60ec5
LP
404 case 'u':
405 arg_unit = optarg;
406 break;
407
0d43c694
LP
408 case '?':
409 return -EINVAL;
410
15119c16
LP
411 case 'F':
412 arg_field = optarg;
413 break;
414
d4205751
LP
415 case 'x':
416 arg_catalog = true;
417 break;
418
419 case ARG_LIST_CATALOG:
420 arg_action = ACTION_LIST_CATALOG;
421 break;
422
423 case ARG_UPDATE_CATALOG:
424 arg_action = ACTION_UPDATE_CATALOG;
425 break;
426
0d43c694
LP
427 default:
428 log_error("Unknown option code %c", c);
429 return -EINVAL;
430 }
431 }
432
67e04a48 433 if (arg_follow && !arg_no_tail && arg_lines < 0)
e91af489
LP
434 arg_lines = 10;
435
3ba09ee8 436 if (arg_since_set && arg_until_set && arg_since > arg_until) {
cfbc22ab
LP
437 log_error("--since= must be before --until=.");
438 return -EINVAL;
439 }
440
441 if (arg_cursor && arg_since_set) {
442 log_error("Please specify either --since= or --cursor=, not both.");
443 return -EINVAL;
444 }
445
0d43c694
LP
446 return 1;
447}
448
39f7f5c1 449static int generate_new_id128(void) {
55ee336c
LP
450 sd_id128_t id;
451 int r;
452 unsigned i;
453
454 r = sd_id128_randomize(&id);
455 if (r < 0) {
456 log_error("Failed to generate ID: %s", strerror(-r));
457 return r;
458 }
459
460 printf("As string:\n"
461 SD_ID128_FORMAT_STR "\n\n"
462 "As UUID:\n"
463 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
464 "As macro:\n"
d489071f 465 "#define MESSAGE_XYZ SD_ID128_MAKE(",
55ee336c
LP
466 SD_ID128_FORMAT_VAL(id),
467 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
468 for (i = 0; i < 16; i++)
469 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
d489071f 470 fputs(")\n\n", stdout);
55ee336c 471
d489071f
ZJS
472 printf("As Python constant:\n"
473 ">>> import uuid\n"
474 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
475 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
476
477 return 0;
478}
479
a963990f
LP
480static int add_matches(sd_journal *j, char **args) {
481 char **i;
482 int r;
59cea26a 483
a963990f 484 assert(j);
59cea26a 485
a963990f 486 STRV_FOREACH(i, args) {
59cea26a 487
cbdca852
LP
488 if (streq(*i, "+"))
489 r = sd_journal_add_disjunction(j);
490 else if (path_is_absolute(*i)) {
b6a34514 491 char *p, *t = NULL;
e5124088 492 const char *path;
a963990f 493 struct stat st;
e5124088 494
a963990f
LP
495 p = canonicalize_file_name(*i);
496 path = p ? p : *i;
e5124088
LP
497
498 if (stat(path, &st) < 0) {
499 free(p);
500 log_error("Couldn't stat file: %m");
a963990f 501 return -errno;
e5124088
LP
502 }
503
b6a34514 504 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
e5124088 505 t = strappend("_EXE=", path);
b6a34514
LP
506 else if (S_ISCHR(st.st_mode))
507 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
508 else if (S_ISBLK(st.st_mode))
509 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
510 else {
e5124088 511 free(p);
b6a34514 512 log_error("File is not a device node, regular file or is not executable: %s", *i);
a963990f 513 return -EINVAL;
50940700 514 }
e5124088
LP
515
516 free(p);
b6a34514
LP
517
518 if (!t)
519 return log_oom();
520
521 r = sd_journal_add_match(j, t, 0);
522 free(t);
e5124088 523 } else
cbdca852 524 r = sd_journal_add_match(j, *i, 0);
e5124088 525
de7b95cd 526 if (r < 0) {
cbdca852 527 log_error("Failed to add match '%s': %s", *i, strerror(-r));
a963990f 528 return r;
de7b95cd
LP
529 }
530 }
531
a963990f
LP
532 return 0;
533}
534
535static int add_this_boot(sd_journal *j) {
536 char match[9+32+1] = "_BOOT_ID=";
537 sd_id128_t boot_id;
538 int r;
539
941e990d
LP
540 assert(j);
541
a963990f
LP
542 if (!arg_this_boot)
543 return 0;
544
545 r = sd_id128_get_boot(&boot_id);
546 if (r < 0) {
547 log_error("Failed to get boot id: %s", strerror(-r));
548 return r;
549 }
550
551 sd_id128_to_string(boot_id, match + 9);
552 r = sd_journal_add_match(j, match, strlen(match));
553 if (r < 0) {
554 log_error("Failed to add match: %s", strerror(-r));
555 return r;
556 }
557
558 return 0;
559}
560
c3f60ec5
LP
561static int add_unit(sd_journal *j) {
562 _cleanup_free_ char *m = NULL, *u = NULL;
563 int r;
564
565 assert(j);
566
567 if (isempty(arg_unit))
568 return 0;
569
570 u = unit_name_mangle(arg_unit);
571 if (!u)
572 return log_oom();
573
574 m = strappend("_SYSTEMD_UNIT=", u);
575 if (!m)
576 return log_oom();
577
578 r = sd_journal_add_match(j, m, strlen(m));
579 if (r < 0) {
580 log_error("Failed to add match: %s", strerror(-r));
581 return r;
582 }
583
584 return 0;
585}
586
941e990d
LP
587static int add_priorities(sd_journal *j) {
588 char match[] = "PRIORITY=0";
589 int i, r;
590
591 assert(j);
592
593 if (arg_priorities == 0xFF)
594 return 0;
595
596 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
597 if (arg_priorities & (1 << i)) {
598 match[sizeof(match)-2] = '0' + i;
599
941e990d
LP
600 r = sd_journal_add_match(j, match, strlen(match));
601 if (r < 0) {
602 log_error("Failed to add match: %s", strerror(-r));
603 return r;
604 }
605 }
606
607 return 0;
608}
609
7560fffc
LP
610static int setup_keys(void) {
611#ifdef HAVE_GCRYPT
612 size_t mpk_size, seed_size, state_size, i;
613 uint8_t *mpk, *seed, *state;
614 ssize_t l;
f982e6f7 615 int fd = -1, r, attr = 0;
7560fffc
LP
616 sd_id128_t machine, boot;
617 char *p = NULL, *k = NULL;
baed47c3 618 struct FSSHeader h;
14d10188 619 uint64_t n;
7560fffc
LP
620
621 r = sd_id128_get_machine(&machine);
622 if (r < 0) {
623 log_error("Failed to get machine ID: %s", strerror(-r));
624 return r;
625 }
626
627 r = sd_id128_get_boot(&boot);
628 if (r < 0) {
629 log_error("Failed to get boot ID: %s", strerror(-r));
630 return r;
631 }
632
baed47c3 633 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
634 SD_ID128_FORMAT_VAL(machine)) < 0)
635 return log_oom();
636
637 if (access(p, F_OK) >= 0) {
f7fab8a5 638 log_error("Sealing key file %s exists already.", p);
7560fffc
LP
639 r = -EEXIST;
640 goto finish;
641 }
642
baed47c3 643 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
644 SD_ID128_FORMAT_VAL(machine)) < 0) {
645 r = log_oom();
646 goto finish;
647 }
648
649 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
650 mpk = alloca(mpk_size);
651
652 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
653 seed = alloca(seed_size);
654
655 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
656 state = alloca(state_size);
657
658 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
659 if (fd < 0) {
660 log_error("Failed to open /dev/random: %m");
661 r = -errno;
662 goto finish;
663 }
664
665 log_info("Generating seed...");
666 l = loop_read(fd, seed, seed_size, true);
667 if (l < 0 || (size_t) l != seed_size) {
668 log_error("Failed to read random seed: %s", strerror(EIO));
669 r = -EIO;
670 goto finish;
671 }
672
673 log_info("Generating key pair...");
674 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
675
baed47c3 676 log_info("Generating sealing key...");
7560fffc
LP
677 FSPRG_GenState0(state, mpk, seed, seed_size);
678
baed47c3
LP
679 assert(arg_interval > 0);
680
7560fffc 681 n = now(CLOCK_REALTIME);
baed47c3 682 n /= arg_interval;
7560fffc
LP
683
684 close_nointr_nofail(fd);
685 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
686 if (fd < 0) {
687 log_error("Failed to open %s: %m", k);
688 r = -errno;
689 goto finish;
690 }
691
f982e6f7
LP
692 /* Enable secure remove, exclusion from dump, synchronous
693 * writing and in-place updating */
694 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
695 log_warning("FS_IOC_GETFLAGS failed: %m");
696
697 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
698
699 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
700 log_warning("FS_IOC_SETFLAGS failed: %m");
701
7560fffc
LP
702 zero(h);
703 memcpy(h.signature, "KSHHRHLP", 8);
704 h.machine_id = machine;
705 h.boot_id = boot;
706 h.header_size = htole64(sizeof(h));
baed47c3
LP
707 h.start_usec = htole64(n * arg_interval);
708 h.interval_usec = htole64(arg_interval);
709 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
710 h.fsprg_state_size = htole64(state_size);
7560fffc
LP
711
712 l = loop_write(fd, &h, sizeof(h), false);
713 if (l < 0 || (size_t) l != sizeof(h)) {
714 log_error("Failed to write header: %s", strerror(EIO));
715 r = -EIO;
716 goto finish;
717 }
718
719 l = loop_write(fd, state, state_size, false);
720 if (l < 0 || (size_t) l != state_size) {
721 log_error("Failed to write state: %s", strerror(EIO));
722 r = -EIO;
723 goto finish;
724 }
725
726 if (link(k, p) < 0) {
727 log_error("Failed to link file: %m");
728 r = -errno;
729 goto finish;
730 }
731
8481248b 732 if (on_tty()) {
7560fffc
LP
733 fprintf(stderr,
734 "\n"
baed47c3 735 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
c05276f2
LP
736 "the following local file. This key file is automatically updated when the\n"
737 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
738 "\n"
739 "\t%s\n"
740 "\n"
baed47c3
LP
741 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
742 "at a safe location and should not be saved locally on disk.\n"
7560fffc
LP
743 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
744 fflush(stderr);
745 }
746 for (i = 0; i < seed_size; i++) {
747 if (i > 0 && i % 3 == 0)
748 putchar('-');
749 printf("%02x", ((uint8_t*) seed)[i]);
750 }
751
baed47c3
LP
752 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
753
8481248b 754 if (on_tty()) {
f6a971bc 755 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 756
baed47c3
LP
757 fprintf(stderr,
758 ANSI_HIGHLIGHT_OFF "\n"
759 "The sealing key is automatically changed every %s.\n",
760 format_timespan(tsb, sizeof(tsb), arg_interval));
f6a971bc
LP
761
762 hn = gethostname_malloc();
763
764 if (hn) {
765 hostname_cleanup(hn);
adac1c93 766 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 767 } else
adac1c93 768 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc
LP
769
770#ifdef HAVE_QRENCODE
cf5a3432 771 /* If this is not an UTF-8 system don't print any QR codes */
09017585 772 if (is_locale_utf8()) {
cf5a3432
LP
773 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
774 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
775 }
f6a971bc
LP
776#endif
777 free(hn);
baed47c3 778 }
7560fffc
LP
779
780 r = 0;
781
782finish:
783 if (fd >= 0)
784 close_nointr_nofail(fd);
785
786 if (k) {
787 unlink(k);
788 free(k);
789 }
790
791 free(p);
792
793 return r;
794#else
feb12d3e
LP
795 log_error("Forward-secure sealing not available.");
796 return -ENOTSUP;
7560fffc
LP
797#endif
798}
799
beec0085
LP
800static int verify(sd_journal *j) {
801 int r = 0;
802 Iterator i;
803 JournalFile *f;
804
805 assert(j);
806
cedb42bb
LP
807 log_show_color(true);
808
beec0085
LP
809 HASHMAP_FOREACH(f, j->files, i) {
810 int k;
2a7b539a 811 usec_t first, validated, last;
beec0085 812
56e81f7c 813#ifdef HAVE_GCRYPT
feb12d3e 814 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 815 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 816#endif
4da416aa 817
2a7b539a 818 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 819 if (k == -EINVAL) {
baed47c3 820 /* If the key was invalid give up right-away. */
56e81f7c
LP
821 return k;
822 } else if (k < 0) {
beec0085 823 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
56e81f7c 824 r = k;
6c7be122
LP
825 } else {
826 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 827 log_info("PASS: %s", f->path);
6c7be122 828
c0ca7aee 829 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 830 if (validated > 0) {
c0ca7aee 831 log_info("=> Validated from %s to %s, final %s entries not sealed.",
2a7b539a
LP
832 format_timestamp(a, sizeof(a), first),
833 format_timestamp(b, sizeof(b), validated),
834 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
835 } else if (last > 0)
c0ca7aee 836 log_info("=> No sealing yet, %s of entries not sealed.",
2a7b539a 837 format_timespan(c, sizeof(c), last - first));
c0ca7aee
LP
838 else
839 log_info("=> No sealing yet, no entries in file.");
840 }
6c7be122 841 }
beec0085
LP
842 }
843
844 return r;
845}
846
15804ceb
LP
847static int access_check(void) {
848
849#ifdef HAVE_ACL
850 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
851 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
852 return -EACCES;
853 }
854
855 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
856 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
857#else
858 if (geteuid() != 0 && in_group("adm") <= 0) {
859 log_error("No access to messages. Only users in the group 'adm' can see messages.");
860 return -EACCES;
861 }
862#endif
863
864 return 0;
865}
866
a963990f
LP
867int main(int argc, char *argv[]) {
868 int r;
869 sd_journal *j = NULL;
a963990f 870 bool need_seek = false;
14a65d65 871 sd_id128_t previous_boot_id;
67e04a48
ZJS
872 bool previous_boot_id_valid = false, first_line = true;
873 int n_shown = 0;
a963990f 874
a9cdc94f 875 setlocale(LC_ALL, "");
a963990f
LP
876 log_parse_environment();
877 log_open();
878
879 r = parse_argv(argc, argv);
880 if (r <= 0)
881 goto finish;
882
ed757c0c
LP
883 signal(SIGWINCH, columns_lines_cache_reset);
884
7560fffc 885 if (arg_action == ACTION_NEW_ID128) {
a963990f
LP
886 r = generate_new_id128();
887 goto finish;
888 }
889
7560fffc
LP
890 if (arg_action == ACTION_SETUP_KEYS) {
891 r = setup_keys();
892 goto finish;
893 }
894
d4205751
LP
895 if (arg_action == ACTION_LIST_CATALOG) {
896 r = catalog_list(stdout);
83f6936a
LP
897 if (r < 0)
898 log_error("Failed to list catalog: %s", strerror(-r));
d4205751
LP
899 goto finish;
900 }
901
902 if (arg_action == ACTION_UPDATE_CATALOG) {
903 r = catalog_update();
904 goto finish;
905 }
906
15804ceb
LP
907 r = access_check();
908 if (r < 0)
909 goto finish;
910
a963990f
LP
911 if (arg_directory)
912 r = sd_journal_open_directory(&j, arg_directory, 0);
913 else
9e8a535f 914 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
a963990f
LP
915 if (r < 0) {
916 log_error("Failed to open journal: %s", strerror(-r));
917 goto finish;
918 }
919
beec0085
LP
920 if (arg_action == ACTION_VERIFY) {
921 r = verify(j);
922 goto finish;
923 }
924
7560fffc 925 if (arg_action == ACTION_PRINT_HEADER) {
dca6219e
LP
926 journal_print_header(j);
927 r = 0;
928 goto finish;
929 }
930
a1a03e30
LP
931 if (arg_action == ACTION_DISK_USAGE) {
932 uint64_t bytes;
933 char sbytes[FORMAT_BYTES_MAX];
934
935 r = sd_journal_get_usage(j, &bytes);
936 if (r < 0)
937 goto finish;
938
939 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
940 r = 0;
941 goto finish;
942 }
943
a963990f
LP
944 r = add_this_boot(j);
945 if (r < 0)
946 goto finish;
947
c3f60ec5
LP
948 r = add_unit(j);
949 if (r < 0)
950 goto finish;
951
a963990f
LP
952 r = add_matches(j, argv + optind);
953 if (r < 0)
954 goto finish;
955
941e990d
LP
956 r = add_priorities(j);
957 if (r < 0)
958 goto finish;
959
67e04a48
ZJS
960 /* Opening the fd now means the first sd_journal_wait() will actually wait */
961 r = sd_journal_get_fd(j);
962 if (r < 0)
963 goto finish;
964
15119c16
LP
965 if (arg_field) {
966 const void *data;
967 size_t size;
968
969 r = sd_journal_query_unique(j, arg_field);
970 if (r < 0) {
971 log_error("Failed to query unique data objects: %s", strerror(-r));
972 goto finish;
973 }
974
975 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
976 const void *eq;
977
67e04a48 978 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
979 break;
980
15119c16
LP
981 eq = memchr(data, '=', size);
982 if (eq)
983 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
984 else
985 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875
LP
986
987 n_shown ++;
15119c16
LP
988 }
989
990 r = 0;
991 goto finish;
992 }
993
cfbc22ab
LP
994 if (arg_cursor) {
995 r = sd_journal_seek_cursor(j, arg_cursor);
08984293 996 if (r < 0) {
cfbc22ab 997 log_error("Failed to seek to cursor: %s", strerror(-r));
08984293
LP
998 goto finish;
999 }
1000
cfbc22ab 1001 r = sd_journal_next(j);
08984293 1002
cfbc22ab
LP
1003 } else if (arg_since_set) {
1004 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 1005 if (r < 0) {
cfbc22ab 1006 log_error("Failed to seek to date: %s", strerror(-r));
8f14c832
LP
1007 goto finish;
1008 }
8f14c832
LP
1009 r = sd_journal_next(j);
1010
67e04a48 1011 } else if (arg_lines >= 0) {
2100675e
LP
1012 r = sd_journal_seek_tail(j);
1013 if (r < 0) {
1014 log_error("Failed to seek to tail: %s", strerror(-r));
1015 goto finish;
1016 }
1017
1018 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 1019
2100675e
LP
1020 } else {
1021 r = sd_journal_seek_head(j);
1022 if (r < 0) {
1023 log_error("Failed to seek to head: %s", strerror(-r));
1024 goto finish;
1025 }
6f003b43
LP
1026
1027 r = sd_journal_next(j);
1028 }
1029
1030 if (r < 0) {
1031 log_error("Failed to iterate through journal: %s", strerror(-r));
1032 goto finish;
50f20cfd 1033 }
87d2c1ff 1034
f89a3b6f
LP
1035 if (!arg_no_pager && !arg_follow)
1036 pager_open();
0d43c694 1037
cfbc22ab
LP
1038 if (!arg_quiet) {
1039 usec_t start, end;
1040 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1041
1042 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1043 if (r < 0) {
1044 log_error("Failed to get cutoff: %s", strerror(-r));
1045 goto finish;
1046 }
1047
1048 if (r > 0) {
1049 if (arg_follow)
9048b11f
LP
1050 printf("-- Logs begin at %s. --\n",
1051 format_timestamp(start_buf, sizeof(start_buf), start));
cfbc22ab 1052 else
9048b11f 1053 printf("-- Logs begin at %s, end at %s. --\n",
cfbc22ab
LP
1054 format_timestamp(start_buf, sizeof(start_buf), start),
1055 format_timestamp(end_buf, sizeof(end_buf), end));
1056 }
1057 }
1058
50f20cfd 1059 for (;;) {
67e04a48 1060 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab
LP
1061 int flags;
1062
6f003b43
LP
1063 if (need_seek) {
1064 r = sd_journal_next(j);
1065 if (r < 0) {
1066 log_error("Failed to iterate through journal: %s", strerror(-r));
1067 goto finish;
1068 }
0d43c694
LP
1069 }
1070
1071 if (r == 0)
1072 break;
1073
cfbc22ab
LP
1074 if (arg_until_set) {
1075 usec_t usec;
1076
1077 r = sd_journal_get_realtime_usec(j, &usec);
1078 if (r < 0) {
1079 log_error("Failed to determine timestamp: %s", strerror(-r));
1080 goto finish;
1081 }
3ba09ee8
PF
1082 if (usec > arg_until)
1083 goto finish;
cfbc22ab
LP
1084 }
1085
cd931c0a
LP
1086 if (!arg_merge) {
1087 sd_id128_t boot_id;
14a65d65 1088
cd931c0a
LP
1089 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1090 if (r >= 0) {
1091 if (previous_boot_id_valid &&
1092 !sd_id128_equal(boot_id, previous_boot_id))
9048b11f 1093 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
cd931c0a
LP
1094
1095 previous_boot_id = boot_id;
1096 previous_boot_id_valid = true;
1097 }
14a65d65
LP
1098 }
1099
cfbc22ab 1100 flags =
cd4b13e0 1101 arg_all * OUTPUT_SHOW_ALL |
e3657ecd 1102 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
d4205751
LP
1103 on_tty() * OUTPUT_COLOR |
1104 arg_catalog * OUTPUT_CATALOG;
cfbc22ab 1105
08ace05b 1106 r = output_journal(stdout, j, arg_output, 0, flags);
244692cb 1107 if (r < 0 || ferror(stdout))
72f59706 1108 goto finish;
6f003b43
LP
1109
1110 need_seek = true;
cfbc22ab 1111 n_shown++;
87d2c1ff
LP
1112 }
1113
50f20cfd
LP
1114 if (!arg_follow)
1115 break;
1116
e02d1cf7 1117 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 1118 if (r < 0) {
7a69007a 1119 log_error("Couldn't wait for journal event: %s", strerror(-r));
50f20cfd
LP
1120 goto finish;
1121 }
67e04a48
ZJS
1122
1123 first_line = false;
de190aef 1124 }
87d2c1ff
LP
1125
1126finish:
3fbf9cbb
LP
1127 if (j)
1128 sd_journal_close(j);
87d2c1ff 1129
0d43c694
LP
1130 pager_close();
1131
3fbf9cbb 1132 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 1133}