]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
0b3a79bee97e3140f2af54e9f4d77c449bc75c9d
[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
469 for (i = 0; i < 16; i++)
470 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
471
472 fputs(")\n", stdout);
473
474 return 0;
475 }
476
477 static int add_matches(sd_journal *j, char **args) {
478 char **i;
479 int r;
480
481 assert(j);
482
483 STRV_FOREACH(i, args) {
484
485 if (streq(*i, "+"))
486 r = sd_journal_add_disjunction(j);
487 else if (path_is_absolute(*i)) {
488 char *p, *t = NULL;
489 const char *path;
490 struct stat st;
491
492 p = canonicalize_file_name(*i);
493 path = p ? p : *i;
494
495 if (stat(path, &st) < 0) {
496 free(p);
497 log_error("Couldn't stat file: %m");
498 return -errno;
499 }
500
501 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
502 t = strappend("_EXE=", path);
503 else if (S_ISCHR(st.st_mode))
504 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
505 else if (S_ISBLK(st.st_mode))
506 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
507 else {
508 free(p);
509 log_error("File is not a device node, regular file or is not executable: %s", *i);
510 return -EINVAL;
511 }
512
513 free(p);
514
515 if (!t)
516 return log_oom();
517
518 r = sd_journal_add_match(j, t, 0);
519 free(t);
520 } else
521 r = sd_journal_add_match(j, *i, 0);
522
523 if (r < 0) {
524 log_error("Failed to add match '%s': %s", *i, strerror(-r));
525 return r;
526 }
527 }
528
529 return 0;
530 }
531
532 static int add_this_boot(sd_journal *j) {
533 char match[9+32+1] = "_BOOT_ID=";
534 sd_id128_t boot_id;
535 int r;
536
537 assert(j);
538
539 if (!arg_this_boot)
540 return 0;
541
542 r = sd_id128_get_boot(&boot_id);
543 if (r < 0) {
544 log_error("Failed to get boot id: %s", strerror(-r));
545 return r;
546 }
547
548 sd_id128_to_string(boot_id, match + 9);
549 r = sd_journal_add_match(j, match, strlen(match));
550 if (r < 0) {
551 log_error("Failed to add match: %s", strerror(-r));
552 return r;
553 }
554
555 return 0;
556 }
557
558 static int add_unit(sd_journal *j) {
559 _cleanup_free_ char *m = NULL, *u = NULL;
560 int r;
561
562 assert(j);
563
564 if (isempty(arg_unit))
565 return 0;
566
567 u = unit_name_mangle(arg_unit);
568 if (!u)
569 return log_oom();
570
571 m = strappend("_SYSTEMD_UNIT=", u);
572 if (!m)
573 return log_oom();
574
575 r = sd_journal_add_match(j, m, strlen(m));
576 if (r < 0) {
577 log_error("Failed to add match: %s", strerror(-r));
578 return r;
579 }
580
581 return 0;
582 }
583
584 static int add_priorities(sd_journal *j) {
585 char match[] = "PRIORITY=0";
586 int i, r;
587
588 assert(j);
589
590 if (arg_priorities == 0xFF)
591 return 0;
592
593 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
594 if (arg_priorities & (1 << i)) {
595 match[sizeof(match)-2] = '0' + i;
596
597 r = sd_journal_add_match(j, match, strlen(match));
598 if (r < 0) {
599 log_error("Failed to add match: %s", strerror(-r));
600 return r;
601 }
602 }
603
604 return 0;
605 }
606
607 static int setup_keys(void) {
608 #ifdef HAVE_GCRYPT
609 size_t mpk_size, seed_size, state_size, i;
610 uint8_t *mpk, *seed, *state;
611 ssize_t l;
612 int fd = -1, r, attr = 0;
613 sd_id128_t machine, boot;
614 char *p = NULL, *k = NULL;
615 struct FSSHeader h;
616 uint64_t n;
617
618 r = sd_id128_get_machine(&machine);
619 if (r < 0) {
620 log_error("Failed to get machine ID: %s", strerror(-r));
621 return r;
622 }
623
624 r = sd_id128_get_boot(&boot);
625 if (r < 0) {
626 log_error("Failed to get boot ID: %s", strerror(-r));
627 return r;
628 }
629
630 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
631 SD_ID128_FORMAT_VAL(machine)) < 0)
632 return log_oom();
633
634 if (access(p, F_OK) >= 0) {
635 log_error("Sealing key file %s exists already.", p);
636 r = -EEXIST;
637 goto finish;
638 }
639
640 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
641 SD_ID128_FORMAT_VAL(machine)) < 0) {
642 r = log_oom();
643 goto finish;
644 }
645
646 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
647 mpk = alloca(mpk_size);
648
649 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
650 seed = alloca(seed_size);
651
652 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
653 state = alloca(state_size);
654
655 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
656 if (fd < 0) {
657 log_error("Failed to open /dev/random: %m");
658 r = -errno;
659 goto finish;
660 }
661
662 log_info("Generating seed...");
663 l = loop_read(fd, seed, seed_size, true);
664 if (l < 0 || (size_t) l != seed_size) {
665 log_error("Failed to read random seed: %s", strerror(EIO));
666 r = -EIO;
667 goto finish;
668 }
669
670 log_info("Generating key pair...");
671 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
672
673 log_info("Generating sealing key...");
674 FSPRG_GenState0(state, mpk, seed, seed_size);
675
676 assert(arg_interval > 0);
677
678 n = now(CLOCK_REALTIME);
679 n /= arg_interval;
680
681 close_nointr_nofail(fd);
682 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
683 if (fd < 0) {
684 log_error("Failed to open %s: %m", k);
685 r = -errno;
686 goto finish;
687 }
688
689 /* Enable secure remove, exclusion from dump, synchronous
690 * writing and in-place updating */
691 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
692 log_warning("FS_IOC_GETFLAGS failed: %m");
693
694 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
695
696 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
697 log_warning("FS_IOC_SETFLAGS failed: %m");
698
699 zero(h);
700 memcpy(h.signature, "KSHHRHLP", 8);
701 h.machine_id = machine;
702 h.boot_id = boot;
703 h.header_size = htole64(sizeof(h));
704 h.start_usec = htole64(n * arg_interval);
705 h.interval_usec = htole64(arg_interval);
706 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
707 h.fsprg_state_size = htole64(state_size);
708
709 l = loop_write(fd, &h, sizeof(h), false);
710 if (l < 0 || (size_t) l != sizeof(h)) {
711 log_error("Failed to write header: %s", strerror(EIO));
712 r = -EIO;
713 goto finish;
714 }
715
716 l = loop_write(fd, state, state_size, false);
717 if (l < 0 || (size_t) l != state_size) {
718 log_error("Failed to write state: %s", strerror(EIO));
719 r = -EIO;
720 goto finish;
721 }
722
723 if (link(k, p) < 0) {
724 log_error("Failed to link file: %m");
725 r = -errno;
726 goto finish;
727 }
728
729 if (on_tty()) {
730 fprintf(stderr,
731 "\n"
732 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
733 "the following local file. This key file is automatically updated when the\n"
734 "sealing key is advanced. It should not be used on multiple hosts.\n"
735 "\n"
736 "\t%s\n"
737 "\n"
738 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
739 "at a safe location and should not be saved locally on disk.\n"
740 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
741 fflush(stderr);
742 }
743 for (i = 0; i < seed_size; i++) {
744 if (i > 0 && i % 3 == 0)
745 putchar('-');
746 printf("%02x", ((uint8_t*) seed)[i]);
747 }
748
749 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
750
751 if (on_tty()) {
752 char tsb[FORMAT_TIMESPAN_MAX], *hn;
753
754 fprintf(stderr,
755 ANSI_HIGHLIGHT_OFF "\n"
756 "The sealing key is automatically changed every %s.\n",
757 format_timespan(tsb, sizeof(tsb), arg_interval));
758
759 hn = gethostname_malloc();
760
761 if (hn) {
762 hostname_cleanup(hn);
763 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
764 } else
765 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
766
767 #ifdef HAVE_QRENCODE
768 /* If this is not an UTF-8 system don't print any QR codes */
769 if (is_locale_utf8()) {
770 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
771 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
772 }
773 #endif
774 free(hn);
775 }
776
777 r = 0;
778
779 finish:
780 if (fd >= 0)
781 close_nointr_nofail(fd);
782
783 if (k) {
784 unlink(k);
785 free(k);
786 }
787
788 free(p);
789
790 return r;
791 #else
792 log_error("Forward-secure sealing not available.");
793 return -ENOTSUP;
794 #endif
795 }
796
797 static int verify(sd_journal *j) {
798 int r = 0;
799 Iterator i;
800 JournalFile *f;
801
802 assert(j);
803
804 log_show_color(true);
805
806 HASHMAP_FOREACH(f, j->files, i) {
807 int k;
808 usec_t first, validated, last;
809
810 #ifdef HAVE_GCRYPT
811 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
812 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
813 #endif
814
815 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
816 if (k == -EINVAL) {
817 /* If the key was invalid give up right-away. */
818 return k;
819 } else if (k < 0) {
820 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
821 r = k;
822 } else {
823 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
824 log_info("PASS: %s", f->path);
825
826 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
827 if (validated > 0) {
828 log_info("=> Validated from %s to %s, final %s entries not sealed.",
829 format_timestamp(a, sizeof(a), first),
830 format_timestamp(b, sizeof(b), validated),
831 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
832 } else if (last > 0)
833 log_info("=> No sealing yet, %s of entries not sealed.",
834 format_timespan(c, sizeof(c), last - first));
835 else
836 log_info("=> No sealing yet, no entries in file.");
837 }
838 }
839 }
840
841 return r;
842 }
843
844 static int access_check(void) {
845
846 #ifdef HAVE_ACL
847 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
848 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
849 return -EACCES;
850 }
851
852 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
853 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
854 #else
855 if (geteuid() != 0 && in_group("adm") <= 0) {
856 log_error("No access to messages. Only users in the group 'adm' can see messages.");
857 return -EACCES;
858 }
859 #endif
860
861 return 0;
862 }
863
864 int main(int argc, char *argv[]) {
865 int r;
866 sd_journal *j = NULL;
867 bool need_seek = false;
868 sd_id128_t previous_boot_id;
869 bool previous_boot_id_valid = false, first_line = true;
870 int n_shown = 0;
871
872 setlocale(LC_ALL, "");
873 log_parse_environment();
874 log_open();
875
876 r = parse_argv(argc, argv);
877 if (r <= 0)
878 goto finish;
879
880 signal(SIGWINCH, columns_lines_cache_reset);
881
882 if (arg_action == ACTION_NEW_ID128) {
883 r = generate_new_id128();
884 goto finish;
885 }
886
887 if (arg_action == ACTION_SETUP_KEYS) {
888 r = setup_keys();
889 goto finish;
890 }
891
892 if (arg_action == ACTION_LIST_CATALOG) {
893 r = catalog_list(stdout);
894 if (r < 0)
895 log_error("Failed to list catalog: %s", strerror(-r));
896 goto finish;
897 }
898
899 if (arg_action == ACTION_UPDATE_CATALOG) {
900 r = catalog_update();
901 goto finish;
902 }
903
904 r = access_check();
905 if (r < 0)
906 goto finish;
907
908 if (arg_directory)
909 r = sd_journal_open_directory(&j, arg_directory, 0);
910 else
911 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
912 if (r < 0) {
913 log_error("Failed to open journal: %s", strerror(-r));
914 goto finish;
915 }
916
917 if (arg_action == ACTION_VERIFY) {
918 r = verify(j);
919 goto finish;
920 }
921
922 if (arg_action == ACTION_PRINT_HEADER) {
923 journal_print_header(j);
924 r = 0;
925 goto finish;
926 }
927
928 if (arg_action == ACTION_DISK_USAGE) {
929 uint64_t bytes;
930 char sbytes[FORMAT_BYTES_MAX];
931
932 r = sd_journal_get_usage(j, &bytes);
933 if (r < 0)
934 goto finish;
935
936 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
937 r = 0;
938 goto finish;
939 }
940
941 r = add_this_boot(j);
942 if (r < 0)
943 goto finish;
944
945 r = add_unit(j);
946 if (r < 0)
947 goto finish;
948
949 r = add_matches(j, argv + optind);
950 if (r < 0)
951 goto finish;
952
953 r = add_priorities(j);
954 if (r < 0)
955 goto finish;
956
957 /* Opening the fd now means the first sd_journal_wait() will actually wait */
958 r = sd_journal_get_fd(j);
959 if (r < 0)
960 goto finish;
961
962 if (arg_field) {
963 const void *data;
964 size_t size;
965
966 r = sd_journal_query_unique(j, arg_field);
967 if (r < 0) {
968 log_error("Failed to query unique data objects: %s", strerror(-r));
969 goto finish;
970 }
971
972 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
973 const void *eq;
974
975 if (arg_lines >= 0 && n_shown >= arg_lines)
976 break;
977
978 eq = memchr(data, '=', size);
979 if (eq)
980 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
981 else
982 printf("%.*s\n", (int) size, (const char*) data);
983
984 n_shown ++;
985 }
986
987 r = 0;
988 goto finish;
989 }
990
991 if (arg_cursor) {
992 r = sd_journal_seek_cursor(j, arg_cursor);
993 if (r < 0) {
994 log_error("Failed to seek to cursor: %s", strerror(-r));
995 goto finish;
996 }
997
998 r = sd_journal_next(j);
999
1000 } else if (arg_since_set) {
1001 r = sd_journal_seek_realtime_usec(j, arg_since);
1002 if (r < 0) {
1003 log_error("Failed to seek to date: %s", strerror(-r));
1004 goto finish;
1005 }
1006 r = sd_journal_next(j);
1007
1008 } else if (arg_lines >= 0) {
1009 r = sd_journal_seek_tail(j);
1010 if (r < 0) {
1011 log_error("Failed to seek to tail: %s", strerror(-r));
1012 goto finish;
1013 }
1014
1015 r = sd_journal_previous_skip(j, arg_lines);
1016
1017 } else {
1018 r = sd_journal_seek_head(j);
1019 if (r < 0) {
1020 log_error("Failed to seek to head: %s", strerror(-r));
1021 goto finish;
1022 }
1023
1024 r = sd_journal_next(j);
1025 }
1026
1027 if (r < 0) {
1028 log_error("Failed to iterate through journal: %s", strerror(-r));
1029 goto finish;
1030 }
1031
1032 if (!arg_no_pager && !arg_follow)
1033 pager_open();
1034
1035 if (!arg_quiet) {
1036 usec_t start, end;
1037 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1038
1039 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1040 if (r < 0) {
1041 log_error("Failed to get cutoff: %s", strerror(-r));
1042 goto finish;
1043 }
1044
1045 if (r > 0) {
1046 if (arg_follow)
1047 printf("-- Logs begin at %s. --\n",
1048 format_timestamp(start_buf, sizeof(start_buf), start));
1049 else
1050 printf("-- Logs begin at %s, end at %s. --\n",
1051 format_timestamp(start_buf, sizeof(start_buf), start),
1052 format_timestamp(end_buf, sizeof(end_buf), end));
1053 }
1054 }
1055
1056 for (;;) {
1057 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1058 int flags;
1059
1060 if (need_seek) {
1061 r = sd_journal_next(j);
1062 if (r < 0) {
1063 log_error("Failed to iterate through journal: %s", strerror(-r));
1064 goto finish;
1065 }
1066 }
1067
1068 if (r == 0)
1069 break;
1070
1071 if (arg_until_set) {
1072 usec_t usec;
1073
1074 r = sd_journal_get_realtime_usec(j, &usec);
1075 if (r < 0) {
1076 log_error("Failed to determine timestamp: %s", strerror(-r));
1077 goto finish;
1078 }
1079 if (usec > arg_until)
1080 goto finish;
1081 }
1082
1083 if (!arg_merge) {
1084 sd_id128_t boot_id;
1085
1086 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1087 if (r >= 0) {
1088 if (previous_boot_id_valid &&
1089 !sd_id128_equal(boot_id, previous_boot_id))
1090 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1091
1092 previous_boot_id = boot_id;
1093 previous_boot_id_valid = true;
1094 }
1095 }
1096
1097 flags =
1098 arg_all * OUTPUT_SHOW_ALL |
1099 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1100 on_tty() * OUTPUT_COLOR |
1101 arg_catalog * OUTPUT_CATALOG;
1102
1103 r = output_journal(stdout, j, arg_output, 0, flags);
1104 if (r < 0 || ferror(stdout))
1105 goto finish;
1106
1107 need_seek = true;
1108 n_shown++;
1109 }
1110
1111 if (!arg_follow)
1112 break;
1113
1114 r = sd_journal_wait(j, (uint64_t) -1);
1115 if (r < 0) {
1116 log_error("Couldn't wait for journal event: %s", strerror(-r));
1117 goto finish;
1118 }
1119
1120 first_line = false;
1121 }
1122
1123 finish:
1124 if (j)
1125 sd_journal_close(j);
1126
1127 pager_close();
1128
1129 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1130 }