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