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