]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
Merge nss-myhostname
[thirdparty/systemd.git] / src / journal / journalctl.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <locale.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <stddef.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <sys/poll.h>
31 #include <time.h>
32 #include <getopt.h>
33 #include <signal.h>
34 #include <sys/stat.h>
35 #include <sys/ioctl.h>
36 #include <linux/fs.h>
37
38 #include <systemd/sd-journal.h>
39
40 #include "log.h"
41 #include "util.h"
42 #include "path-util.h"
43 #include "build.h"
44 #include "pager.h"
45 #include "logs-show.h"
46 #include "strv.h"
47 #include "journal-internal.h"
48 #include "journal-def.h"
49 #include "journal-verify.h"
50 #include "journal-authenticate.h"
51 #include "journal-qrcode.h"
52 #include "fsprg.h"
53 #include "unit-name.h"
54 #include "catalog.h"
55
56 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
57
58 static OutputMode arg_output = OUTPUT_SHORT;
59 static bool arg_follow = false;
60 static bool arg_full = false;
61 static bool arg_all = false;
62 static bool arg_no_pager = false;
63 static unsigned arg_lines = 0;
64 static bool arg_no_tail = false;
65 static bool arg_quiet = false;
66 static bool arg_merge = false;
67 static bool arg_this_boot = false;
68 static const char *arg_cursor = NULL;
69 static const char *arg_directory = NULL;
70 static int arg_priorities = 0xFF;
71 static const char *arg_verify_key = NULL;
72 #ifdef HAVE_GCRYPT
73 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
74 #endif
75 static usec_t arg_since, arg_until;
76 static bool arg_since_set = false, arg_until_set = false;
77 static const char *arg_unit = NULL;
78 static const char *arg_field = NULL;
79 static bool arg_catalog = false;
80
81 static enum {
82 ACTION_SHOW,
83 ACTION_NEW_ID128,
84 ACTION_PRINT_HEADER,
85 ACTION_SETUP_KEYS,
86 ACTION_VERIFY,
87 ACTION_DISK_USAGE,
88 ACTION_LIST_CATALOG,
89 ACTION_UPDATE_CATALOG
90 } arg_action = ACTION_SHOW;
91
92 static int help(void) {
93
94 printf("%s [OPTIONS...] [MATCHES...]\n\n"
95 "Query the journal.\n\n"
96 "Flags:\n"
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"
99 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
100 " -b --this-boot Show data only from current boot\n"
101 " -u --unit=UNIT Show data only from the specified unit\n"
102 " -p --priority=RANGE Show only messages within the specified priority range\n"
103 " -f --follow Follow journal\n"
104 " -n --lines[=INTEGER] Number of journal entries to show\n"
105 " --no-tail Show all lines, even in follow mode\n"
106 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
107 " verbose, export, json, json-pretty, json-sse, cat)\n"
108 " -x --catalog Add message explanations where available\n"
109 " --full Do not ellipsize fields\n"
110 " -a --all Show all fields, including long and unprintable\n"
111 " -q --quiet Don't show privilege warning\n"
112 " --no-pager Do not pipe output into a pager\n"
113 " -m --merge Show entries from all available journals\n"
114 " -D --directory=PATH Show journal files from directory\n"
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"
122 " --new-id128 Generate a new 128 Bit ID\n"
123 " --header Show journal header information\n"
124 " --disk-usage Show total disk usage\n"
125 " -F --field=FIELD List all values a certain field takes\n"
126 " --list-catalog Show message IDs of all entries in the message catalog\n"
127 " --update-catalog Update the message catalog database\n"
128 #ifdef HAVE_GCRYPT
129 " --setup-keys Generate new FSS key pair\n"
130 " --verify Verify journal file consistency\n"
131 #endif
132 , program_invocation_short_name);
133
134 return 0;
135 }
136
137 static int parse_argv(int argc, char *argv[]) {
138
139 enum {
140 ARG_VERSION = 0x100,
141 ARG_NO_PAGER,
142 ARG_NO_TAIL,
143 ARG_NEW_ID128,
144 ARG_HEADER,
145 ARG_FULL,
146 ARG_SETUP_KEYS,
147 ARG_INTERVAL,
148 ARG_VERIFY,
149 ARG_VERIFY_KEY,
150 ARG_DISK_USAGE,
151 ARG_SINCE,
152 ARG_UNTIL,
153 ARG_LIST_CATALOG,
154 ARG_UPDATE_CATALOG
155 };
156
157 static const struct option options[] = {
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' },
164 { "full", no_argument, NULL, ARG_FULL },
165 { "lines", optional_argument, NULL, 'n' },
166 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
167 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
168 { "quiet", no_argument, NULL, 'q' },
169 { "merge", no_argument, NULL, 'm' },
170 { "this-boot", no_argument, NULL, 'b' },
171 { "directory", required_argument, NULL, 'D' },
172 { "header", no_argument, NULL, ARG_HEADER },
173 { "priority", required_argument, NULL, 'p' },
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 },
178 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
179 { "cursor", required_argument, NULL, 'c' },
180 { "since", required_argument, NULL, ARG_SINCE },
181 { "until", required_argument, NULL, ARG_UNTIL },
182 { "unit", required_argument, NULL, 'u' },
183 { "field", required_argument, NULL, 'F' },
184 { "catalog", no_argument, NULL, 'x' },
185 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
186 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
187 { NULL, 0, NULL, 0 }
188 };
189
190 int c, r;
191
192 assert(argc >= 0);
193 assert(argv);
194
195 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:x", options, NULL)) >= 0) {
196
197 switch (c) {
198
199 case 'h':
200 help();
201 return 0;
202
203 case ARG_VERSION:
204 puts(PACKAGE_STRING);
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':
217 arg_output = output_mode_from_string(optarg);
218 if (arg_output < 0) {
219 log_error("Unknown output format '%s'.", optarg);
220 return -EINVAL;
221 }
222
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
230 break;
231
232 case ARG_FULL:
233 arg_full = true;
234 break;
235
236 case 'a':
237 arg_all = true;
238 break;
239
240 case 'n':
241 if (optarg) {
242 r = safe_atou(optarg, &arg_lines);
243 if (r < 0 || arg_lines <= 0) {
244 log_error("Failed to parse lines '%s'", optarg);
245 return -EINVAL;
246 }
247 } else
248 arg_lines = 10;
249
250 break;
251
252 case ARG_NO_TAIL:
253 arg_no_tail = true;
254 break;
255
256 case ARG_NEW_ID128:
257 arg_action = ACTION_NEW_ID128;
258 break;
259
260 case 'q':
261 arg_quiet = true;
262 break;
263
264 case 'm':
265 arg_merge = true;
266 break;
267
268 case 'b':
269 arg_this_boot = true;
270 break;
271
272 case 'D':
273 arg_directory = optarg;
274 break;
275
276 case 'c':
277 arg_cursor = optarg;
278 break;
279
280 case ARG_HEADER:
281 arg_action = ACTION_PRINT_HEADER;
282 break;
283
284 case ARG_VERIFY:
285 arg_action = ACTION_VERIFY;
286 break;
287
288 case ARG_DISK_USAGE:
289 arg_action = ACTION_DISK_USAGE;
290 break;
291
292 #ifdef HAVE_GCRYPT
293 case ARG_SETUP_KEYS:
294 arg_action = ACTION_SETUP_KEYS;
295 break;
296
297
298 case ARG_VERIFY_KEY:
299 arg_action = ACTION_VERIFY;
300 arg_verify_key = optarg;
301 arg_merge = false;
302 break;
303
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);
308 return -EINVAL;
309 }
310 break;
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
318
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
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
387 case 'u':
388 arg_unit = optarg;
389 break;
390
391 case '?':
392 return -EINVAL;
393
394 case 'F':
395 arg_field = optarg;
396 break;
397
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
410 default:
411 log_error("Unknown option code %c", c);
412 return -EINVAL;
413 }
414 }
415
416 if (arg_follow && !arg_no_tail && arg_lines <= 0)
417 arg_lines = 10;
418
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
429 return 1;
430 }
431
432 static int generate_new_id128(void) {
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
460 static int add_matches(sd_journal *j, char **args) {
461 char **i;
462 int r;
463
464 assert(j);
465
466 STRV_FOREACH(i, args) {
467
468 if (streq(*i, "+"))
469 r = sd_journal_add_disjunction(j);
470 else if (path_is_absolute(*i)) {
471 char *p, *t = NULL;
472 const char *path;
473 struct stat st;
474
475 p = canonicalize_file_name(*i);
476 path = p ? p : *i;
477
478 if (stat(path, &st) < 0) {
479 free(p);
480 log_error("Couldn't stat file: %m");
481 return -errno;
482 }
483
484 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
485 t = strappend("_EXE=", path);
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 {
491 free(p);
492 log_error("File is not a device node, regular file or is not executable: %s", *i);
493 return -EINVAL;
494 }
495
496 free(p);
497
498 if (!t)
499 return log_oom();
500
501 r = sd_journal_add_match(j, t, 0);
502 free(t);
503 } else
504 r = sd_journal_add_match(j, *i, 0);
505
506 if (r < 0) {
507 log_error("Failed to add match '%s': %s", *i, strerror(-r));
508 return r;
509 }
510 }
511
512 return 0;
513 }
514
515 static 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
520 assert(j);
521
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
541 static 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
567 static 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
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
590 static 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;
595 int fd = -1, r, attr = 0;
596 sd_id128_t machine, boot;
597 char *p = NULL, *k = NULL;
598 struct FSSHeader h;
599 uint64_t n;
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
613 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
614 SD_ID128_FORMAT_VAL(machine)) < 0)
615 return log_oom();
616
617 if (access(p, F_OK) >= 0) {
618 log_error("Sealing key file %s exists already.", p);
619 r = -EEXIST;
620 goto finish;
621 }
622
623 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
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
656 log_info("Generating sealing key...");
657 FSPRG_GenState0(state, mpk, seed, seed_size);
658
659 assert(arg_interval > 0);
660
661 n = now(CLOCK_REALTIME);
662 n /= arg_interval;
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
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
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));
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);
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
712 if (on_tty()) {
713 fprintf(stderr,
714 "\n"
715 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
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"
718 "\n"
719 "\t%s\n"
720 "\n"
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"
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
732 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
733
734 if (on_tty()) {
735 char tsb[FORMAT_TIMESPAN_MAX], *hn;
736
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));
741
742 hn = gethostname_malloc();
743
744 if (hn) {
745 hostname_cleanup(hn);
746 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
747 } else
748 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
749
750 #ifdef HAVE_QRENCODE
751 /* If this is not an UTF-8 system don't print any QR codes */
752 if (is_locale_utf8()) {
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 }
756 #endif
757 free(hn);
758 }
759
760 r = 0;
761
762 finish:
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
775 log_error("Forward-secure sealing not available.");
776 return -ENOTSUP;
777 #endif
778 }
779
780 static int verify(sd_journal *j) {
781 int r = 0;
782 Iterator i;
783 JournalFile *f;
784
785 assert(j);
786
787 log_show_color(true);
788
789 HASHMAP_FOREACH(f, j->files, i) {
790 int k;
791 usec_t first, validated, last;
792
793 #ifdef HAVE_GCRYPT
794 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
795 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
796 #endif
797
798 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
799 if (k == -EINVAL) {
800 /* If the key was invalid give up right-away. */
801 return k;
802 } else if (k < 0) {
803 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
804 r = k;
805 } else {
806 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
807 log_info("PASS: %s", f->path);
808
809 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
810 if (validated > 0) {
811 log_info("=> Validated from %s to %s, final %s entries not sealed.",
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)
816 log_info("=> No sealing yet, %s of entries not sealed.",
817 format_timespan(c, sizeof(c), last - first));
818 else
819 log_info("=> No sealing yet, no entries in file.");
820 }
821 }
822 }
823
824 return r;
825 }
826
827 static 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
847 int main(int argc, char *argv[]) {
848 int r;
849 sd_journal *j = NULL;
850 bool need_seek = false;
851 sd_id128_t previous_boot_id;
852 bool previous_boot_id_valid = false;
853 unsigned n_shown = 0;
854
855 setlocale(LC_ALL, "");
856 log_parse_environment();
857 log_open();
858
859 r = parse_argv(argc, argv);
860 if (r <= 0)
861 goto finish;
862
863 signal(SIGWINCH, columns_lines_cache_reset);
864
865 if (arg_action == ACTION_NEW_ID128) {
866 r = generate_new_id128();
867 goto finish;
868 }
869
870 if (arg_action == ACTION_SETUP_KEYS) {
871 r = setup_keys();
872 goto finish;
873 }
874
875 if (arg_action == ACTION_LIST_CATALOG) {
876 r = catalog_list(stdout);
877 if (r < 0)
878 log_error("Failed to list catalog: %s", strerror(-r));
879 goto finish;
880 }
881
882 if (arg_action == ACTION_UPDATE_CATALOG) {
883 r = catalog_update();
884 goto finish;
885 }
886
887 r = access_check();
888 if (r < 0)
889 goto finish;
890
891 if (arg_directory)
892 r = sd_journal_open_directory(&j, arg_directory, 0);
893 else
894 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
895 if (r < 0) {
896 log_error("Failed to open journal: %s", strerror(-r));
897 goto finish;
898 }
899
900 if (arg_action == ACTION_VERIFY) {
901 r = verify(j);
902 goto finish;
903 }
904
905 if (arg_action == ACTION_PRINT_HEADER) {
906 journal_print_header(j);
907 r = 0;
908 goto finish;
909 }
910
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
924 r = add_this_boot(j);
925 if (r < 0)
926 goto finish;
927
928 r = add_unit(j);
929 if (r < 0)
930 goto finish;
931
932 r = add_matches(j, argv + optind);
933 if (r < 0)
934 goto finish;
935
936 r = add_priorities(j);
937 if (r < 0)
938 goto finish;
939
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
953 if (arg_lines > 0 && n_shown >= arg_lines)
954 break;
955
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);
961
962 n_shown ++;
963 }
964
965 r = 0;
966 goto finish;
967 }
968
969 if (arg_cursor) {
970 r = sd_journal_seek_cursor(j, arg_cursor);
971 if (r < 0) {
972 log_error("Failed to seek to cursor: %s", strerror(-r));
973 goto finish;
974 }
975
976 r = sd_journal_next(j);
977
978 } else if (arg_since_set) {
979 r = sd_journal_seek_realtime_usec(j, arg_since);
980 if (r < 0) {
981 log_error("Failed to seek to date: %s", strerror(-r));
982 goto finish;
983 }
984 r = sd_journal_next(j);
985
986 } else if (arg_lines > 0) {
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);
994
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 }
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;
1008 }
1009
1010 if (!arg_no_pager && !arg_follow)
1011 pager_open();
1012
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)
1025 printf("-- Logs begin at %s. --\n",
1026 format_timestamp(start_buf, sizeof(start_buf), start));
1027 else
1028 printf("-- Logs begin at %s, end at %s. --\n",
1029 format_timestamp(start_buf, sizeof(start_buf), start),
1030 format_timestamp(end_buf, sizeof(end_buf), end));
1031 }
1032 }
1033
1034 for (;;) {
1035 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
1036 int flags;
1037
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 }
1044 }
1045
1046 if (r == 0)
1047 break;
1048
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
1059 if (!arg_merge) {
1060 sd_id128_t boot_id;
1061
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))
1066 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1067
1068 previous_boot_id = boot_id;
1069 previous_boot_id_valid = true;
1070 }
1071 }
1072
1073 flags =
1074 arg_all * OUTPUT_SHOW_ALL |
1075 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1076 on_tty() * OUTPUT_COLOR |
1077 arg_catalog * OUTPUT_CATALOG;
1078
1079 r = output_journal(stdout, j, arg_output, 0, flags);
1080 if (r < 0)
1081 goto finish;
1082
1083 need_seek = true;
1084 n_shown++;
1085 }
1086
1087 if (!arg_follow)
1088 break;
1089
1090 r = sd_journal_wait(j, (uint64_t) -1);
1091 if (r < 0) {
1092 log_error("Couldn't wait for journal event: %s", strerror(-r));
1093 goto finish;
1094 }
1095 }
1096
1097 finish:
1098 if (j)
1099 sd_journal_close(j);
1100
1101 pager_close();
1102
1103 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1104 }