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