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