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