]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
journalctl: use _cleanup_ in one function
[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
517 assert(j);
518
519 STRV_FOREACH(i, args) {
520 int r;
521
522 if (streq(*i, "+"))
523 r = sd_journal_add_disjunction(j);
524 else if (path_is_absolute(*i)) {
525 char _cleanup_free_ *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 log_error("Couldn't stat file: %m");
534 return -errno;
535 }
536
537 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
538 t = strappend("_EXE=", path);
539 else if (S_ISCHR(st.st_mode))
540 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
541 else if (S_ISBLK(st.st_mode))
542 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
543 else {
544 log_error("File is not a device node, regular file or is not executable: %s", *i);
545 return -EINVAL;
546 }
547
548 if (!t)
549 return log_oom();
550
551 r = sd_journal_add_match(j, t, 0);
552 } else
553 r = sd_journal_add_match(j, *i, 0);
554
555 if (r < 0) {
556 log_error("Failed to add match '%s': %s", *i, strerror(-r));
557 return r;
558 }
559 }
560
561 return 0;
562 }
563
564 static int add_this_boot(sd_journal *j) {
565 char match[9+32+1] = "_BOOT_ID=";
566 sd_id128_t boot_id;
567 int r;
568
569 assert(j);
570
571 if (!arg_this_boot)
572 return 0;
573
574 r = sd_id128_get_boot(&boot_id);
575 if (r < 0) {
576 log_error("Failed to get boot id: %s", strerror(-r));
577 return r;
578 }
579
580 sd_id128_to_string(boot_id, match + 9);
581 r = sd_journal_add_match(j, match, strlen(match));
582 if (r < 0) {
583 log_error("Failed to add match: %s", strerror(-r));
584 return r;
585 }
586
587 return 0;
588 }
589
590 static int add_unit(sd_journal *j) {
591 _cleanup_free_ char *m = NULL, *u = NULL;
592 int r;
593
594 assert(j);
595
596 if (isempty(arg_unit))
597 return 0;
598
599 u = unit_name_mangle(arg_unit);
600 if (!u)
601 return log_oom();
602
603 if (arg_unit_system)
604 r = add_matches_for_unit(j, u);
605 else
606 r = add_matches_for_user_unit(j, u, getuid());
607 if (r < 0)
608 return r;
609
610 return 0;
611 }
612
613 static int add_priorities(sd_journal *j) {
614 char match[] = "PRIORITY=0";
615 int i, r;
616
617 assert(j);
618
619 if (arg_priorities == 0xFF)
620 return 0;
621
622 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
623 if (arg_priorities & (1 << i)) {
624 match[sizeof(match)-2] = '0' + i;
625
626 r = sd_journal_add_match(j, match, strlen(match));
627 if (r < 0) {
628 log_error("Failed to add match: %s", strerror(-r));
629 return r;
630 }
631 }
632
633 return 0;
634 }
635
636 static int setup_keys(void) {
637 #ifdef HAVE_GCRYPT
638 size_t mpk_size, seed_size, state_size, i;
639 uint8_t *mpk, *seed, *state;
640 ssize_t l;
641 int fd = -1, r, attr = 0;
642 sd_id128_t machine, boot;
643 char *p = NULL, *k = NULL;
644 struct FSSHeader h;
645 uint64_t n;
646
647 r = sd_id128_get_machine(&machine);
648 if (r < 0) {
649 log_error("Failed to get machine ID: %s", strerror(-r));
650 return r;
651 }
652
653 r = sd_id128_get_boot(&boot);
654 if (r < 0) {
655 log_error("Failed to get boot ID: %s", strerror(-r));
656 return r;
657 }
658
659 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
660 SD_ID128_FORMAT_VAL(machine)) < 0)
661 return log_oom();
662
663 if (access(p, F_OK) >= 0) {
664 log_error("Sealing key file %s exists already.", p);
665 r = -EEXIST;
666 goto finish;
667 }
668
669 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
670 SD_ID128_FORMAT_VAL(machine)) < 0) {
671 r = log_oom();
672 goto finish;
673 }
674
675 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
676 mpk = alloca(mpk_size);
677
678 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
679 seed = alloca(seed_size);
680
681 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
682 state = alloca(state_size);
683
684 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
685 if (fd < 0) {
686 log_error("Failed to open /dev/random: %m");
687 r = -errno;
688 goto finish;
689 }
690
691 log_info("Generating seed...");
692 l = loop_read(fd, seed, seed_size, true);
693 if (l < 0 || (size_t) l != seed_size) {
694 log_error("Failed to read random seed: %s", strerror(EIO));
695 r = -EIO;
696 goto finish;
697 }
698
699 log_info("Generating key pair...");
700 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
701
702 log_info("Generating sealing key...");
703 FSPRG_GenState0(state, mpk, seed, seed_size);
704
705 assert(arg_interval > 0);
706
707 n = now(CLOCK_REALTIME);
708 n /= arg_interval;
709
710 close_nointr_nofail(fd);
711 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
712 if (fd < 0) {
713 log_error("Failed to open %s: %m", k);
714 r = -errno;
715 goto finish;
716 }
717
718 /* Enable secure remove, exclusion from dump, synchronous
719 * writing and in-place updating */
720 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
721 log_warning("FS_IOC_GETFLAGS failed: %m");
722
723 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
724
725 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
726 log_warning("FS_IOC_SETFLAGS failed: %m");
727
728 zero(h);
729 memcpy(h.signature, "KSHHRHLP", 8);
730 h.machine_id = machine;
731 h.boot_id = boot;
732 h.header_size = htole64(sizeof(h));
733 h.start_usec = htole64(n * arg_interval);
734 h.interval_usec = htole64(arg_interval);
735 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
736 h.fsprg_state_size = htole64(state_size);
737
738 l = loop_write(fd, &h, sizeof(h), false);
739 if (l < 0 || (size_t) l != sizeof(h)) {
740 log_error("Failed to write header: %s", strerror(EIO));
741 r = -EIO;
742 goto finish;
743 }
744
745 l = loop_write(fd, state, state_size, false);
746 if (l < 0 || (size_t) l != state_size) {
747 log_error("Failed to write state: %s", strerror(EIO));
748 r = -EIO;
749 goto finish;
750 }
751
752 if (link(k, p) < 0) {
753 log_error("Failed to link file: %m");
754 r = -errno;
755 goto finish;
756 }
757
758 if (on_tty()) {
759 fprintf(stderr,
760 "\n"
761 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
762 "the following local file. This key file is automatically updated when the\n"
763 "sealing key is advanced. It should not be used on multiple hosts.\n"
764 "\n"
765 "\t%s\n"
766 "\n"
767 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
768 "at a safe location and should not be saved locally on disk.\n"
769 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
770 fflush(stderr);
771 }
772 for (i = 0; i < seed_size; i++) {
773 if (i > 0 && i % 3 == 0)
774 putchar('-');
775 printf("%02x", ((uint8_t*) seed)[i]);
776 }
777
778 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
779
780 if (on_tty()) {
781 char tsb[FORMAT_TIMESPAN_MAX], *hn;
782
783 fprintf(stderr,
784 ANSI_HIGHLIGHT_OFF "\n"
785 "The sealing key is automatically changed every %s.\n",
786 format_timespan(tsb, sizeof(tsb), arg_interval));
787
788 hn = gethostname_malloc();
789
790 if (hn) {
791 hostname_cleanup(hn);
792 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
793 } else
794 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
795
796 #ifdef HAVE_QRENCODE
797 /* If this is not an UTF-8 system don't print any QR codes */
798 if (is_locale_utf8()) {
799 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
800 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
801 }
802 #endif
803 free(hn);
804 }
805
806 r = 0;
807
808 finish:
809 if (fd >= 0)
810 close_nointr_nofail(fd);
811
812 if (k) {
813 unlink(k);
814 free(k);
815 }
816
817 free(p);
818
819 return r;
820 #else
821 log_error("Forward-secure sealing not available.");
822 return -ENOTSUP;
823 #endif
824 }
825
826 static int verify(sd_journal *j) {
827 int r = 0;
828 Iterator i;
829 JournalFile *f;
830
831 assert(j);
832
833 log_show_color(true);
834
835 HASHMAP_FOREACH(f, j->files, i) {
836 int k;
837 usec_t first, validated, last;
838
839 #ifdef HAVE_GCRYPT
840 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
841 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
842 #endif
843
844 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
845 if (k == -EINVAL) {
846 /* If the key was invalid give up right-away. */
847 return k;
848 } else if (k < 0) {
849 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
850 r = k;
851 } else {
852 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
853 log_info("PASS: %s", f->path);
854
855 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
856 if (validated > 0) {
857 log_info("=> Validated from %s to %s, final %s entries not sealed.",
858 format_timestamp(a, sizeof(a), first),
859 format_timestamp(b, sizeof(b), validated),
860 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
861 } else if (last > 0)
862 log_info("=> No sealing yet, %s of entries not sealed.",
863 format_timespan(c, sizeof(c), last - first));
864 else
865 log_info("=> No sealing yet, no entries in file.");
866 }
867 }
868 }
869
870 return r;
871 }
872
873 static int access_check(void) {
874
875 #ifdef HAVE_ACL
876 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("systemd-journal") <= 0) {
877 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages.");
878 return -EACCES;
879 }
880
881 if (!arg_quiet && geteuid() != 0 && in_group("systemd-journal") <= 0)
882 log_warning("Showing user generated messages only. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off.");
883 #else
884 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
885 log_error("No access to messages. Only users in the group 'systemd-journal' can see messages.");
886 return -EACCES;
887 }
888 #endif
889
890 return 0;
891 }
892
893 int main(int argc, char *argv[]) {
894 int r;
895 sd_journal _cleanup_journal_close_ *j = NULL;
896 bool need_seek = false;
897 sd_id128_t previous_boot_id;
898 bool previous_boot_id_valid = false, first_line = true;
899 int n_shown = 0;
900
901 setlocale(LC_ALL, "");
902 log_parse_environment();
903 log_open();
904
905 r = parse_argv(argc, argv);
906 if (r <= 0)
907 goto finish;
908
909 signal(SIGWINCH, columns_lines_cache_reset);
910
911 if (arg_action == ACTION_NEW_ID128) {
912 r = generate_new_id128();
913 goto finish;
914 }
915
916 if (arg_action == ACTION_SETUP_KEYS) {
917 r = setup_keys();
918 goto finish;
919 }
920
921 if (arg_action == ACTION_LIST_CATALOG) {
922 r = catalog_list(stdout);
923 if (r < 0)
924 log_error("Failed to list catalog: %s", strerror(-r));
925 goto finish;
926 }
927
928 if (arg_action == ACTION_UPDATE_CATALOG) {
929 r = catalog_update();
930 goto finish;
931 }
932
933 r = access_check();
934 if (r < 0)
935 return EXIT_FAILURE;
936
937 if (arg_directory)
938 r = sd_journal_open_directory(&j, arg_directory, 0);
939 else
940 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
941 if (r < 0) {
942 log_error("Failed to open journal: %s", strerror(-r));
943 return EXIT_FAILURE;
944 }
945
946 if (arg_action == ACTION_VERIFY) {
947 r = verify(j);
948 goto finish;
949 }
950
951 if (arg_action == ACTION_PRINT_HEADER) {
952 journal_print_header(j);
953 return EXIT_SUCCESS;
954 }
955
956 if (arg_action == ACTION_DISK_USAGE) {
957 uint64_t bytes;
958 char sbytes[FORMAT_BYTES_MAX];
959
960 r = sd_journal_get_usage(j, &bytes);
961 if (r < 0)
962 return EXIT_FAILURE;
963
964 printf("Journals take up %s on disk.\n",
965 format_bytes(sbytes, sizeof(sbytes), bytes));
966 return EXIT_SUCCESS;
967 }
968
969 r = add_this_boot(j);
970 if (r < 0)
971 return EXIT_FAILURE;
972
973 r = add_unit(j);
974 if (r < 0)
975 return EXIT_FAILURE;
976
977 r = add_matches(j, argv + optind);
978 if (r < 0)
979 return EXIT_FAILURE;
980
981 r = add_priorities(j);
982 if (r < 0)
983 return EXIT_FAILURE;
984
985 /* Opening the fd now means the first sd_journal_wait() will actually wait */
986 r = sd_journal_get_fd(j);
987 if (r < 0)
988 return EXIT_FAILURE;
989
990 if (arg_field) {
991 const void *data;
992 size_t size;
993
994 r = sd_journal_query_unique(j, arg_field);
995 if (r < 0) {
996 log_error("Failed to query unique data objects: %s", strerror(-r));
997 return EXIT_FAILURE;
998 }
999
1000 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1001 const void *eq;
1002
1003 if (arg_lines >= 0 && n_shown >= arg_lines)
1004 break;
1005
1006 eq = memchr(data, '=', size);
1007 if (eq)
1008 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1009 else
1010 printf("%.*s\n", (int) size, (const char*) data);
1011
1012 n_shown ++;
1013 }
1014
1015 return EXIT_SUCCESS;
1016 }
1017
1018 if (arg_cursor) {
1019 r = sd_journal_seek_cursor(j, arg_cursor);
1020 if (r < 0) {
1021 log_error("Failed to seek to cursor: %s", strerror(-r));
1022 return EXIT_FAILURE;
1023 }
1024 if (!arg_reverse)
1025 r = sd_journal_next(j);
1026 else
1027 r = sd_journal_previous(j);
1028
1029 } else if (arg_since_set && !arg_reverse) {
1030 r = sd_journal_seek_realtime_usec(j, arg_since);
1031 if (r < 0) {
1032 log_error("Failed to seek to date: %s", strerror(-r));
1033 return EXIT_FAILURE;
1034 }
1035 r = sd_journal_next(j);
1036
1037 } else if (arg_until_set && arg_reverse) {
1038 r = sd_journal_seek_realtime_usec(j, arg_until);
1039 if (r < 0) {
1040 log_error("Failed to seek to date: %s", strerror(-r));
1041 return EXIT_FAILURE;
1042 }
1043 r = sd_journal_previous(j);
1044
1045 } else if (arg_lines >= 0) {
1046 r = sd_journal_seek_tail(j);
1047 if (r < 0) {
1048 log_error("Failed to seek to tail: %s", strerror(-r));
1049 return EXIT_FAILURE;
1050 }
1051
1052 r = sd_journal_previous_skip(j, arg_lines);
1053
1054 } else if (arg_reverse) {
1055 r = sd_journal_seek_tail(j);
1056 if (r < 0) {
1057 log_error("Failed to seek to tail: %s", strerror(-r));
1058 return EXIT_FAILURE;
1059 }
1060
1061 r = sd_journal_previous(j);
1062
1063 } else {
1064 r = sd_journal_seek_head(j);
1065 if (r < 0) {
1066 log_error("Failed to seek to head: %s", strerror(-r));
1067 return EXIT_FAILURE;
1068 }
1069
1070 r = sd_journal_next(j);
1071 }
1072
1073 if (r < 0) {
1074 log_error("Failed to iterate through journal: %s", strerror(-r));
1075 return EXIT_FAILURE;
1076 }
1077
1078 if (!arg_no_pager && !arg_follow)
1079 pager_open(arg_pager_end);
1080
1081 if (!arg_quiet) {
1082 usec_t start, end;
1083 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1084
1085 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1086 if (r < 0) {
1087 log_error("Failed to get cutoff: %s", strerror(-r));
1088 goto finish;
1089 }
1090
1091 if (r > 0) {
1092 if (arg_follow)
1093 printf("-- Logs begin at %s. --\n",
1094 format_timestamp(start_buf, sizeof(start_buf), start));
1095 else
1096 printf("-- Logs begin at %s, end at %s. --\n",
1097 format_timestamp(start_buf, sizeof(start_buf), start),
1098 format_timestamp(end_buf, sizeof(end_buf), end));
1099 }
1100 }
1101
1102 for (;;) {
1103 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1104 int flags;
1105
1106 if (need_seek) {
1107 if (!arg_reverse)
1108 r = sd_journal_next(j);
1109 else
1110 r = sd_journal_previous(j);
1111 if (r < 0) {
1112 log_error("Failed to iterate through journal: %s", strerror(-r));
1113 goto finish;
1114 }
1115 }
1116
1117 if (r == 0)
1118 break;
1119
1120 if (arg_until_set && !arg_reverse) {
1121 usec_t usec;
1122
1123 r = sd_journal_get_realtime_usec(j, &usec);
1124 if (r < 0) {
1125 log_error("Failed to determine timestamp: %s", strerror(-r));
1126 goto finish;
1127 }
1128 if (usec > arg_until)
1129 goto finish;
1130 }
1131
1132 if (arg_since_set && arg_reverse) {
1133 usec_t usec;
1134
1135 r = sd_journal_get_realtime_usec(j, &usec);
1136 if (r < 0) {
1137 log_error("Failed to determine timestamp: %s", strerror(-r));
1138 goto finish;
1139 }
1140 if (usec < arg_since)
1141 goto finish;
1142 }
1143
1144 if (!arg_merge) {
1145 sd_id128_t boot_id;
1146
1147 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1148 if (r >= 0) {
1149 if (previous_boot_id_valid &&
1150 !sd_id128_equal(boot_id, previous_boot_id))
1151 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1152
1153 previous_boot_id = boot_id;
1154 previous_boot_id_valid = true;
1155 }
1156 }
1157
1158 flags =
1159 arg_all * OUTPUT_SHOW_ALL |
1160 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1161 on_tty() * OUTPUT_COLOR |
1162 arg_catalog * OUTPUT_CATALOG;
1163
1164 r = output_journal(stdout, j, arg_output, 0, flags);
1165 if (r < 0 || ferror(stdout))
1166 goto finish;
1167
1168 need_seek = true;
1169 n_shown++;
1170 }
1171
1172 if (!arg_follow)
1173 break;
1174
1175 r = sd_journal_wait(j, (uint64_t) -1);
1176 if (r < 0) {
1177 log_error("Couldn't wait for journal event: %s", strerror(-r));
1178 goto finish;
1179 }
1180
1181 first_line = false;
1182 }
1183
1184 finish:
1185 pager_close();
1186
1187 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1188 }