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