]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
Merge branch 'python-systemd-reader'
[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 int arg_lines = -1;
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_atoi(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 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 }
266
267 break;
268
269 case ARG_NO_TAIL:
270 arg_no_tail = true;
271 break;
272
273 case ARG_NEW_ID128:
274 arg_action = ACTION_NEW_ID128;
275 break;
276
277 case 'q':
278 arg_quiet = true;
279 break;
280
281 case 'm':
282 arg_merge = true;
283 break;
284
285 case 'b':
286 arg_this_boot = true;
287 break;
288
289 case 'D':
290 arg_directory = optarg;
291 break;
292
293 case 'c':
294 arg_cursor = optarg;
295 break;
296
297 case ARG_HEADER:
298 arg_action = ACTION_PRINT_HEADER;
299 break;
300
301 case ARG_VERIFY:
302 arg_action = ACTION_VERIFY;
303 break;
304
305 case ARG_DISK_USAGE:
306 arg_action = ACTION_DISK_USAGE;
307 break;
308
309 #ifdef HAVE_GCRYPT
310 case ARG_SETUP_KEYS:
311 arg_action = ACTION_SETUP_KEYS;
312 break;
313
314
315 case ARG_VERIFY_KEY:
316 arg_action = ACTION_VERIFY;
317 arg_verify_key = optarg;
318 arg_merge = false;
319 break;
320
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);
325 return -EINVAL;
326 }
327 break;
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
335
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
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
404 case 'u':
405 arg_unit = optarg;
406 break;
407
408 case '?':
409 return -EINVAL;
410
411 case 'F':
412 arg_field = optarg;
413 break;
414
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
427 default:
428 log_error("Unknown option code %c", c);
429 return -EINVAL;
430 }
431 }
432
433 if (arg_follow && !arg_no_tail && arg_lines < 0)
434 arg_lines = 10;
435
436 if (arg_since_set && arg_until_set && arg_since > arg_until) {
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
446 return 1;
447 }
448
449 static int generate_new_id128(void) {
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"
465 "#define MESSAGE_XYZ SD_ID128_MAKE(",
466 SD_ID128_FORMAT_VAL(id),
467 SD_ID128_FORMAT_VAL(id));
468 for (i = 0; i < 16; i++)
469 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
470 fputs(")\n\n", stdout);
471
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));
476
477 return 0;
478 }
479
480 static int add_matches(sd_journal *j, char **args) {
481 char **i;
482 int r;
483
484 assert(j);
485
486 STRV_FOREACH(i, args) {
487
488 if (streq(*i, "+"))
489 r = sd_journal_add_disjunction(j);
490 else if (path_is_absolute(*i)) {
491 char *p, *t = NULL;
492 const char *path;
493 struct stat st;
494
495 p = canonicalize_file_name(*i);
496 path = p ? p : *i;
497
498 if (stat(path, &st) < 0) {
499 free(p);
500 log_error("Couldn't stat file: %m");
501 return -errno;
502 }
503
504 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
505 t = strappend("_EXE=", path);
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 {
511 free(p);
512 log_error("File is not a device node, regular file or is not executable: %s", *i);
513 return -EINVAL;
514 }
515
516 free(p);
517
518 if (!t)
519 return log_oom();
520
521 r = sd_journal_add_match(j, t, 0);
522 free(t);
523 } else
524 r = sd_journal_add_match(j, *i, 0);
525
526 if (r < 0) {
527 log_error("Failed to add match '%s': %s", *i, strerror(-r));
528 return r;
529 }
530 }
531
532 return 0;
533 }
534
535 static 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
540 assert(j);
541
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
561 static 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
587 static 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
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
610 static 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;
615 int fd = -1, r, attr = 0;
616 sd_id128_t machine, boot;
617 char *p = NULL, *k = NULL;
618 struct FSSHeader h;
619 uint64_t n;
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
633 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
634 SD_ID128_FORMAT_VAL(machine)) < 0)
635 return log_oom();
636
637 if (access(p, F_OK) >= 0) {
638 log_error("Sealing key file %s exists already.", p);
639 r = -EEXIST;
640 goto finish;
641 }
642
643 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
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
676 log_info("Generating sealing key...");
677 FSPRG_GenState0(state, mpk, seed, seed_size);
678
679 assert(arg_interval > 0);
680
681 n = now(CLOCK_REALTIME);
682 n /= arg_interval;
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
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
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));
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);
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
732 if (on_tty()) {
733 fprintf(stderr,
734 "\n"
735 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
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"
738 "\n"
739 "\t%s\n"
740 "\n"
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"
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
752 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
753
754 if (on_tty()) {
755 char tsb[FORMAT_TIMESPAN_MAX], *hn;
756
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));
761
762 hn = gethostname_malloc();
763
764 if (hn) {
765 hostname_cleanup(hn);
766 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
767 } else
768 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
769
770 #ifdef HAVE_QRENCODE
771 /* If this is not an UTF-8 system don't print any QR codes */
772 if (is_locale_utf8()) {
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 }
776 #endif
777 free(hn);
778 }
779
780 r = 0;
781
782 finish:
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
795 log_error("Forward-secure sealing not available.");
796 return -ENOTSUP;
797 #endif
798 }
799
800 static int verify(sd_journal *j) {
801 int r = 0;
802 Iterator i;
803 JournalFile *f;
804
805 assert(j);
806
807 log_show_color(true);
808
809 HASHMAP_FOREACH(f, j->files, i) {
810 int k;
811 usec_t first, validated, last;
812
813 #ifdef HAVE_GCRYPT
814 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
815 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
816 #endif
817
818 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
819 if (k == -EINVAL) {
820 /* If the key was invalid give up right-away. */
821 return k;
822 } else if (k < 0) {
823 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
824 r = k;
825 } else {
826 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
827 log_info("PASS: %s", f->path);
828
829 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
830 if (validated > 0) {
831 log_info("=> Validated from %s to %s, final %s entries not sealed.",
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)
836 log_info("=> No sealing yet, %s of entries not sealed.",
837 format_timespan(c, sizeof(c), last - first));
838 else
839 log_info("=> No sealing yet, no entries in file.");
840 }
841 }
842 }
843
844 return r;
845 }
846
847 static 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
867 int main(int argc, char *argv[]) {
868 int r;
869 sd_journal *j = NULL;
870 bool need_seek = false;
871 sd_id128_t previous_boot_id;
872 bool previous_boot_id_valid = false, first_line = true;
873 int n_shown = 0;
874
875 setlocale(LC_ALL, "");
876 log_parse_environment();
877 log_open();
878
879 r = parse_argv(argc, argv);
880 if (r <= 0)
881 goto finish;
882
883 signal(SIGWINCH, columns_lines_cache_reset);
884
885 if (arg_action == ACTION_NEW_ID128) {
886 r = generate_new_id128();
887 goto finish;
888 }
889
890 if (arg_action == ACTION_SETUP_KEYS) {
891 r = setup_keys();
892 goto finish;
893 }
894
895 if (arg_action == ACTION_LIST_CATALOG) {
896 r = catalog_list(stdout);
897 if (r < 0)
898 log_error("Failed to list catalog: %s", strerror(-r));
899 goto finish;
900 }
901
902 if (arg_action == ACTION_UPDATE_CATALOG) {
903 r = catalog_update();
904 goto finish;
905 }
906
907 r = access_check();
908 if (r < 0)
909 goto finish;
910
911 if (arg_directory)
912 r = sd_journal_open_directory(&j, arg_directory, 0);
913 else
914 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
915 if (r < 0) {
916 log_error("Failed to open journal: %s", strerror(-r));
917 goto finish;
918 }
919
920 if (arg_action == ACTION_VERIFY) {
921 r = verify(j);
922 goto finish;
923 }
924
925 if (arg_action == ACTION_PRINT_HEADER) {
926 journal_print_header(j);
927 r = 0;
928 goto finish;
929 }
930
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
944 r = add_this_boot(j);
945 if (r < 0)
946 goto finish;
947
948 r = add_unit(j);
949 if (r < 0)
950 goto finish;
951
952 r = add_matches(j, argv + optind);
953 if (r < 0)
954 goto finish;
955
956 r = add_priorities(j);
957 if (r < 0)
958 goto finish;
959
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
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
978 if (arg_lines >= 0 && n_shown >= arg_lines)
979 break;
980
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);
986
987 n_shown ++;
988 }
989
990 r = 0;
991 goto finish;
992 }
993
994 if (arg_cursor) {
995 r = sd_journal_seek_cursor(j, arg_cursor);
996 if (r < 0) {
997 log_error("Failed to seek to cursor: %s", strerror(-r));
998 goto finish;
999 }
1000
1001 r = sd_journal_next(j);
1002
1003 } else if (arg_since_set) {
1004 r = sd_journal_seek_realtime_usec(j, arg_since);
1005 if (r < 0) {
1006 log_error("Failed to seek to date: %s", strerror(-r));
1007 goto finish;
1008 }
1009 r = sd_journal_next(j);
1010
1011 } else if (arg_lines >= 0) {
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);
1019
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 }
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;
1033 }
1034
1035 if (!arg_no_pager && !arg_follow)
1036 pager_open();
1037
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)
1050 printf("-- Logs begin at %s. --\n",
1051 format_timestamp(start_buf, sizeof(start_buf), start));
1052 else
1053 printf("-- Logs begin at %s, end at %s. --\n",
1054 format_timestamp(start_buf, sizeof(start_buf), start),
1055 format_timestamp(end_buf, sizeof(end_buf), end));
1056 }
1057 }
1058
1059 for (;;) {
1060 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1061 int flags;
1062
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 }
1069 }
1070
1071 if (r == 0)
1072 break;
1073
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 }
1082 if (usec > arg_until)
1083 goto finish;
1084 }
1085
1086 if (!arg_merge) {
1087 sd_id128_t boot_id;
1088
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))
1093 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1094
1095 previous_boot_id = boot_id;
1096 previous_boot_id_valid = true;
1097 }
1098 }
1099
1100 flags =
1101 arg_all * OUTPUT_SHOW_ALL |
1102 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1103 on_tty() * OUTPUT_COLOR |
1104 arg_catalog * OUTPUT_CATALOG;
1105
1106 r = output_journal(stdout, j, arg_output, 0, flags);
1107 if (r < 0 || ferror(stdout))
1108 goto finish;
1109
1110 need_seek = true;
1111 n_shown++;
1112 }
1113
1114 if (!arg_follow)
1115 break;
1116
1117 r = sd_journal_wait(j, (uint64_t) -1);
1118 if (r < 0) {
1119 log_error("Couldn't wait for journal event: %s", strerror(-r));
1120 goto finish;
1121 }
1122
1123 first_line = false;
1124 }
1125
1126 finish:
1127 if (j)
1128 sd_journal_close(j);
1129
1130 pager_close();
1131
1132 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1133 }