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