]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
journalctl: check return of strjoin
[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 const char *arg_cursor = NULL;
75 static const char *arg_directory = NULL;
76 static int arg_priorities = 0xFF;
77 static const char *arg_verify_key = NULL;
78 #ifdef HAVE_GCRYPT
79 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
80 #endif
81 static usec_t arg_since, arg_until;
82 static bool arg_since_set = false, arg_until_set = false;
83 static const char *arg_unit = NULL;
84 static bool arg_unit_system;
85 static const char *arg_field = NULL;
86 static bool arg_catalog = false;
87 static bool arg_reverse = false;
88 static const char *arg_root = NULL;
89
90 static enum {
91 ACTION_SHOW,
92 ACTION_NEW_ID128,
93 ACTION_PRINT_HEADER,
94 ACTION_SETUP_KEYS,
95 ACTION_VERIFY,
96 ACTION_DISK_USAGE,
97 ACTION_LIST_CATALOG,
98 ACTION_DUMP_CATALOG,
99 ACTION_UPDATE_CATALOG
100 } arg_action = ACTION_SHOW;
101
102 static int help(void) {
103
104 printf("%s [OPTIONS...] [MATCHES...]\n\n"
105 "Query the journal.\n\n"
106 "Flags:\n"
107 " --since=DATE Start showing entries newer or of the specified date\n"
108 " --until=DATE Stop showing entries older or of the specified date\n"
109 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
110 " -b --this-boot Show data only from current boot\n"
111 " -u --unit=UNIT Show data only from the specified unit\n"
112 " --user-unit=UNIT Show data only from the specified user session unit\n"
113 " -p --priority=RANGE Show only messages within the specified priority range\n"
114 " -e --pager-end Immediately jump to end of the journal in the pager\n"
115 " -f --follow Follow journal\n"
116 " -n --lines[=INTEGER] Number of journal entries to show\n"
117 " --no-tail Show all lines, even in follow mode\n"
118 " -r --reverse Show the newest entries first\n"
119 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
120 " verbose, export, json, json-pretty, json-sse, cat)\n"
121 " -x --catalog Add message explanations where available\n"
122 " --full Do not ellipsize fields\n"
123 " -a --all Show all fields, including long and unprintable\n"
124 " -q --quiet Don't show privilege warning\n"
125 " --no-pager Do not pipe output into a pager\n"
126 " -m --merge Show entries from all available journals\n"
127 " -D --directory=PATH Show journal files from directory\n"
128 " --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
152 static 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 arg_unit = optarg;
441 arg_unit_system = true;
442 break;
443
444 case ARG_USER_UNIT:
445 arg_unit = optarg;
446 arg_unit_system = false;
447 break;
448
449 case '?':
450 return -EINVAL;
451
452 case 'F':
453 arg_field = optarg;
454 break;
455
456 case 'x':
457 arg_catalog = true;
458 break;
459
460 case ARG_LIST_CATALOG:
461 arg_action = ACTION_LIST_CATALOG;
462 break;
463
464 case ARG_DUMP_CATALOG:
465 arg_action = ACTION_DUMP_CATALOG;
466 break;
467
468 case ARG_UPDATE_CATALOG:
469 arg_action = ACTION_UPDATE_CATALOG;
470 break;
471
472 case 'r':
473 arg_reverse = true;
474 break;
475
476 default:
477 log_error("Unknown option code %c", c);
478 return -EINVAL;
479 }
480 }
481
482 if (arg_follow && !arg_no_tail && arg_lines < 0)
483 arg_lines = 10;
484
485 if (arg_since_set && arg_until_set && arg_since > arg_until) {
486 log_error("--since= must be before --until=.");
487 return -EINVAL;
488 }
489
490 if (arg_cursor && arg_since_set) {
491 log_error("Please specify either --since= or --cursor=, not both.");
492 return -EINVAL;
493 }
494
495 if (arg_follow && arg_reverse) {
496 log_error("Please specify either --reverse= or --follow=, not both.");
497 return -EINVAL;
498 }
499
500 return 1;
501 }
502
503 static int generate_new_id128(void) {
504 sd_id128_t id;
505 int r;
506 unsigned i;
507
508 r = sd_id128_randomize(&id);
509 if (r < 0) {
510 log_error("Failed to generate ID: %s", strerror(-r));
511 return r;
512 }
513
514 printf("As string:\n"
515 SD_ID128_FORMAT_STR "\n\n"
516 "As UUID:\n"
517 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
518 "As macro:\n"
519 "#define MESSAGE_XYZ SD_ID128_MAKE(",
520 SD_ID128_FORMAT_VAL(id),
521 SD_ID128_FORMAT_VAL(id));
522 for (i = 0; i < 16; i++)
523 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
524 fputs(")\n\n", stdout);
525
526 printf("As Python constant:\n"
527 ">>> import uuid\n"
528 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
529 SD_ID128_FORMAT_VAL(id));
530
531 return 0;
532 }
533
534 static int add_matches(sd_journal *j, char **args) {
535 char **i;
536
537 assert(j);
538
539 STRV_FOREACH(i, args) {
540 int r;
541
542 if (streq(*i, "+"))
543 r = sd_journal_add_disjunction(j);
544 else if (path_is_absolute(*i)) {
545 char _cleanup_free_ *p, *t = NULL;
546 const char *path;
547 struct stat st;
548
549 p = canonicalize_file_name(*i);
550 path = p ? p : *i;
551
552 if (stat(path, &st) < 0) {
553 log_error("Couldn't stat file: %m");
554 return -errno;
555 }
556
557 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
558 t = strappend("_EXE=", path);
559 else if (S_ISCHR(st.st_mode))
560 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
561 else if (S_ISBLK(st.st_mode))
562 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
563 else {
564 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
565 return -EINVAL;
566 }
567
568 if (!t)
569 return log_oom();
570
571 r = sd_journal_add_match(j, t, 0);
572 } else
573 r = sd_journal_add_match(j, *i, 0);
574
575 if (r < 0) {
576 log_error("Failed to add match '%s': %s", *i, strerror(-r));
577 return r;
578 }
579 }
580
581 return 0;
582 }
583
584 static int add_this_boot(sd_journal *j) {
585 char match[9+32+1] = "_BOOT_ID=";
586 sd_id128_t boot_id;
587 int r;
588
589 assert(j);
590
591 if (!arg_this_boot)
592 return 0;
593
594 r = sd_id128_get_boot(&boot_id);
595 if (r < 0) {
596 log_error("Failed to get boot id: %s", strerror(-r));
597 return r;
598 }
599
600 sd_id128_to_string(boot_id, match + 9);
601 r = sd_journal_add_match(j, match, strlen(match));
602 if (r < 0) {
603 log_error("Failed to add match: %s", strerror(-r));
604 return r;
605 }
606
607 return 0;
608 }
609
610 static int add_unit(sd_journal *j) {
611 _cleanup_free_ char *u = NULL;
612 int r;
613
614 assert(j);
615
616 if (isempty(arg_unit))
617 return 0;
618
619 u = unit_name_mangle(arg_unit);
620 if (!u)
621 return log_oom();
622
623 if (arg_unit_system)
624 r = add_matches_for_unit(j, u);
625 else
626 r = add_matches_for_user_unit(j, u, getuid());
627 if (r < 0)
628 return r;
629
630 return 0;
631 }
632
633 static int add_priorities(sd_journal *j) {
634 char match[] = "PRIORITY=0";
635 int i, r;
636
637 assert(j);
638
639 if (arg_priorities == 0xFF)
640 return 0;
641
642 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
643 if (arg_priorities & (1 << i)) {
644 match[sizeof(match)-2] = '0' + i;
645
646 r = sd_journal_add_match(j, match, strlen(match));
647 if (r < 0) {
648 log_error("Failed to add match: %s", strerror(-r));
649 return r;
650 }
651 }
652
653 return 0;
654 }
655
656 static int setup_keys(void) {
657 #ifdef HAVE_GCRYPT
658 size_t mpk_size, seed_size, state_size, i;
659 uint8_t *mpk, *seed, *state;
660 ssize_t l;
661 int fd = -1, r, attr = 0;
662 sd_id128_t machine, boot;
663 char *p = NULL, *k = NULL;
664 struct FSSHeader h;
665 uint64_t n;
666
667 r = sd_id128_get_machine(&machine);
668 if (r < 0) {
669 log_error("Failed to get machine ID: %s", strerror(-r));
670 return r;
671 }
672
673 r = sd_id128_get_boot(&boot);
674 if (r < 0) {
675 log_error("Failed to get boot ID: %s", strerror(-r));
676 return r;
677 }
678
679 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
680 SD_ID128_FORMAT_VAL(machine)) < 0)
681 return log_oom();
682
683 if (access(p, F_OK) >= 0) {
684 log_error("Sealing key file %s exists already.", p);
685 r = -EEXIST;
686 goto finish;
687 }
688
689 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
690 SD_ID128_FORMAT_VAL(machine)) < 0) {
691 r = log_oom();
692 goto finish;
693 }
694
695 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
696 mpk = alloca(mpk_size);
697
698 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
699 seed = alloca(seed_size);
700
701 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
702 state = alloca(state_size);
703
704 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
705 if (fd < 0) {
706 log_error("Failed to open /dev/random: %m");
707 r = -errno;
708 goto finish;
709 }
710
711 log_info("Generating seed...");
712 l = loop_read(fd, seed, seed_size, true);
713 if (l < 0 || (size_t) l != seed_size) {
714 log_error("Failed to read random seed: %s", strerror(EIO));
715 r = -EIO;
716 goto finish;
717 }
718
719 log_info("Generating key pair...");
720 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
721
722 log_info("Generating sealing key...");
723 FSPRG_GenState0(state, mpk, seed, seed_size);
724
725 assert(arg_interval > 0);
726
727 n = now(CLOCK_REALTIME);
728 n /= arg_interval;
729
730 close_nointr_nofail(fd);
731 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
732 if (fd < 0) {
733 log_error("Failed to open %s: %m", k);
734 r = -errno;
735 goto finish;
736 }
737
738 /* Enable secure remove, exclusion from dump, synchronous
739 * writing and in-place updating */
740 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
741 log_warning("FS_IOC_GETFLAGS failed: %m");
742
743 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
744
745 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
746 log_warning("FS_IOC_SETFLAGS failed: %m");
747
748 zero(h);
749 memcpy(h.signature, "KSHHRHLP", 8);
750 h.machine_id = machine;
751 h.boot_id = boot;
752 h.header_size = htole64(sizeof(h));
753 h.start_usec = htole64(n * arg_interval);
754 h.interval_usec = htole64(arg_interval);
755 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
756 h.fsprg_state_size = htole64(state_size);
757
758 l = loop_write(fd, &h, sizeof(h), false);
759 if (l < 0 || (size_t) l != sizeof(h)) {
760 log_error("Failed to write header: %s", strerror(EIO));
761 r = -EIO;
762 goto finish;
763 }
764
765 l = loop_write(fd, state, state_size, false);
766 if (l < 0 || (size_t) l != state_size) {
767 log_error("Failed to write state: %s", strerror(EIO));
768 r = -EIO;
769 goto finish;
770 }
771
772 if (link(k, p) < 0) {
773 log_error("Failed to link file: %m");
774 r = -errno;
775 goto finish;
776 }
777
778 if (on_tty()) {
779 fprintf(stderr,
780 "\n"
781 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
782 "the following local file. This key file is automatically updated when the\n"
783 "sealing key is advanced. It should not be used on multiple hosts.\n"
784 "\n"
785 "\t%s\n"
786 "\n"
787 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
788 "at a safe location and should not be saved locally on disk.\n"
789 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
790 fflush(stderr);
791 }
792 for (i = 0; i < seed_size; i++) {
793 if (i > 0 && i % 3 == 0)
794 putchar('-');
795 printf("%02x", ((uint8_t*) seed)[i]);
796 }
797
798 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
799
800 if (on_tty()) {
801 char tsb[FORMAT_TIMESPAN_MAX], *hn;
802
803 fprintf(stderr,
804 ANSI_HIGHLIGHT_OFF "\n"
805 "The sealing key is automatically changed every %s.\n",
806 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
807
808 hn = gethostname_malloc();
809
810 if (hn) {
811 hostname_cleanup(hn);
812 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
813 } else
814 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
815
816 #ifdef HAVE_QRENCODE
817 /* If this is not an UTF-8 system don't print any QR codes */
818 if (is_locale_utf8()) {
819 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
820 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
821 }
822 #endif
823 free(hn);
824 }
825
826 r = 0;
827
828 finish:
829 if (fd >= 0)
830 close_nointr_nofail(fd);
831
832 if (k) {
833 unlink(k);
834 free(k);
835 }
836
837 free(p);
838
839 return r;
840 #else
841 log_error("Forward-secure sealing not available.");
842 return -ENOTSUP;
843 #endif
844 }
845
846 static int verify(sd_journal *j) {
847 int r = 0;
848 Iterator i;
849 JournalFile *f;
850
851 assert(j);
852
853 log_show_color(true);
854
855 HASHMAP_FOREACH(f, j->files, i) {
856 int k;
857 usec_t first, validated, last;
858
859 #ifdef HAVE_GCRYPT
860 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
861 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
862 #endif
863
864 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
865 if (k == -EINVAL) {
866 /* If the key was invalid give up right-away. */
867 return k;
868 } else if (k < 0) {
869 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
870 r = k;
871 } else {
872 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
873 log_info("PASS: %s", f->path);
874
875 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
876 if (validated > 0) {
877 log_info("=> Validated from %s to %s, final %s entries not sealed.",
878 format_timestamp(a, sizeof(a), first),
879 format_timestamp(b, sizeof(b), validated),
880 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
881 } else if (last > 0)
882 log_info("=> No sealing yet, %s of entries not sealed.",
883 format_timespan(c, sizeof(c), last - first, 0));
884 else
885 log_info("=> No sealing yet, no entries in file.");
886 }
887 }
888 }
889
890 return r;
891 }
892
893 #ifdef HAVE_ACL
894 static int access_check_var_log_journal(sd_journal *j) {
895 _cleanup_strv_free_ char **g = NULL;
896 bool have_access;
897 int r;
898
899 assert(j);
900
901 have_access = in_group("systemd-journal") > 0;
902
903 if (!have_access) {
904 /* Let's enumerate all groups from the default ACL of
905 * the directory, which generally should allow access
906 * to most journal files too */
907 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
908 if (r < 0)
909 return r;
910 }
911
912 if (!have_access) {
913
914 if (strv_isempty(g))
915 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
916 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
917 " turn off this notice.");
918 else {
919 _cleanup_free_ char *s = NULL;
920
921 r = strv_extend(&g, "systemd-journal");
922 if (r < 0)
923 return log_oom();
924
925 strv_sort(g);
926 strv_uniq(g);
927
928 s = strv_join(g, "', '");
929 if (!s)
930 return log_oom();
931
932 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
933 " Users in the groups '%s' can see all messages.\n"
934 " Pass -q to turn off this notice.", s);
935 }
936 }
937
938 return 0;
939 }
940 #endif
941
942 static int access_check(sd_journal *j) {
943 Iterator it;
944 void *code;
945 int r = 0;
946
947 assert(j);
948
949 if (set_isempty(j->errors)) {
950 if (hashmap_isempty(j->files))
951 log_notice("No journal files were found.");
952 return 0;
953 }
954
955 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
956 #ifdef HAVE_ACL
957 /* If /var/log/journal doesn't even exist,
958 * unprivileged users have no access at all */
959 if (access("/var/log/journal", F_OK) < 0 &&
960 geteuid() != 0 &&
961 in_group("systemd-journal") <= 0) {
962 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
963 "enabled. Users in the 'systemd-journal' group may always access messages.");
964 return -EACCES;
965 }
966
967 /* If /var/log/journal exists, try to pring a nice
968 notice if the user lacks access to it */
969 if (!arg_quiet && geteuid() != 0) {
970 r = access_check_var_log_journal(j);
971 if (r < 0)
972 return r;
973 }
974 #else
975 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
976 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
977 "group may access messages.");
978 return -EACCES;
979 }
980 #endif
981
982 if (hashmap_isempty(j->files)) {
983 log_error("No journal files were opened due to insufficient permissions.");
984 r = -EACCES;
985 }
986 }
987
988 SET_FOREACH(code, j->errors, it) {
989 int err;
990
991 err = -PTR_TO_INT(code);
992 assert(err > 0);
993
994 if (err != EACCES)
995 log_warning("Error was encountered while opening journal files: %s",
996 strerror(err));
997 }
998
999 return r;
1000 }
1001
1002 int main(int argc, char *argv[]) {
1003 int r;
1004 sd_journal _cleanup_journal_close_ *j = NULL;
1005 bool need_seek = false;
1006 sd_id128_t previous_boot_id;
1007 bool previous_boot_id_valid = false, first_line = true;
1008 int n_shown = 0;
1009
1010 setlocale(LC_ALL, "");
1011 log_parse_environment();
1012 log_open();
1013
1014 r = parse_argv(argc, argv);
1015 if (r <= 0)
1016 goto finish;
1017
1018 signal(SIGWINCH, columns_lines_cache_reset);
1019
1020 if (arg_action == ACTION_NEW_ID128) {
1021 r = generate_new_id128();
1022 goto finish;
1023 }
1024
1025 if (arg_action == ACTION_SETUP_KEYS) {
1026 r = setup_keys();
1027 goto finish;
1028 }
1029
1030 if (arg_action == ACTION_UPDATE_CATALOG ||
1031 arg_action == ACTION_LIST_CATALOG ||
1032 arg_action == ACTION_DUMP_CATALOG) {
1033
1034 const char* database = CATALOG_DATABASE;
1035 char _cleanup_free_ *copy = NULL;
1036 if (arg_root) {
1037 copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1038 if (!copy) {
1039 r = log_oom();
1040 goto finish;
1041 }
1042 path_kill_slashes(copy);
1043 database = copy;
1044 }
1045
1046 if (arg_action == ACTION_UPDATE_CATALOG) {
1047 r = catalog_update(database, arg_root, catalog_file_dirs);
1048 if (r < 0)
1049 log_error("Failed to list catalog: %s", strerror(-r));
1050 } else {
1051 bool oneline = arg_action == ACTION_LIST_CATALOG;
1052
1053 if (optind < argc)
1054 r = catalog_list_items(stdout, database,
1055 oneline, argv + optind);
1056 else
1057 r = catalog_list(stdout, database, oneline);
1058 if (r < 0)
1059 log_error("Failed to list catalog: %s", strerror(-r));
1060 }
1061
1062 goto finish;
1063 }
1064
1065 if (arg_directory)
1066 r = sd_journal_open_directory(&j, arg_directory, 0);
1067 else
1068 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
1069 if (r < 0) {
1070 log_error("Failed to open journal: %s", strerror(-r));
1071 return EXIT_FAILURE;
1072 }
1073
1074 r = access_check(j);
1075 if (r < 0)
1076 return EXIT_FAILURE;
1077
1078 if (arg_action == ACTION_VERIFY) {
1079 r = verify(j);
1080 goto finish;
1081 }
1082
1083 if (arg_action == ACTION_PRINT_HEADER) {
1084 journal_print_header(j);
1085 return EXIT_SUCCESS;
1086 }
1087
1088 if (arg_action == ACTION_DISK_USAGE) {
1089 uint64_t bytes;
1090 char sbytes[FORMAT_BYTES_MAX];
1091
1092 r = sd_journal_get_usage(j, &bytes);
1093 if (r < 0)
1094 return EXIT_FAILURE;
1095
1096 printf("Journals take up %s on disk.\n",
1097 format_bytes(sbytes, sizeof(sbytes), bytes));
1098 return EXIT_SUCCESS;
1099 }
1100
1101 r = add_this_boot(j);
1102 if (r < 0)
1103 return EXIT_FAILURE;
1104
1105 r = add_unit(j);
1106 if (r < 0)
1107 return EXIT_FAILURE;
1108
1109 r = add_matches(j, argv + optind);
1110 if (r < 0)
1111 return EXIT_FAILURE;
1112
1113 r = add_priorities(j);
1114 if (r < 0)
1115 return EXIT_FAILURE;
1116
1117 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1118 r = sd_journal_get_fd(j);
1119 if (r < 0)
1120 return EXIT_FAILURE;
1121
1122 if (arg_field) {
1123 const void *data;
1124 size_t size;
1125
1126 r = sd_journal_query_unique(j, arg_field);
1127 if (r < 0) {
1128 log_error("Failed to query unique data objects: %s", strerror(-r));
1129 return EXIT_FAILURE;
1130 }
1131
1132 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1133 const void *eq;
1134
1135 if (arg_lines >= 0 && n_shown >= arg_lines)
1136 break;
1137
1138 eq = memchr(data, '=', size);
1139 if (eq)
1140 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1141 else
1142 printf("%.*s\n", (int) size, (const char*) data);
1143
1144 n_shown ++;
1145 }
1146
1147 return EXIT_SUCCESS;
1148 }
1149
1150 if (arg_cursor) {
1151 r = sd_journal_seek_cursor(j, arg_cursor);
1152 if (r < 0) {
1153 log_error("Failed to seek to cursor: %s", strerror(-r));
1154 return EXIT_FAILURE;
1155 }
1156 if (!arg_reverse)
1157 r = sd_journal_next(j);
1158 else
1159 r = sd_journal_previous(j);
1160
1161 } else if (arg_since_set && !arg_reverse) {
1162 r = sd_journal_seek_realtime_usec(j, arg_since);
1163 if (r < 0) {
1164 log_error("Failed to seek to date: %s", strerror(-r));
1165 return EXIT_FAILURE;
1166 }
1167 r = sd_journal_next(j);
1168
1169 } else if (arg_until_set && arg_reverse) {
1170 r = sd_journal_seek_realtime_usec(j, arg_until);
1171 if (r < 0) {
1172 log_error("Failed to seek to date: %s", strerror(-r));
1173 return EXIT_FAILURE;
1174 }
1175 r = sd_journal_previous(j);
1176
1177 } else if (arg_lines >= 0) {
1178 r = sd_journal_seek_tail(j);
1179 if (r < 0) {
1180 log_error("Failed to seek to tail: %s", strerror(-r));
1181 return EXIT_FAILURE;
1182 }
1183
1184 r = sd_journal_previous_skip(j, arg_lines);
1185
1186 } else if (arg_reverse) {
1187 r = sd_journal_seek_tail(j);
1188 if (r < 0) {
1189 log_error("Failed to seek to tail: %s", strerror(-r));
1190 return EXIT_FAILURE;
1191 }
1192
1193 r = sd_journal_previous(j);
1194
1195 } else {
1196 r = sd_journal_seek_head(j);
1197 if (r < 0) {
1198 log_error("Failed to seek to head: %s", strerror(-r));
1199 return EXIT_FAILURE;
1200 }
1201
1202 r = sd_journal_next(j);
1203 }
1204
1205 if (r < 0) {
1206 log_error("Failed to iterate through journal: %s", strerror(-r));
1207 return EXIT_FAILURE;
1208 }
1209
1210 if (!arg_no_pager && !arg_follow)
1211 pager_open(arg_pager_end);
1212
1213 if (!arg_quiet) {
1214 usec_t start, end;
1215 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1216
1217 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1218 if (r < 0) {
1219 log_error("Failed to get cutoff: %s", strerror(-r));
1220 goto finish;
1221 }
1222
1223 if (r > 0) {
1224 if (arg_follow)
1225 printf("-- Logs begin at %s. --\n",
1226 format_timestamp(start_buf, sizeof(start_buf), start));
1227 else
1228 printf("-- Logs begin at %s, end at %s. --\n",
1229 format_timestamp(start_buf, sizeof(start_buf), start),
1230 format_timestamp(end_buf, sizeof(end_buf), end));
1231 }
1232 }
1233
1234 for (;;) {
1235 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1236 int flags;
1237
1238 if (need_seek) {
1239 if (!arg_reverse)
1240 r = sd_journal_next(j);
1241 else
1242 r = sd_journal_previous(j);
1243 if (r < 0) {
1244 log_error("Failed to iterate through journal: %s", strerror(-r));
1245 goto finish;
1246 }
1247 }
1248
1249 if (r == 0)
1250 break;
1251
1252 if (arg_until_set && !arg_reverse) {
1253 usec_t usec;
1254
1255 r = sd_journal_get_realtime_usec(j, &usec);
1256 if (r < 0) {
1257 log_error("Failed to determine timestamp: %s", strerror(-r));
1258 goto finish;
1259 }
1260 if (usec > arg_until)
1261 goto finish;
1262 }
1263
1264 if (arg_since_set && arg_reverse) {
1265 usec_t usec;
1266
1267 r = sd_journal_get_realtime_usec(j, &usec);
1268 if (r < 0) {
1269 log_error("Failed to determine timestamp: %s", strerror(-r));
1270 goto finish;
1271 }
1272 if (usec < arg_since)
1273 goto finish;
1274 }
1275
1276 if (!arg_merge) {
1277 sd_id128_t boot_id;
1278
1279 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1280 if (r >= 0) {
1281 if (previous_boot_id_valid &&
1282 !sd_id128_equal(boot_id, previous_boot_id))
1283 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1284
1285 previous_boot_id = boot_id;
1286 previous_boot_id_valid = true;
1287 }
1288 }
1289
1290 flags =
1291 arg_all * OUTPUT_SHOW_ALL |
1292 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1293 on_tty() * OUTPUT_COLOR |
1294 arg_catalog * OUTPUT_CATALOG;
1295
1296 r = output_journal(stdout, j, arg_output, 0, flags);
1297 if (r < 0 || ferror(stdout))
1298 goto finish;
1299
1300 need_seek = true;
1301 n_shown++;
1302 }
1303
1304 if (!arg_follow)
1305 break;
1306
1307 r = sd_journal_wait(j, (uint64_t) -1);
1308 if (r < 0) {
1309 log_error("Couldn't wait for journal event: %s", strerror(-r));
1310 goto finish;
1311 }
1312
1313 first_line = false;
1314 }
1315
1316 finish:
1317 pager_close();
1318
1319 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1320 }