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