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