]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
update TODO
[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;
cfbc22ab 63static unsigned arg_lines = 0;
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) {
cfbc22ab
LP
242 r = safe_atou(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 }
247 } else
248 arg_lines = 10;
249
2100675e
LP
250 break;
251
e91af489
LP
252 case ARG_NO_TAIL:
253 arg_no_tail = true;
254 break;
255
39f7f5c1 256 case ARG_NEW_ID128:
7560fffc 257 arg_action = ACTION_NEW_ID128;
55ee336c
LP
258 break;
259
43673799
LP
260 case 'q':
261 arg_quiet = true;
490e567d 262 break;
43673799 263
9e8a535f
LP
264 case 'm':
265 arg_merge = true;
2bd3c38a
LP
266 break;
267
59cea26a
LP
268 case 'b':
269 arg_this_boot = true;
270 break;
271
a963990f
LP
272 case 'D':
273 arg_directory = optarg;
274 break;
275
8f14c832
LP
276 case 'c':
277 arg_cursor = optarg;
278 break;
279
dca6219e 280 case ARG_HEADER:
7560fffc
LP
281 arg_action = ACTION_PRINT_HEADER;
282 break;
283
feb12d3e
LP
284 case ARG_VERIFY:
285 arg_action = ACTION_VERIFY;
286 break;
287
a1a03e30
LP
288 case ARG_DISK_USAGE:
289 arg_action = ACTION_DISK_USAGE;
290 break;
291
feb12d3e 292#ifdef HAVE_GCRYPT
7560fffc
LP
293 case ARG_SETUP_KEYS:
294 arg_action = ACTION_SETUP_KEYS;
dca6219e
LP
295 break;
296
beec0085 297
baed47c3 298 case ARG_VERIFY_KEY:
4da416aa 299 arg_action = ACTION_VERIFY;
baed47c3 300 arg_verify_key = optarg;
9e8a535f 301 arg_merge = false;
4da416aa
LP
302 break;
303
baed47c3
LP
304 case ARG_INTERVAL:
305 r = parse_usec(optarg, &arg_interval);
306 if (r < 0 || arg_interval <= 0) {
307 log_error("Failed to parse sealing key change interval: %s", optarg);
14d10188
LP
308 return -EINVAL;
309 }
310 break;
feb12d3e
LP
311#else
312 case ARG_SETUP_KEYS:
313 case ARG_VERIFY_KEY:
314 case ARG_INTERVAL:
315 log_error("Forward-secure sealing not available.");
316 return -ENOTSUP;
317#endif
14d10188 318
941e990d
LP
319 case 'p': {
320 const char *dots;
321
322 dots = strstr(optarg, "..");
323 if (dots) {
324 char *a;
325 int from, to, i;
326
327 /* a range */
328 a = strndup(optarg, dots - optarg);
329 if (!a)
330 return log_oom();
331
332 from = log_level_from_string(a);
333 to = log_level_from_string(dots + 2);
334 free(a);
335
336 if (from < 0 || to < 0) {
337 log_error("Failed to parse log level range %s", optarg);
338 return -EINVAL;
339 }
340
341 arg_priorities = 0;
342
343 if (from < to) {
344 for (i = from; i <= to; i++)
345 arg_priorities |= 1 << i;
346 } else {
347 for (i = to; i <= from; i++)
348 arg_priorities |= 1 << i;
349 }
350
351 } else {
352 int p, i;
353
354 p = log_level_from_string(optarg);
355 if (p < 0) {
356 log_error("Unknown log level %s", optarg);
357 return -EINVAL;
358 }
359
360 arg_priorities = 0;
361
362 for (i = 0; i <= p; i++)
363 arg_priorities |= 1 << i;
364 }
365
366 break;
367 }
368
cfbc22ab
LP
369 case ARG_SINCE:
370 r = parse_timestamp(optarg, &arg_since);
371 if (r < 0) {
372 log_error("Failed to parse timestamp: %s", optarg);
373 return -EINVAL;
374 }
375 arg_since_set = true;
376 break;
377
378 case ARG_UNTIL:
379 r = parse_timestamp(optarg, &arg_until);
380 if (r < 0) {
381 log_error("Failed to parse timestamp: %s", optarg);
382 return -EINVAL;
383 }
384 arg_until_set = true;
385 break;
386
c3f60ec5
LP
387 case 'u':
388 arg_unit = optarg;
389 break;
390
0d43c694
LP
391 case '?':
392 return -EINVAL;
393
15119c16
LP
394 case 'F':
395 arg_field = optarg;
396 break;
397
d4205751
LP
398 case 'x':
399 arg_catalog = true;
400 break;
401
402 case ARG_LIST_CATALOG:
403 arg_action = ACTION_LIST_CATALOG;
404 break;
405
406 case ARG_UPDATE_CATALOG:
407 arg_action = ACTION_UPDATE_CATALOG;
408 break;
409
0d43c694
LP
410 default:
411 log_error("Unknown option code %c", c);
412 return -EINVAL;
413 }
414 }
415
cfbc22ab 416 if (arg_follow && !arg_no_tail && arg_lines <= 0)
e91af489
LP
417 arg_lines = 10;
418
cfbc22ab
LP
419 if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
420 log_error("--since= must be before --until=.");
421 return -EINVAL;
422 }
423
424 if (arg_cursor && arg_since_set) {
425 log_error("Please specify either --since= or --cursor=, not both.");
426 return -EINVAL;
427 }
428
0d43c694
LP
429 return 1;
430}
431
39f7f5c1 432static int generate_new_id128(void) {
55ee336c
LP
433 sd_id128_t id;
434 int r;
435 unsigned i;
436
437 r = sd_id128_randomize(&id);
438 if (r < 0) {
439 log_error("Failed to generate ID: %s", strerror(-r));
440 return r;
441 }
442
443 printf("As string:\n"
444 SD_ID128_FORMAT_STR "\n\n"
445 "As UUID:\n"
446 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
447 "As macro:\n"
448 "#define MESSAGE_XYZ SD_ID128_MAKE(",
449 SD_ID128_FORMAT_VAL(id),
450 SD_ID128_FORMAT_VAL(id));
451
452 for (i = 0; i < 16; i++)
453 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
454
455 fputs(")\n", stdout);
456
457 return 0;
458}
459
a963990f
LP
460static int add_matches(sd_journal *j, char **args) {
461 char **i;
462 int r;
59cea26a 463
a963990f 464 assert(j);
59cea26a 465
a963990f 466 STRV_FOREACH(i, args) {
59cea26a 467
cbdca852
LP
468 if (streq(*i, "+"))
469 r = sd_journal_add_disjunction(j);
470 else if (path_is_absolute(*i)) {
b6a34514 471 char *p, *t = NULL;
e5124088 472 const char *path;
a963990f 473 struct stat st;
e5124088 474
a963990f
LP
475 p = canonicalize_file_name(*i);
476 path = p ? p : *i;
e5124088
LP
477
478 if (stat(path, &st) < 0) {
479 free(p);
480 log_error("Couldn't stat file: %m");
a963990f 481 return -errno;
e5124088
LP
482 }
483
b6a34514 484 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
e5124088 485 t = strappend("_EXE=", path);
b6a34514
LP
486 else if (S_ISCHR(st.st_mode))
487 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
488 else if (S_ISBLK(st.st_mode))
489 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
490 else {
e5124088 491 free(p);
b6a34514 492 log_error("File is not a device node, regular file or is not executable: %s", *i);
a963990f 493 return -EINVAL;
50940700 494 }
e5124088
LP
495
496 free(p);
b6a34514
LP
497
498 if (!t)
499 return log_oom();
500
501 r = sd_journal_add_match(j, t, 0);
502 free(t);
e5124088 503 } else
cbdca852 504 r = sd_journal_add_match(j, *i, 0);
e5124088 505
de7b95cd 506 if (r < 0) {
cbdca852 507 log_error("Failed to add match '%s': %s", *i, strerror(-r));
a963990f 508 return r;
de7b95cd
LP
509 }
510 }
511
a963990f
LP
512 return 0;
513}
514
515static int add_this_boot(sd_journal *j) {
516 char match[9+32+1] = "_BOOT_ID=";
517 sd_id128_t boot_id;
518 int r;
519
941e990d
LP
520 assert(j);
521
a963990f
LP
522 if (!arg_this_boot)
523 return 0;
524
525 r = sd_id128_get_boot(&boot_id);
526 if (r < 0) {
527 log_error("Failed to get boot id: %s", strerror(-r));
528 return r;
529 }
530
531 sd_id128_to_string(boot_id, match + 9);
532 r = sd_journal_add_match(j, match, strlen(match));
533 if (r < 0) {
534 log_error("Failed to add match: %s", strerror(-r));
535 return r;
536 }
537
538 return 0;
539}
540
c3f60ec5
LP
541static int add_unit(sd_journal *j) {
542 _cleanup_free_ char *m = NULL, *u = NULL;
543 int r;
544
545 assert(j);
546
547 if (isempty(arg_unit))
548 return 0;
549
550 u = unit_name_mangle(arg_unit);
551 if (!u)
552 return log_oom();
553
554 m = strappend("_SYSTEMD_UNIT=", u);
555 if (!m)
556 return log_oom();
557
558 r = sd_journal_add_match(j, m, strlen(m));
559 if (r < 0) {
560 log_error("Failed to add match: %s", strerror(-r));
561 return r;
562 }
563
564 return 0;
565}
566
941e990d
LP
567static int add_priorities(sd_journal *j) {
568 char match[] = "PRIORITY=0";
569 int i, r;
570
571 assert(j);
572
573 if (arg_priorities == 0xFF)
574 return 0;
575
576 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
577 if (arg_priorities & (1 << i)) {
578 match[sizeof(match)-2] = '0' + i;
579
941e990d
LP
580 r = sd_journal_add_match(j, match, strlen(match));
581 if (r < 0) {
582 log_error("Failed to add match: %s", strerror(-r));
583 return r;
584 }
585 }
586
587 return 0;
588}
589
7560fffc
LP
590static int setup_keys(void) {
591#ifdef HAVE_GCRYPT
592 size_t mpk_size, seed_size, state_size, i;
593 uint8_t *mpk, *seed, *state;
594 ssize_t l;
f982e6f7 595 int fd = -1, r, attr = 0;
7560fffc
LP
596 sd_id128_t machine, boot;
597 char *p = NULL, *k = NULL;
baed47c3 598 struct FSSHeader h;
14d10188 599 uint64_t n;
7560fffc
LP
600
601 r = sd_id128_get_machine(&machine);
602 if (r < 0) {
603 log_error("Failed to get machine ID: %s", strerror(-r));
604 return r;
605 }
606
607 r = sd_id128_get_boot(&boot);
608 if (r < 0) {
609 log_error("Failed to get boot ID: %s", strerror(-r));
610 return r;
611 }
612
baed47c3 613 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
614 SD_ID128_FORMAT_VAL(machine)) < 0)
615 return log_oom();
616
617 if (access(p, F_OK) >= 0) {
f7fab8a5 618 log_error("Sealing key file %s exists already.", p);
7560fffc
LP
619 r = -EEXIST;
620 goto finish;
621 }
622
baed47c3 623 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
624 SD_ID128_FORMAT_VAL(machine)) < 0) {
625 r = log_oom();
626 goto finish;
627 }
628
629 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
630 mpk = alloca(mpk_size);
631
632 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
633 seed = alloca(seed_size);
634
635 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
636 state = alloca(state_size);
637
638 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
639 if (fd < 0) {
640 log_error("Failed to open /dev/random: %m");
641 r = -errno;
642 goto finish;
643 }
644
645 log_info("Generating seed...");
646 l = loop_read(fd, seed, seed_size, true);
647 if (l < 0 || (size_t) l != seed_size) {
648 log_error("Failed to read random seed: %s", strerror(EIO));
649 r = -EIO;
650 goto finish;
651 }
652
653 log_info("Generating key pair...");
654 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
655
baed47c3 656 log_info("Generating sealing key...");
7560fffc
LP
657 FSPRG_GenState0(state, mpk, seed, seed_size);
658
baed47c3
LP
659 assert(arg_interval > 0);
660
7560fffc 661 n = now(CLOCK_REALTIME);
baed47c3 662 n /= arg_interval;
7560fffc
LP
663
664 close_nointr_nofail(fd);
665 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
666 if (fd < 0) {
667 log_error("Failed to open %s: %m", k);
668 r = -errno;
669 goto finish;
670 }
671
f982e6f7
LP
672 /* Enable secure remove, exclusion from dump, synchronous
673 * writing and in-place updating */
674 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
675 log_warning("FS_IOC_GETFLAGS failed: %m");
676
677 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
678
679 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
680 log_warning("FS_IOC_SETFLAGS failed: %m");
681
7560fffc
LP
682 zero(h);
683 memcpy(h.signature, "KSHHRHLP", 8);
684 h.machine_id = machine;
685 h.boot_id = boot;
686 h.header_size = htole64(sizeof(h));
baed47c3
LP
687 h.start_usec = htole64(n * arg_interval);
688 h.interval_usec = htole64(arg_interval);
689 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
690 h.fsprg_state_size = htole64(state_size);
7560fffc
LP
691
692 l = loop_write(fd, &h, sizeof(h), false);
693 if (l < 0 || (size_t) l != sizeof(h)) {
694 log_error("Failed to write header: %s", strerror(EIO));
695 r = -EIO;
696 goto finish;
697 }
698
699 l = loop_write(fd, state, state_size, false);
700 if (l < 0 || (size_t) l != state_size) {
701 log_error("Failed to write state: %s", strerror(EIO));
702 r = -EIO;
703 goto finish;
704 }
705
706 if (link(k, p) < 0) {
707 log_error("Failed to link file: %m");
708 r = -errno;
709 goto finish;
710 }
711
8481248b 712 if (on_tty()) {
7560fffc
LP
713 fprintf(stderr,
714 "\n"
baed47c3 715 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
c05276f2
LP
716 "the following local file. This key file is automatically updated when the\n"
717 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
718 "\n"
719 "\t%s\n"
720 "\n"
baed47c3
LP
721 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
722 "at a safe location and should not be saved locally on disk.\n"
7560fffc
LP
723 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
724 fflush(stderr);
725 }
726 for (i = 0; i < seed_size; i++) {
727 if (i > 0 && i % 3 == 0)
728 putchar('-');
729 printf("%02x", ((uint8_t*) seed)[i]);
730 }
731
baed47c3
LP
732 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
733
8481248b 734 if (on_tty()) {
f6a971bc 735 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 736
baed47c3
LP
737 fprintf(stderr,
738 ANSI_HIGHLIGHT_OFF "\n"
739 "The sealing key is automatically changed every %s.\n",
740 format_timespan(tsb, sizeof(tsb), arg_interval));
f6a971bc
LP
741
742 hn = gethostname_malloc();
743
744 if (hn) {
745 hostname_cleanup(hn);
adac1c93 746 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 747 } else
adac1c93 748 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc
LP
749
750#ifdef HAVE_QRENCODE
cf5a3432 751 /* If this is not an UTF-8 system don't print any QR codes */
09017585 752 if (is_locale_utf8()) {
cf5a3432
LP
753 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
754 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
755 }
f6a971bc
LP
756#endif
757 free(hn);
baed47c3 758 }
7560fffc
LP
759
760 r = 0;
761
762finish:
763 if (fd >= 0)
764 close_nointr_nofail(fd);
765
766 if (k) {
767 unlink(k);
768 free(k);
769 }
770
771 free(p);
772
773 return r;
774#else
feb12d3e
LP
775 log_error("Forward-secure sealing not available.");
776 return -ENOTSUP;
7560fffc
LP
777#endif
778}
779
beec0085
LP
780static int verify(sd_journal *j) {
781 int r = 0;
782 Iterator i;
783 JournalFile *f;
784
785 assert(j);
786
cedb42bb
LP
787 log_show_color(true);
788
beec0085
LP
789 HASHMAP_FOREACH(f, j->files, i) {
790 int k;
2a7b539a 791 usec_t first, validated, last;
beec0085 792
56e81f7c 793#ifdef HAVE_GCRYPT
feb12d3e 794 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 795 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 796#endif
4da416aa 797
2a7b539a 798 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 799 if (k == -EINVAL) {
baed47c3 800 /* If the key was invalid give up right-away. */
56e81f7c
LP
801 return k;
802 } else if (k < 0) {
beec0085 803 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
56e81f7c 804 r = k;
6c7be122
LP
805 } else {
806 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 807 log_info("PASS: %s", f->path);
6c7be122 808
c0ca7aee 809 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 810 if (validated > 0) {
c0ca7aee 811 log_info("=> Validated from %s to %s, final %s entries not sealed.",
2a7b539a
LP
812 format_timestamp(a, sizeof(a), first),
813 format_timestamp(b, sizeof(b), validated),
814 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
815 } else if (last > 0)
c0ca7aee 816 log_info("=> No sealing yet, %s of entries not sealed.",
2a7b539a 817 format_timespan(c, sizeof(c), last - first));
c0ca7aee
LP
818 else
819 log_info("=> No sealing yet, no entries in file.");
820 }
6c7be122 821 }
beec0085
LP
822 }
823
824 return r;
825}
826
15804ceb
LP
827static int access_check(void) {
828
829#ifdef HAVE_ACL
830 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
831 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
832 return -EACCES;
833 }
834
835 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
836 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
837#else
838 if (geteuid() != 0 && in_group("adm") <= 0) {
839 log_error("No access to messages. Only users in the group 'adm' can see messages.");
840 return -EACCES;
841 }
842#endif
843
844 return 0;
845}
846
a963990f
LP
847int main(int argc, char *argv[]) {
848 int r;
849 sd_journal *j = NULL;
a963990f 850 bool need_seek = false;
14a65d65
LP
851 sd_id128_t previous_boot_id;
852 bool previous_boot_id_valid = false;
cfbc22ab 853 unsigned n_shown = 0;
a963990f 854
a9cdc94f 855 setlocale(LC_ALL, "");
a963990f
LP
856 log_parse_environment();
857 log_open();
858
859 r = parse_argv(argc, argv);
860 if (r <= 0)
861 goto finish;
862
ed757c0c
LP
863 signal(SIGWINCH, columns_lines_cache_reset);
864
7560fffc 865 if (arg_action == ACTION_NEW_ID128) {
a963990f
LP
866 r = generate_new_id128();
867 goto finish;
868 }
869
7560fffc
LP
870 if (arg_action == ACTION_SETUP_KEYS) {
871 r = setup_keys();
872 goto finish;
873 }
874
d4205751
LP
875 if (arg_action == ACTION_LIST_CATALOG) {
876 r = catalog_list(stdout);
83f6936a
LP
877 if (r < 0)
878 log_error("Failed to list catalog: %s", strerror(-r));
d4205751
LP
879 goto finish;
880 }
881
882 if (arg_action == ACTION_UPDATE_CATALOG) {
883 r = catalog_update();
884 goto finish;
885 }
886
15804ceb
LP
887 r = access_check();
888 if (r < 0)
889 goto finish;
890
a963990f
LP
891 if (arg_directory)
892 r = sd_journal_open_directory(&j, arg_directory, 0);
893 else
9e8a535f 894 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
a963990f
LP
895 if (r < 0) {
896 log_error("Failed to open journal: %s", strerror(-r));
897 goto finish;
898 }
899
beec0085
LP
900 if (arg_action == ACTION_VERIFY) {
901 r = verify(j);
902 goto finish;
903 }
904
7560fffc 905 if (arg_action == ACTION_PRINT_HEADER) {
dca6219e
LP
906 journal_print_header(j);
907 r = 0;
908 goto finish;
909 }
910
a1a03e30
LP
911 if (arg_action == ACTION_DISK_USAGE) {
912 uint64_t bytes;
913 char sbytes[FORMAT_BYTES_MAX];
914
915 r = sd_journal_get_usage(j, &bytes);
916 if (r < 0)
917 goto finish;
918
919 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
920 r = 0;
921 goto finish;
922 }
923
a963990f
LP
924 r = add_this_boot(j);
925 if (r < 0)
926 goto finish;
927
c3f60ec5
LP
928 r = add_unit(j);
929 if (r < 0)
930 goto finish;
931
a963990f
LP
932 r = add_matches(j, argv + optind);
933 if (r < 0)
934 goto finish;
935
941e990d
LP
936 r = add_priorities(j);
937 if (r < 0)
938 goto finish;
939
15119c16
LP
940 if (arg_field) {
941 const void *data;
942 size_t size;
943
944 r = sd_journal_query_unique(j, arg_field);
945 if (r < 0) {
946 log_error("Failed to query unique data objects: %s", strerror(-r));
947 goto finish;
948 }
949
950 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
951 const void *eq;
952
fd6e8875
LP
953 if (arg_lines > 0 && n_shown >= arg_lines)
954 break;
955
15119c16
LP
956 eq = memchr(data, '=', size);
957 if (eq)
958 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
959 else
960 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875
LP
961
962 n_shown ++;
15119c16
LP
963 }
964
965 r = 0;
966 goto finish;
967 }
968
cfbc22ab
LP
969 if (arg_cursor) {
970 r = sd_journal_seek_cursor(j, arg_cursor);
08984293 971 if (r < 0) {
cfbc22ab 972 log_error("Failed to seek to cursor: %s", strerror(-r));
08984293
LP
973 goto finish;
974 }
975
cfbc22ab 976 r = sd_journal_next(j);
08984293 977
cfbc22ab
LP
978 } else if (arg_since_set) {
979 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 980 if (r < 0) {
cfbc22ab 981 log_error("Failed to seek to date: %s", strerror(-r));
8f14c832
LP
982 goto finish;
983 }
8f14c832
LP
984 r = sd_journal_next(j);
985
cfbc22ab 986 } else if (arg_lines > 0) {
2100675e
LP
987 r = sd_journal_seek_tail(j);
988 if (r < 0) {
989 log_error("Failed to seek to tail: %s", strerror(-r));
990 goto finish;
991 }
992
993 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 994
2100675e
LP
995 } else {
996 r = sd_journal_seek_head(j);
997 if (r < 0) {
998 log_error("Failed to seek to head: %s", strerror(-r));
999 goto finish;
1000 }
6f003b43
LP
1001
1002 r = sd_journal_next(j);
1003 }
1004
1005 if (r < 0) {
1006 log_error("Failed to iterate through journal: %s", strerror(-r));
1007 goto finish;
50f20cfd 1008 }
87d2c1ff 1009
f89a3b6f
LP
1010 if (!arg_no_pager && !arg_follow)
1011 pager_open();
0d43c694 1012
cfbc22ab
LP
1013 if (!arg_quiet) {
1014 usec_t start, end;
1015 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1016
1017 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1018 if (r < 0) {
1019 log_error("Failed to get cutoff: %s", strerror(-r));
1020 goto finish;
1021 }
1022
1023 if (r > 0) {
1024 if (arg_follow)
9048b11f
LP
1025 printf("-- Logs begin at %s. --\n",
1026 format_timestamp(start_buf, sizeof(start_buf), start));
cfbc22ab 1027 else
9048b11f 1028 printf("-- Logs begin at %s, end at %s. --\n",
cfbc22ab
LP
1029 format_timestamp(start_buf, sizeof(start_buf), start),
1030 format_timestamp(end_buf, sizeof(end_buf), end));
1031 }
1032 }
1033
50f20cfd 1034 for (;;) {
c3eba2ab 1035 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
cfbc22ab
LP
1036 int flags;
1037
6f003b43
LP
1038 if (need_seek) {
1039 r = sd_journal_next(j);
1040 if (r < 0) {
1041 log_error("Failed to iterate through journal: %s", strerror(-r));
1042 goto finish;
1043 }
0d43c694
LP
1044 }
1045
1046 if (r == 0)
1047 break;
1048
cfbc22ab
LP
1049 if (arg_until_set) {
1050 usec_t usec;
1051
1052 r = sd_journal_get_realtime_usec(j, &usec);
1053 if (r < 0) {
1054 log_error("Failed to determine timestamp: %s", strerror(-r));
1055 goto finish;
1056 }
1057 }
1058
cd931c0a
LP
1059 if (!arg_merge) {
1060 sd_id128_t boot_id;
14a65d65 1061
cd931c0a
LP
1062 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1063 if (r >= 0) {
1064 if (previous_boot_id_valid &&
1065 !sd_id128_equal(boot_id, previous_boot_id))
9048b11f 1066 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
cd931c0a
LP
1067
1068 previous_boot_id = boot_id;
1069 previous_boot_id_valid = true;
1070 }
14a65d65
LP
1071 }
1072
cfbc22ab 1073 flags =
cd4b13e0 1074 arg_all * OUTPUT_SHOW_ALL |
e3657ecd 1075 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
d4205751
LP
1076 on_tty() * OUTPUT_COLOR |
1077 arg_catalog * OUTPUT_CATALOG;
cfbc22ab 1078
08ace05b 1079 r = output_journal(stdout, j, arg_output, 0, flags);
72f59706
LP
1080 if (r < 0)
1081 goto finish;
6f003b43
LP
1082
1083 need_seek = true;
cfbc22ab 1084 n_shown++;
87d2c1ff
LP
1085 }
1086
50f20cfd
LP
1087 if (!arg_follow)
1088 break;
1089
e02d1cf7 1090 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 1091 if (r < 0) {
7a69007a 1092 log_error("Couldn't wait for journal event: %s", strerror(-r));
50f20cfd
LP
1093 goto finish;
1094 }
de190aef 1095 }
87d2c1ff
LP
1096
1097finish:
3fbf9cbb
LP
1098 if (j)
1099 sd_journal_close(j);
87d2c1ff 1100
0d43c694
LP
1101 pager_close();
1102
3fbf9cbb 1103 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 1104}