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