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