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