]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
journalctl: imply -n1000 when -e is used
[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_pager_end = false;
60 static bool arg_follow = false;
61 static bool arg_full = false;
62 static bool arg_all = false;
63 static bool arg_no_pager = false;
64 static int arg_lines = -1;
65 static bool arg_no_tail = false;
66 static bool arg_quiet = false;
67 static bool arg_merge = false;
68 static bool arg_this_boot = false;
69 static const char *arg_cursor = NULL;
70 static const char *arg_directory = NULL;
71 static int arg_priorities = 0xFF;
72 static const char *arg_verify_key = NULL;
73 #ifdef HAVE_GCRYPT
74 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
75 #endif
76 static usec_t arg_since, arg_until;
77 static bool arg_since_set = false, arg_until_set = false;
78 static const char *arg_unit = NULL;
79 static const char *arg_unit_type = NULL;
80 static const char *arg_field = NULL;
81 static bool arg_catalog = false;
82 static bool arg_reverse = false;
83
84 static enum {
85 ACTION_SHOW,
86 ACTION_NEW_ID128,
87 ACTION_PRINT_HEADER,
88 ACTION_SETUP_KEYS,
89 ACTION_VERIFY,
90 ACTION_DISK_USAGE,
91 ACTION_LIST_CATALOG,
92 ACTION_UPDATE_CATALOG
93 } arg_action = ACTION_SHOW;
94
95 static int help(void) {
96
97 printf("%s [OPTIONS...] [MATCHES...]\n\n"
98 "Query the journal.\n\n"
99 "Flags:\n"
100 " --since=DATE Start showing entries newer or of the specified date\n"
101 " --until=DATE Stop showing entries older or of the specified date\n"
102 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
103 " -b --this-boot Show data only from current boot\n"
104 " -u --unit=UNIT Show data only from the specified unit\n"
105 " --user-unit=UNIT Show data only from the specified user session unit\n"
106 " -p --priority=RANGE Show only messages within the specified priority range\n"
107 " -e --pager-end Immediately jump to end of the journal in the pager\n"
108 " -f --follow Follow journal\n"
109 " -n --lines[=INTEGER] Number of journal entries to show\n"
110 " --no-tail Show all lines, even in follow mode\n"
111 " -r --reverse Show the newest entries first\n"
112 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
113 " verbose, export, json, json-pretty, json-sse, cat)\n"
114 " -x --catalog Add message explanations where available\n"
115 " --full Do not ellipsize fields\n"
116 " -a --all Show all fields, including long and unprintable\n"
117 " -q --quiet Don't show privilege warning\n"
118 " --no-pager Do not pipe output into a pager\n"
119 " -m --merge Show entries from all available journals\n"
120 " -D --directory=PATH Show journal files from directory\n"
121 #ifdef HAVE_GCRYPT
122 " --interval=TIME Time interval for changing the FSS sealing key\n"
123 " --verify-key=KEY Specify FSS verification key\n"
124 #endif
125 "\nCommands:\n"
126 " -h --help Show this help\n"
127 " --version Show package version\n"
128 " --new-id128 Generate a new 128 Bit ID\n"
129 " --header Show journal header information\n"
130 " --disk-usage Show total disk usage\n"
131 " -F --field=FIELD List all values a certain field takes\n"
132 " --list-catalog Show message IDs of all entries in the message catalog\n"
133 " --update-catalog Update the message catalog database\n"
134 #ifdef HAVE_GCRYPT
135 " --setup-keys Generate new FSS key pair\n"
136 " --verify Verify journal file consistency\n"
137 #endif
138 , program_invocation_short_name);
139
140 return 0;
141 }
142
143 static int parse_argv(int argc, char *argv[]) {
144
145 enum {
146 ARG_VERSION = 0x100,
147 ARG_NO_PAGER,
148 ARG_NO_TAIL,
149 ARG_NEW_ID128,
150 ARG_HEADER,
151 ARG_FULL,
152 ARG_SETUP_KEYS,
153 ARG_INTERVAL,
154 ARG_VERIFY,
155 ARG_VERIFY_KEY,
156 ARG_DISK_USAGE,
157 ARG_SINCE,
158 ARG_UNTIL,
159 ARG_USER_UNIT,
160 ARG_LIST_CATALOG,
161 ARG_UPDATE_CATALOG
162 };
163
164 static const struct option options[] = {
165 { "help", no_argument, NULL, 'h' },
166 { "version" , no_argument, NULL, ARG_VERSION },
167 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
168 { "pager-end", no_argument, NULL, 'e' },
169 { "follow", no_argument, NULL, 'f' },
170 { "output", required_argument, NULL, 'o' },
171 { "all", no_argument, NULL, 'a' },
172 { "full", no_argument, NULL, ARG_FULL },
173 { "lines", optional_argument, NULL, 'n' },
174 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
175 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
176 { "quiet", no_argument, NULL, 'q' },
177 { "merge", no_argument, NULL, 'm' },
178 { "this-boot", no_argument, NULL, 'b' },
179 { "directory", required_argument, NULL, 'D' },
180 { "header", no_argument, NULL, ARG_HEADER },
181 { "priority", required_argument, NULL, 'p' },
182 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
183 { "interval", required_argument, NULL, ARG_INTERVAL },
184 { "verify", no_argument, NULL, ARG_VERIFY },
185 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
186 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
187 { "cursor", required_argument, NULL, 'c' },
188 { "since", required_argument, NULL, ARG_SINCE },
189 { "until", required_argument, NULL, ARG_UNTIL },
190 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
191 { "unit", required_argument, NULL, 'u' },
192 { "field", required_argument, NULL, 'F' },
193 { "catalog", no_argument, NULL, 'x' },
194 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
195 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
196 { "reverse", no_argument, NULL, 'r' },
197 { NULL, 0, NULL, 0 }
198 };
199
200 int c, r;
201
202 assert(argc >= 0);
203 assert(argv);
204
205 while ((c = getopt_long(argc, argv, "hefo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) {
206
207 switch (c) {
208
209 case 'h':
210 help();
211 return 0;
212
213 case ARG_VERSION:
214 puts(PACKAGE_STRING);
215 puts(SYSTEMD_FEATURES);
216 return 0;
217
218 case ARG_NO_PAGER:
219 arg_no_pager = true;
220 break;
221
222 case 'e':
223 arg_pager_end = true;
224
225 if (arg_lines < 0)
226 arg_lines = 1000;
227
228 break;
229
230 case 'f':
231 arg_follow = true;
232 break;
233
234 case 'o':
235 arg_output = output_mode_from_string(optarg);
236 if (arg_output < 0) {
237 log_error("Unknown output format '%s'.", optarg);
238 return -EINVAL;
239 }
240
241 if (arg_output == OUTPUT_EXPORT ||
242 arg_output == OUTPUT_JSON ||
243 arg_output == OUTPUT_JSON_PRETTY ||
244 arg_output == OUTPUT_JSON_SSE ||
245 arg_output == OUTPUT_CAT)
246 arg_quiet = true;
247
248 break;
249
250 case ARG_FULL:
251 arg_full = true;
252 break;
253
254 case 'a':
255 arg_all = true;
256 break;
257
258 case 'n':
259 if (optarg) {
260 r = safe_atoi(optarg, &arg_lines);
261 if (r < 0 || arg_lines < 0) {
262 log_error("Failed to parse lines '%s'", optarg);
263 return -EINVAL;
264 }
265 } else {
266 int n;
267
268 /* Hmm, no argument? Maybe the next
269 * word on the command line is
270 * supposed to be the argument? Let's
271 * see if there is one, and is
272 * parsable as a positive
273 * integer... */
274
275 if (optind < argc &&
276 safe_atoi(argv[optind], &n) >= 0 &&
277 n >= 0) {
278
279 arg_lines = n;
280 optind++;
281 } else
282 arg_lines = 10;
283 }
284
285 break;
286
287 case ARG_NO_TAIL:
288 arg_no_tail = true;
289 break;
290
291 case ARG_NEW_ID128:
292 arg_action = ACTION_NEW_ID128;
293 break;
294
295 case 'q':
296 arg_quiet = true;
297 break;
298
299 case 'm':
300 arg_merge = true;
301 break;
302
303 case 'b':
304 arg_this_boot = true;
305 break;
306
307 case 'D':
308 arg_directory = optarg;
309 break;
310
311 case 'c':
312 arg_cursor = optarg;
313 break;
314
315 case ARG_HEADER:
316 arg_action = ACTION_PRINT_HEADER;
317 break;
318
319 case ARG_VERIFY:
320 arg_action = ACTION_VERIFY;
321 break;
322
323 case ARG_DISK_USAGE:
324 arg_action = ACTION_DISK_USAGE;
325 break;
326
327 #ifdef HAVE_GCRYPT
328 case ARG_SETUP_KEYS:
329 arg_action = ACTION_SETUP_KEYS;
330 break;
331
332
333 case ARG_VERIFY_KEY:
334 arg_action = ACTION_VERIFY;
335 arg_verify_key = optarg;
336 arg_merge = false;
337 break;
338
339 case ARG_INTERVAL:
340 r = parse_usec(optarg, &arg_interval);
341 if (r < 0 || arg_interval <= 0) {
342 log_error("Failed to parse sealing key change interval: %s", optarg);
343 return -EINVAL;
344 }
345 break;
346 #else
347 case ARG_SETUP_KEYS:
348 case ARG_VERIFY_KEY:
349 case ARG_INTERVAL:
350 log_error("Forward-secure sealing not available.");
351 return -ENOTSUP;
352 #endif
353
354 case 'p': {
355 const char *dots;
356
357 dots = strstr(optarg, "..");
358 if (dots) {
359 char *a;
360 int from, to, i;
361
362 /* a range */
363 a = strndup(optarg, dots - optarg);
364 if (!a)
365 return log_oom();
366
367 from = log_level_from_string(a);
368 to = log_level_from_string(dots + 2);
369 free(a);
370
371 if (from < 0 || to < 0) {
372 log_error("Failed to parse log level range %s", optarg);
373 return -EINVAL;
374 }
375
376 arg_priorities = 0;
377
378 if (from < to) {
379 for (i = from; i <= to; i++)
380 arg_priorities |= 1 << i;
381 } else {
382 for (i = to; i <= from; i++)
383 arg_priorities |= 1 << i;
384 }
385
386 } else {
387 int p, i;
388
389 p = log_level_from_string(optarg);
390 if (p < 0) {
391 log_error("Unknown log level %s", optarg);
392 return -EINVAL;
393 }
394
395 arg_priorities = 0;
396
397 for (i = 0; i <= p; i++)
398 arg_priorities |= 1 << i;
399 }
400
401 break;
402 }
403
404 case ARG_SINCE:
405 r = parse_timestamp(optarg, &arg_since);
406 if (r < 0) {
407 log_error("Failed to parse timestamp: %s", optarg);
408 return -EINVAL;
409 }
410 arg_since_set = true;
411 break;
412
413 case ARG_UNTIL:
414 r = parse_timestamp(optarg, &arg_until);
415 if (r < 0) {
416 log_error("Failed to parse timestamp: %s", optarg);
417 return -EINVAL;
418 }
419 arg_until_set = true;
420 break;
421
422 case ARG_USER_UNIT:
423 arg_unit = optarg;
424 arg_unit_type = "_SYSTEMD_USER_UNIT=";
425 break;
426
427 case 'u':
428 arg_unit = optarg;
429 arg_unit_type = "_SYSTEMD_UNIT=";
430 break;
431
432 case '?':
433 return -EINVAL;
434
435 case 'F':
436 arg_field = optarg;
437 break;
438
439 case 'x':
440 arg_catalog = true;
441 break;
442
443 case ARG_LIST_CATALOG:
444 arg_action = ACTION_LIST_CATALOG;
445 break;
446
447 case ARG_UPDATE_CATALOG:
448 arg_action = ACTION_UPDATE_CATALOG;
449 break;
450
451 case 'r':
452 arg_reverse = true;
453 break;
454
455 default:
456 log_error("Unknown option code %c", c);
457 return -EINVAL;
458 }
459 }
460
461 if (arg_follow && !arg_no_tail && arg_lines < 0)
462 arg_lines = 10;
463
464 if (arg_since_set && arg_until_set && arg_since > arg_until) {
465 log_error("--since= must be before --until=.");
466 return -EINVAL;
467 }
468
469 if (arg_cursor && arg_since_set) {
470 log_error("Please specify either --since= or --cursor=, not both.");
471 return -EINVAL;
472 }
473
474 if (arg_follow && arg_reverse) {
475 log_error("Please specify either --reverse= or --follow=, not both.");
476 return -EINVAL;
477 }
478
479 return 1;
480 }
481
482 static int generate_new_id128(void) {
483 sd_id128_t id;
484 int r;
485 unsigned i;
486
487 r = sd_id128_randomize(&id);
488 if (r < 0) {
489 log_error("Failed to generate ID: %s", strerror(-r));
490 return r;
491 }
492
493 printf("As string:\n"
494 SD_ID128_FORMAT_STR "\n\n"
495 "As UUID:\n"
496 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
497 "As macro:\n"
498 "#define MESSAGE_XYZ SD_ID128_MAKE(",
499 SD_ID128_FORMAT_VAL(id),
500 SD_ID128_FORMAT_VAL(id));
501 for (i = 0; i < 16; i++)
502 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
503 fputs(")\n\n", stdout);
504
505 printf("As Python constant:\n"
506 ">>> import uuid\n"
507 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
508 SD_ID128_FORMAT_VAL(id));
509
510 return 0;
511 }
512
513 static int add_matches(sd_journal *j, char **args) {
514 char **i;
515 int r;
516
517 assert(j);
518
519 STRV_FOREACH(i, args) {
520
521 if (streq(*i, "+"))
522 r = sd_journal_add_disjunction(j);
523 else if (path_is_absolute(*i)) {
524 char *p, *t = NULL;
525 const char *path;
526 struct stat st;
527
528 p = canonicalize_file_name(*i);
529 path = p ? p : *i;
530
531 if (stat(path, &st) < 0) {
532 free(p);
533 log_error("Couldn't stat file: %m");
534 return -errno;
535 }
536
537 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
538 t = strappend("_EXE=", path);
539 else if (S_ISCHR(st.st_mode))
540 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
541 else if (S_ISBLK(st.st_mode))
542 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
543 else {
544 free(p);
545 log_error("File is not a device node, regular file or is not executable: %s", *i);
546 return -EINVAL;
547 }
548
549 free(p);
550
551 if (!t)
552 return log_oom();
553
554 r = sd_journal_add_match(j, t, 0);
555 free(t);
556 } else
557 r = sd_journal_add_match(j, *i, 0);
558
559 if (r < 0) {
560 log_error("Failed to add match '%s': %s", *i, strerror(-r));
561 return r;
562 }
563 }
564
565 return 0;
566 }
567
568 static int add_this_boot(sd_journal *j) {
569 char match[9+32+1] = "_BOOT_ID=";
570 sd_id128_t boot_id;
571 int r;
572
573 assert(j);
574
575 if (!arg_this_boot)
576 return 0;
577
578 r = sd_id128_get_boot(&boot_id);
579 if (r < 0) {
580 log_error("Failed to get boot id: %s", strerror(-r));
581 return r;
582 }
583
584 sd_id128_to_string(boot_id, match + 9);
585 r = sd_journal_add_match(j, match, strlen(match));
586 if (r < 0) {
587 log_error("Failed to add match: %s", strerror(-r));
588 return r;
589 }
590
591 return 0;
592 }
593
594 static int add_unit(sd_journal *j) {
595 _cleanup_free_ char *m = NULL, *u = NULL;
596 int r;
597
598 assert(j);
599
600 if (isempty(arg_unit))
601 return 0;
602
603 u = unit_name_mangle(arg_unit);
604 if (!u)
605 return log_oom();
606
607 m = strappend(arg_unit_type, u);
608
609 if (!m)
610 return log_oom();
611
612 r = sd_journal_add_match(j, m, strlen(m));
613 if (r < 0) {
614 log_error("Failed to add match: %s", strerror(-r));
615 return r;
616 }
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 *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 r = catalog_list(stdout);
931 if (r < 0)
932 log_error("Failed to list catalog: %s", strerror(-r));
933 goto finish;
934 }
935
936 if (arg_action == ACTION_UPDATE_CATALOG) {
937 r = catalog_update();
938 goto finish;
939 }
940
941 r = access_check();
942 if (r < 0)
943 goto finish;
944
945 if (arg_directory)
946 r = sd_journal_open_directory(&j, arg_directory, 0);
947 else
948 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
949 if (r < 0) {
950 log_error("Failed to open journal: %s", strerror(-r));
951 goto finish;
952 }
953
954 if (arg_action == ACTION_VERIFY) {
955 r = verify(j);
956 goto finish;
957 }
958
959 if (arg_action == ACTION_PRINT_HEADER) {
960 journal_print_header(j);
961 r = 0;
962 goto finish;
963 }
964
965 if (arg_action == ACTION_DISK_USAGE) {
966 uint64_t bytes;
967 char sbytes[FORMAT_BYTES_MAX];
968
969 r = sd_journal_get_usage(j, &bytes);
970 if (r < 0)
971 goto finish;
972
973 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
974 r = 0;
975 goto finish;
976 }
977
978 r = add_this_boot(j);
979 if (r < 0)
980 goto finish;
981
982 r = add_unit(j);
983 if (r < 0)
984 goto finish;
985
986 r = add_matches(j, argv + optind);
987 if (r < 0)
988 goto finish;
989
990 r = add_priorities(j);
991 if (r < 0)
992 goto finish;
993
994 /* Opening the fd now means the first sd_journal_wait() will actually wait */
995 r = sd_journal_get_fd(j);
996 if (r < 0)
997 goto finish;
998
999 if (arg_field) {
1000 const void *data;
1001 size_t size;
1002
1003 r = sd_journal_query_unique(j, arg_field);
1004 if (r < 0) {
1005 log_error("Failed to query unique data objects: %s", strerror(-r));
1006 goto finish;
1007 }
1008
1009 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1010 const void *eq;
1011
1012 if (arg_lines >= 0 && n_shown >= arg_lines)
1013 break;
1014
1015 eq = memchr(data, '=', size);
1016 if (eq)
1017 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1018 else
1019 printf("%.*s\n", (int) size, (const char*) data);
1020
1021 n_shown ++;
1022 }
1023
1024 r = 0;
1025 goto finish;
1026 }
1027
1028 if (arg_cursor) {
1029 r = sd_journal_seek_cursor(j, arg_cursor);
1030 if (r < 0) {
1031 log_error("Failed to seek to cursor: %s", strerror(-r));
1032 goto finish;
1033 }
1034 if (!arg_reverse)
1035 r = sd_journal_next(j);
1036 else
1037 r = sd_journal_previous(j);
1038
1039 } else if (arg_since_set && !arg_reverse) {
1040 r = sd_journal_seek_realtime_usec(j, arg_since);
1041 if (r < 0) {
1042 log_error("Failed to seek to date: %s", strerror(-r));
1043 goto finish;
1044 }
1045 r = sd_journal_next(j);
1046
1047 } else if (arg_until_set && arg_reverse) {
1048 r = sd_journal_seek_realtime_usec(j, arg_until);
1049 if (r < 0) {
1050 log_error("Failed to seek to date: %s", strerror(-r));
1051 goto finish;
1052 }
1053 r = sd_journal_previous(j);
1054
1055 } else if (arg_lines >= 0) {
1056 r = sd_journal_seek_tail(j);
1057 if (r < 0) {
1058 log_error("Failed to seek to tail: %s", strerror(-r));
1059 goto finish;
1060 }
1061
1062 r = sd_journal_previous_skip(j, arg_lines);
1063
1064 } else if (arg_reverse) {
1065 r = sd_journal_seek_tail(j);
1066 if (r < 0) {
1067 log_error("Failed to seek to tail: %s", strerror(-r));
1068 goto finish;
1069 }
1070
1071 r = sd_journal_previous(j);
1072
1073 } else {
1074 r = sd_journal_seek_head(j);
1075 if (r < 0) {
1076 log_error("Failed to seek to head: %s", strerror(-r));
1077 goto finish;
1078 }
1079
1080 r = sd_journal_next(j);
1081 }
1082
1083 if (r < 0) {
1084 log_error("Failed to iterate through journal: %s", strerror(-r));
1085 goto finish;
1086 }
1087
1088 if (!arg_no_pager && !arg_follow)
1089 pager_open(arg_pager_end);
1090
1091 if (!arg_quiet) {
1092 usec_t start, end;
1093 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1094
1095 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1096 if (r < 0) {
1097 log_error("Failed to get cutoff: %s", strerror(-r));
1098 goto finish;
1099 }
1100
1101 if (r > 0) {
1102 if (arg_follow)
1103 printf("-- Logs begin at %s. --\n",
1104 format_timestamp(start_buf, sizeof(start_buf), start));
1105 else
1106 printf("-- Logs begin at %s, end at %s. --\n",
1107 format_timestamp(start_buf, sizeof(start_buf), start),
1108 format_timestamp(end_buf, sizeof(end_buf), end));
1109 }
1110 }
1111
1112 for (;;) {
1113 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1114 int flags;
1115
1116 if (need_seek) {
1117 if (!arg_reverse)
1118 r = sd_journal_next(j);
1119 else
1120 r = sd_journal_previous(j);
1121 if (r < 0) {
1122 log_error("Failed to iterate through journal: %s", strerror(-r));
1123 goto finish;
1124 }
1125 }
1126
1127 if (r == 0)
1128 break;
1129
1130 if (arg_until_set && !arg_reverse) {
1131 usec_t usec;
1132
1133 r = sd_journal_get_realtime_usec(j, &usec);
1134 if (r < 0) {
1135 log_error("Failed to determine timestamp: %s", strerror(-r));
1136 goto finish;
1137 }
1138 if (usec > arg_until)
1139 goto finish;
1140 }
1141
1142 if (arg_since_set && arg_reverse) {
1143 usec_t usec;
1144
1145 r = sd_journal_get_realtime_usec(j, &usec);
1146 if (r < 0) {
1147 log_error("Failed to determine timestamp: %s", strerror(-r));
1148 goto finish;
1149 }
1150 if (usec < arg_since)
1151 goto finish;
1152 }
1153
1154 if (!arg_merge) {
1155 sd_id128_t boot_id;
1156
1157 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1158 if (r >= 0) {
1159 if (previous_boot_id_valid &&
1160 !sd_id128_equal(boot_id, previous_boot_id))
1161 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1162
1163 previous_boot_id = boot_id;
1164 previous_boot_id_valid = true;
1165 }
1166 }
1167
1168 flags =
1169 arg_all * OUTPUT_SHOW_ALL |
1170 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1171 on_tty() * OUTPUT_COLOR |
1172 arg_catalog * OUTPUT_CATALOG;
1173
1174 r = output_journal(stdout, j, arg_output, 0, flags);
1175 if (r < 0 || ferror(stdout))
1176 goto finish;
1177
1178 need_seek = true;
1179 n_shown++;
1180 }
1181
1182 if (!arg_follow)
1183 break;
1184
1185 r = sd_journal_wait(j, (uint64_t) -1);
1186 if (r < 0) {
1187 log_error("Couldn't wait for journal event: %s", strerror(-r));
1188 goto finish;
1189 }
1190
1191 first_line = false;
1192 }
1193
1194 finish:
1195 if (j)
1196 sd_journal_close(j);
1197
1198 pager_close();
1199
1200 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1201 }