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