]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
hashmap: introduce hash_ops to make struct Hashmap smaller
[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 <fnmatch.h>
25 #include <errno.h>
26 #include <stddef.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.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 #ifdef HAVE_ACL
39 #include <sys/acl.h>
40 #include "acl-util.h"
41 #endif
42
43 #include "systemd/sd-journal.h"
44
45 #include "log.h"
46 #include "logs-show.h"
47 #include "util.h"
48 #include "path-util.h"
49 #include "fileio.h"
50 #include "build.h"
51 #include "pager.h"
52 #include "strv.h"
53 #include "set.h"
54 #include "journal-internal.h"
55 #include "journal-def.h"
56 #include "journal-verify.h"
57 #include "journal-authenticate.h"
58 #include "journal-qrcode.h"
59 #include "fsprg.h"
60 #include "unit-name.h"
61 #include "catalog.h"
62
63 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
64
65 static OutputMode arg_output = OUTPUT_SHORT;
66 static bool arg_pager_end = false;
67 static bool arg_follow = false;
68 static bool arg_full = true;
69 static bool arg_all = false;
70 static bool arg_no_pager = false;
71 static int arg_lines = -2;
72 static bool arg_no_tail = false;
73 static bool arg_quiet = false;
74 static bool arg_merge = false;
75 static bool arg_boot = false;
76 static sd_id128_t arg_boot_id = {};
77 static int arg_boot_offset = 0;
78 static bool arg_dmesg = false;
79 static const char *arg_cursor = NULL;
80 static const char *arg_after_cursor = NULL;
81 static bool arg_show_cursor = false;
82 static const char *arg_directory = NULL;
83 static char **arg_file = NULL;
84 static int arg_priorities = 0xFF;
85 static const char *arg_verify_key = NULL;
86 #ifdef HAVE_GCRYPT
87 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
88 static bool arg_force = false;
89 #endif
90 static usec_t arg_since, arg_until;
91 static bool arg_since_set = false, arg_until_set = false;
92 static char **arg_syslog_identifier = NULL;
93 static char **arg_system_units = NULL;
94 static char **arg_user_units = NULL;
95 static const char *arg_field = NULL;
96 static bool arg_catalog = false;
97 static bool arg_reverse = false;
98 static int arg_journal_type = 0;
99 static const char *arg_root = NULL;
100 static const char *arg_machine = NULL;
101
102 static enum {
103 ACTION_SHOW,
104 ACTION_NEW_ID128,
105 ACTION_PRINT_HEADER,
106 ACTION_SETUP_KEYS,
107 ACTION_VERIFY,
108 ACTION_DISK_USAGE,
109 ACTION_LIST_CATALOG,
110 ACTION_DUMP_CATALOG,
111 ACTION_UPDATE_CATALOG,
112 ACTION_LIST_BOOTS,
113 } arg_action = ACTION_SHOW;
114
115 typedef struct boot_id_t {
116 sd_id128_t id;
117 uint64_t first;
118 uint64_t last;
119 } boot_id_t;
120
121 static void pager_open_if_enabled(void) {
122
123 if (arg_no_pager)
124 return;
125
126 pager_open(arg_pager_end);
127 }
128
129 static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
130 sd_id128_t id = SD_ID128_NULL;
131 int off = 0, r;
132
133 if (strlen(x) >= 32) {
134 char *t;
135
136 t = strndupa(x, 32);
137 r = sd_id128_from_string(t, &id);
138 if (r >= 0)
139 x += 32;
140
141 if (*x != '-' && *x != '+' && *x != 0)
142 return -EINVAL;
143
144 if (*x != 0) {
145 r = safe_atoi(x, &off);
146 if (r < 0)
147 return r;
148 }
149 } else {
150 r = safe_atoi(x, &off);
151 if (r < 0)
152 return r;
153 }
154
155 if (boot_id)
156 *boot_id = id;
157
158 if (offset)
159 *offset = off;
160
161 return 0;
162 }
163
164 static void help(void) {
165
166 pager_open_if_enabled();
167
168 printf("%s [OPTIONS...] [MATCHES...]\n\n"
169 "Query the journal.\n\n"
170 "Flags:\n"
171 " --system Show the system journal\n"
172 " --user Show the user journal for the current user\n"
173 " -M --machine=CONTAINER Operate on local container\n"
174 " --since=DATE Start showing entries on or newer than the specified date\n"
175 " --until=DATE Stop showing entries on or older than the specified date\n"
176 " -c --cursor=CURSOR Start showing entries from the specified cursor\n"
177 " --after-cursor=CURSOR Start showing entries from after the specified cursor\n"
178 " --show-cursor Print the cursor after all the entries\n"
179 " -b --boot[=ID] Show data only from ID or, if unspecified, the current boot\n"
180 " --list-boots Show terse information about recorded boots\n"
181 " -k --dmesg Show kernel message log from the current boot\n"
182 " -u --unit=UNIT Show data only from the specified unit\n"
183 " --user-unit=UNIT Show data only from the specified user session unit\n"
184 " -t --identifier=STRING Show only messages with the specified syslog identifier\n"
185 " -p --priority=RANGE Show only messages within the specified priority range\n"
186 " -e --pager-end Immediately jump to end of the journal in the pager\n"
187 " -f --follow Follow the journal\n"
188 " -n --lines[=INTEGER] Number of journal entries to show\n"
189 " --no-tail Show all lines, even in follow mode\n"
190 " -r --reverse Show the newest entries first\n"
191 " -o --output=STRING Change journal output mode (short, short-iso,\n"
192 " short-precise, short-monotonic, verbose,\n"
193 " export, json, json-pretty, json-sse, cat)\n"
194 " -x --catalog Add message explanations where available\n"
195 " --no-full Ellipsize fields\n"
196 " -a --all Show all fields, including long and unprintable\n"
197 " -q --quiet Do not show privilege warning\n"
198 " --no-pager Do not pipe output into a pager\n"
199 " -m --merge Show entries from all available journals\n"
200 " -D --directory=PATH Show journal files from directory\n"
201 " --file=PATH Show journal file\n"
202 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
203 #ifdef HAVE_GCRYPT
204 " --interval=TIME Time interval for changing the FSS sealing key\n"
205 " --verify-key=KEY Specify FSS verification key\n"
206 " --force Force overriding of the FSS key pair with --setup-keys\n"
207 #endif
208 "\nCommands:\n"
209 " -h --help Show this help text\n"
210 " --version Show package version\n"
211 " --new-id128 Generate a new 128-bit ID\n"
212 " --header Show journal header information\n"
213 " --disk-usage Show total disk usage of all journal files\n"
214 " -F --field=FIELD List all values that a specified field takes\n"
215 " --list-catalog Show message IDs of all entries in the message catalog\n"
216 " --dump-catalog Show entries in the message catalog\n"
217 " --update-catalog Update the message catalog database\n"
218 #ifdef HAVE_GCRYPT
219 " --setup-keys Generate a new FSS key pair\n"
220 " --verify Verify journal file consistency\n"
221 #endif
222 , program_invocation_short_name);
223 }
224
225 static int parse_argv(int argc, char *argv[]) {
226
227 enum {
228 ARG_VERSION = 0x100,
229 ARG_NO_PAGER,
230 ARG_NO_FULL,
231 ARG_NO_TAIL,
232 ARG_NEW_ID128,
233 ARG_LIST_BOOTS,
234 ARG_USER,
235 ARG_SYSTEM,
236 ARG_ROOT,
237 ARG_HEADER,
238 ARG_SETUP_KEYS,
239 ARG_FILE,
240 ARG_INTERVAL,
241 ARG_VERIFY,
242 ARG_VERIFY_KEY,
243 ARG_DISK_USAGE,
244 ARG_SINCE,
245 ARG_UNTIL,
246 ARG_AFTER_CURSOR,
247 ARG_SHOW_CURSOR,
248 ARG_USER_UNIT,
249 ARG_LIST_CATALOG,
250 ARG_DUMP_CATALOG,
251 ARG_UPDATE_CATALOG,
252 ARG_FORCE,
253 };
254
255 static const struct option options[] = {
256 { "help", no_argument, NULL, 'h' },
257 { "version" , no_argument, NULL, ARG_VERSION },
258 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
259 { "pager-end", no_argument, NULL, 'e' },
260 { "follow", no_argument, NULL, 'f' },
261 { "force", no_argument, NULL, ARG_FORCE },
262 { "output", required_argument, NULL, 'o' },
263 { "all", no_argument, NULL, 'a' },
264 { "full", no_argument, NULL, 'l' },
265 { "no-full", no_argument, NULL, ARG_NO_FULL },
266 { "lines", optional_argument, NULL, 'n' },
267 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
268 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
269 { "quiet", no_argument, NULL, 'q' },
270 { "merge", no_argument, NULL, 'm' },
271 { "boot", optional_argument, NULL, 'b' },
272 { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
273 { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */
274 { "dmesg", no_argument, NULL, 'k' },
275 { "system", no_argument, NULL, ARG_SYSTEM },
276 { "user", no_argument, NULL, ARG_USER },
277 { "directory", required_argument, NULL, 'D' },
278 { "file", required_argument, NULL, ARG_FILE },
279 { "root", required_argument, NULL, ARG_ROOT },
280 { "header", no_argument, NULL, ARG_HEADER },
281 { "identifier", required_argument, NULL, 't' },
282 { "priority", required_argument, NULL, 'p' },
283 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
284 { "interval", required_argument, NULL, ARG_INTERVAL },
285 { "verify", no_argument, NULL, ARG_VERIFY },
286 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
287 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
288 { "cursor", required_argument, NULL, 'c' },
289 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
290 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
291 { "since", required_argument, NULL, ARG_SINCE },
292 { "until", required_argument, NULL, ARG_UNTIL },
293 { "unit", required_argument, NULL, 'u' },
294 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
295 { "field", required_argument, NULL, 'F' },
296 { "catalog", no_argument, NULL, 'x' },
297 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
298 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
299 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
300 { "reverse", no_argument, NULL, 'r' },
301 { "machine", required_argument, NULL, 'M' },
302 {}
303 };
304
305 int c, r;
306
307 assert(argc >= 0);
308 assert(argv);
309
310 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
311
312 switch (c) {
313
314 case 'h':
315 help();
316 return 0;
317
318 case ARG_VERSION:
319 puts(PACKAGE_STRING);
320 puts(SYSTEMD_FEATURES);
321 return 0;
322
323 case ARG_NO_PAGER:
324 arg_no_pager = true;
325 break;
326
327 case 'e':
328 arg_pager_end = true;
329
330 if (arg_lines < -1)
331 arg_lines = 1000;
332
333 break;
334
335 case 'f':
336 arg_follow = true;
337 break;
338
339 case 'o':
340 arg_output = output_mode_from_string(optarg);
341 if (arg_output < 0) {
342 log_error("Unknown output format '%s'.", optarg);
343 return -EINVAL;
344 }
345
346 if (arg_output == OUTPUT_EXPORT ||
347 arg_output == OUTPUT_JSON ||
348 arg_output == OUTPUT_JSON_PRETTY ||
349 arg_output == OUTPUT_JSON_SSE ||
350 arg_output == OUTPUT_CAT)
351 arg_quiet = true;
352
353 break;
354
355 case 'l':
356 arg_full = true;
357 break;
358
359 case ARG_NO_FULL:
360 arg_full = false;
361 break;
362
363 case 'a':
364 arg_all = true;
365 break;
366
367 case 'n':
368 if (optarg) {
369 if (streq(optarg, "all"))
370 arg_lines = -1;
371 else {
372 r = safe_atoi(optarg, &arg_lines);
373 if (r < 0 || arg_lines < 0) {
374 log_error("Failed to parse lines '%s'", optarg);
375 return -EINVAL;
376 }
377 }
378 } else {
379 arg_lines = 10;
380
381 /* Hmm, no argument? Maybe the next
382 * word on the command line is
383 * supposed to be the argument? Let's
384 * see if there is one, and is
385 * parsable. */
386 if (optind < argc) {
387 int n;
388 if (streq(argv[optind], "all")) {
389 arg_lines = -1;
390 optind++;
391 } else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) {
392 arg_lines = n;
393 optind++;
394 }
395 }
396 }
397
398 break;
399
400 case ARG_NO_TAIL:
401 arg_no_tail = true;
402 break;
403
404 case ARG_NEW_ID128:
405 arg_action = ACTION_NEW_ID128;
406 break;
407
408 case 'q':
409 arg_quiet = true;
410 break;
411
412 case 'm':
413 arg_merge = true;
414 break;
415
416 case 'b':
417 arg_boot = true;
418
419 if (optarg) {
420 r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
421 if (r < 0) {
422 log_error("Failed to parse boot descriptor '%s'", optarg);
423 return -EINVAL;
424 }
425 } else {
426
427 /* Hmm, no argument? Maybe the next
428 * word on the command line is
429 * supposed to be the argument? Let's
430 * see if there is one and is parsable
431 * as a boot descriptor... */
432
433 if (optind < argc &&
434 parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0)
435 optind++;
436 }
437
438 break;
439
440 case ARG_LIST_BOOTS:
441 arg_action = ACTION_LIST_BOOTS;
442 break;
443
444 case 'k':
445 arg_boot = arg_dmesg = true;
446 break;
447
448 case ARG_SYSTEM:
449 arg_journal_type |= SD_JOURNAL_SYSTEM;
450 break;
451
452 case ARG_USER:
453 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
454 break;
455
456 case 'M':
457 arg_machine = optarg;
458 break;
459
460 case 'D':
461 arg_directory = optarg;
462 break;
463
464 case ARG_FILE:
465 r = glob_extend(&arg_file, optarg);
466 if (r < 0) {
467 log_error("Failed to add paths: %s", strerror(-r));
468 return r;
469 };
470 break;
471
472 case ARG_ROOT:
473 arg_root = optarg;
474 break;
475
476 case 'c':
477 arg_cursor = optarg;
478 break;
479
480 case ARG_AFTER_CURSOR:
481 arg_after_cursor = optarg;
482 break;
483
484 case ARG_SHOW_CURSOR:
485 arg_show_cursor = true;
486 break;
487
488 case ARG_HEADER:
489 arg_action = ACTION_PRINT_HEADER;
490 break;
491
492 case ARG_VERIFY:
493 arg_action = ACTION_VERIFY;
494 break;
495
496 case ARG_DISK_USAGE:
497 arg_action = ACTION_DISK_USAGE;
498 break;
499
500 #ifdef HAVE_GCRYPT
501 case ARG_FORCE:
502 arg_force = true;
503 break;
504
505 case ARG_SETUP_KEYS:
506 arg_action = ACTION_SETUP_KEYS;
507 break;
508
509
510 case ARG_VERIFY_KEY:
511 arg_action = ACTION_VERIFY;
512 arg_verify_key = optarg;
513 arg_merge = false;
514 break;
515
516 case ARG_INTERVAL:
517 r = parse_sec(optarg, &arg_interval);
518 if (r < 0 || arg_interval <= 0) {
519 log_error("Failed to parse sealing key change interval: %s", optarg);
520 return -EINVAL;
521 }
522 break;
523 #else
524 case ARG_SETUP_KEYS:
525 case ARG_VERIFY_KEY:
526 case ARG_INTERVAL:
527 case ARG_FORCE:
528 log_error("Forward-secure sealing not available.");
529 return -ENOTSUP;
530 #endif
531
532 case 'p': {
533 const char *dots;
534
535 dots = strstr(optarg, "..");
536 if (dots) {
537 char *a;
538 int from, to, i;
539
540 /* a range */
541 a = strndup(optarg, dots - optarg);
542 if (!a)
543 return log_oom();
544
545 from = log_level_from_string(a);
546 to = log_level_from_string(dots + 2);
547 free(a);
548
549 if (from < 0 || to < 0) {
550 log_error("Failed to parse log level range %s", optarg);
551 return -EINVAL;
552 }
553
554 arg_priorities = 0;
555
556 if (from < to) {
557 for (i = from; i <= to; i++)
558 arg_priorities |= 1 << i;
559 } else {
560 for (i = to; i <= from; i++)
561 arg_priorities |= 1 << i;
562 }
563
564 } else {
565 int p, i;
566
567 p = log_level_from_string(optarg);
568 if (p < 0) {
569 log_error("Unknown log level %s", optarg);
570 return -EINVAL;
571 }
572
573 arg_priorities = 0;
574
575 for (i = 0; i <= p; i++)
576 arg_priorities |= 1 << i;
577 }
578
579 break;
580 }
581
582 case ARG_SINCE:
583 r = parse_timestamp(optarg, &arg_since);
584 if (r < 0) {
585 log_error("Failed to parse timestamp: %s", optarg);
586 return -EINVAL;
587 }
588 arg_since_set = true;
589 break;
590
591 case ARG_UNTIL:
592 r = parse_timestamp(optarg, &arg_until);
593 if (r < 0) {
594 log_error("Failed to parse timestamp: %s", optarg);
595 return -EINVAL;
596 }
597 arg_until_set = true;
598 break;
599
600 case 't':
601 r = strv_extend(&arg_syslog_identifier, optarg);
602 if (r < 0)
603 return log_oom();
604 break;
605
606 case 'u':
607 r = strv_extend(&arg_system_units, optarg);
608 if (r < 0)
609 return log_oom();
610 break;
611
612 case ARG_USER_UNIT:
613 r = strv_extend(&arg_user_units, optarg);
614 if (r < 0)
615 return log_oom();
616 break;
617
618 case 'F':
619 arg_field = optarg;
620 break;
621
622 case 'x':
623 arg_catalog = true;
624 break;
625
626 case ARG_LIST_CATALOG:
627 arg_action = ACTION_LIST_CATALOG;
628 break;
629
630 case ARG_DUMP_CATALOG:
631 arg_action = ACTION_DUMP_CATALOG;
632 break;
633
634 case ARG_UPDATE_CATALOG:
635 arg_action = ACTION_UPDATE_CATALOG;
636 break;
637
638 case 'r':
639 arg_reverse = true;
640 break;
641
642 case '?':
643 return -EINVAL;
644
645 default:
646 assert_not_reached("Unhandled option");
647 }
648
649 if (arg_follow && !arg_no_tail && arg_lines < -1)
650 arg_lines = 10;
651
652 if (!!arg_directory + !!arg_file + !!arg_machine > 1) {
653 log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one.");
654 return -EINVAL;
655 }
656
657 if (arg_since_set && arg_until_set && arg_since > arg_until) {
658 log_error("--since= must be before --until=.");
659 return -EINVAL;
660 }
661
662 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
663 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
664 return -EINVAL;
665 }
666
667 if (arg_follow && arg_reverse) {
668 log_error("Please specify either --reverse= or --follow=, not both.");
669 return -EINVAL;
670 }
671
672 if (arg_action != ACTION_SHOW && optind < argc) {
673 log_error("Extraneous arguments starting with '%s'", argv[optind]);
674 return -EINVAL;
675 }
676
677 return 1;
678 }
679
680 static int generate_new_id128(void) {
681 sd_id128_t id;
682 int r;
683 unsigned i;
684
685 r = sd_id128_randomize(&id);
686 if (r < 0) {
687 log_error("Failed to generate ID: %s", strerror(-r));
688 return r;
689 }
690
691 printf("As string:\n"
692 SD_ID128_FORMAT_STR "\n\n"
693 "As UUID:\n"
694 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
695 "As macro:\n"
696 "#define MESSAGE_XYZ SD_ID128_MAKE(",
697 SD_ID128_FORMAT_VAL(id),
698 SD_ID128_FORMAT_VAL(id));
699 for (i = 0; i < 16; i++)
700 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
701 fputs(")\n\n", stdout);
702
703 printf("As Python constant:\n"
704 ">>> import uuid\n"
705 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
706 SD_ID128_FORMAT_VAL(id));
707
708 return 0;
709 }
710
711 static int add_matches(sd_journal *j, char **args) {
712 char **i;
713 bool have_term = false;
714
715 assert(j);
716
717 STRV_FOREACH(i, args) {
718 int r;
719
720 if (streq(*i, "+")) {
721 if (!have_term)
722 break;
723 r = sd_journal_add_disjunction(j);
724 have_term = false;
725
726 } else if (path_is_absolute(*i)) {
727 _cleanup_free_ char *p, *t = NULL, *t2 = NULL;
728 const char *path;
729 _cleanup_free_ char *interpreter = NULL;
730 struct stat st;
731
732 p = canonicalize_file_name(*i);
733 path = p ? p : *i;
734
735 if (stat(path, &st) < 0) {
736 log_error("Couldn't stat file: %m");
737 return -errno;
738 }
739
740 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
741 if (executable_is_script(path, &interpreter) > 0) {
742 _cleanup_free_ char *comm;
743
744 comm = strndup(basename(path), 15);
745 if (!comm)
746 return log_oom();
747
748 t = strappend("_COMM=", comm);
749
750 /* Append _EXE only if the interpreter is not a link.
751 Otherwise, it might be outdated often. */
752 if (lstat(interpreter, &st) == 0 &&
753 !S_ISLNK(st.st_mode)) {
754 t2 = strappend("_EXE=", interpreter);
755 if (!t2)
756 return log_oom();
757 }
758 } else
759 t = strappend("_EXE=", path);
760 } else if (S_ISCHR(st.st_mode)) {
761 if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u",
762 major(st.st_rdev),
763 minor(st.st_rdev)) < 0)
764 return -ENOMEM;
765 } else if (S_ISBLK(st.st_mode)) {
766 if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u",
767 major(st.st_rdev),
768 minor(st.st_rdev)) < 0)
769 return -ENOMEM;
770 } else {
771 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
772 return -EINVAL;
773 }
774
775 if (!t)
776 return log_oom();
777
778 r = sd_journal_add_match(j, t, 0);
779 if (t2)
780 r = sd_journal_add_match(j, t2, 0);
781 have_term = true;
782
783 } else {
784 r = sd_journal_add_match(j, *i, 0);
785 have_term = true;
786 }
787
788 if (r < 0) {
789 log_error("Failed to add match '%s': %s", *i, strerror(-r));
790 return r;
791 }
792 }
793
794 if (!strv_isempty(args) && !have_term) {
795 log_error("\"+\" can only be used between terms");
796 return -EINVAL;
797 }
798
799 return 0;
800 }
801
802 static int boot_id_cmp(const void *a, const void *b) {
803 uint64_t _a, _b;
804
805 _a = ((const boot_id_t *)a)->first;
806 _b = ((const boot_id_t *)b)->first;
807
808 return _a < _b ? -1 : (_a > _b ? 1 : 0);
809 }
810
811 static int list_boots(sd_journal *j) {
812 int r;
813 const void *data;
814 unsigned int count = 0;
815 int w, i;
816 size_t length, allocated = 0;
817 boot_id_t *id;
818 _cleanup_free_ boot_id_t *all_ids = NULL;
819
820 r = sd_journal_query_unique(j, "_BOOT_ID");
821 if (r < 0)
822 return r;
823
824 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
825 if (length < strlen("_BOOT_ID="))
826 continue;
827
828 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
829 return log_oom();
830
831 id = &all_ids[count];
832
833 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
834 if (r < 0)
835 continue;
836
837 r = sd_journal_add_match(j, data, length);
838 if (r < 0)
839 return r;
840
841 r = sd_journal_seek_head(j);
842 if (r < 0)
843 return r;
844
845 r = sd_journal_next(j);
846 if (r < 0)
847 return r;
848 else if (r == 0)
849 goto flush;
850
851 r = sd_journal_get_realtime_usec(j, &id->first);
852 if (r < 0)
853 return r;
854
855 r = sd_journal_seek_tail(j);
856 if (r < 0)
857 return r;
858
859 r = sd_journal_previous(j);
860 if (r < 0)
861 return r;
862 else if (r == 0)
863 goto flush;
864
865 r = sd_journal_get_realtime_usec(j, &id->last);
866 if (r < 0)
867 return r;
868
869 count++;
870 flush:
871 sd_journal_flush_matches(j);
872 }
873
874 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
875
876 /* numbers are one less, but we need an extra char for the sign */
877 w = DECIMAL_STR_WIDTH(count - 1) + 1;
878
879 for (id = all_ids, i = 0; id < all_ids + count; id++, i++) {
880 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
881
882 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
883 w, i - count + 1,
884 SD_ID128_FORMAT_VAL(id->id),
885 format_timestamp(a, sizeof(a), id->first),
886 format_timestamp(b, sizeof(b), id->last));
887 }
888
889 return 0;
890 }
891
892 static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
893 int r;
894 const void *data;
895 unsigned int count = 0;
896 size_t length, allocated = 0;
897 boot_id_t ref_boot_id = {SD_ID128_NULL}, *id;
898 _cleanup_free_ boot_id_t *all_ids = NULL;
899
900 assert(j);
901 assert(boot_id);
902
903 r = sd_journal_query_unique(j, "_BOOT_ID");
904 if (r < 0)
905 return r;
906
907 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
908 if (length < strlen("_BOOT_ID="))
909 continue;
910
911 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
912 return log_oom();
913
914 id = &all_ids[count];
915
916 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
917 if (r < 0)
918 continue;
919
920 r = sd_journal_add_match(j, data, length);
921 if (r < 0)
922 return r;
923
924 r = sd_journal_seek_head(j);
925 if (r < 0)
926 return r;
927
928 r = sd_journal_next(j);
929 if (r < 0)
930 return r;
931 else if (r == 0)
932 goto flush;
933
934 r = sd_journal_get_realtime_usec(j, &id->first);
935 if (r < 0)
936 return r;
937
938 if (sd_id128_equal(id->id, *boot_id))
939 ref_boot_id = *id;
940
941 count++;
942 flush:
943 sd_journal_flush_matches(j);
944 }
945
946 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
947
948 if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
949 if (relative > (int) count || relative <= -(int)count)
950 return -EADDRNOTAVAIL;
951
952 *boot_id = all_ids[(relative <= 0)*count + relative - 1].id;
953 } else {
954 id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp);
955
956 if (!id ||
957 relative <= 0 ? (id - all_ids) + relative < 0 :
958 (id - all_ids) + relative >= (int) count)
959 return -EADDRNOTAVAIL;
960
961 *boot_id = (id + relative)->id;
962 }
963
964 return 0;
965 }
966
967 static int add_boot(sd_journal *j) {
968 char match[9+32+1] = "_BOOT_ID=";
969 int r;
970
971 assert(j);
972
973 if (!arg_boot)
974 return 0;
975
976 if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
977 return add_match_this_boot(j, arg_machine);
978
979 r = get_relative_boot_id(j, &arg_boot_id, arg_boot_offset);
980 if (r < 0) {
981 if (sd_id128_equal(arg_boot_id, SD_ID128_NULL))
982 log_error("Failed to look up boot %+i: %s", arg_boot_offset, strerror(-r));
983 else
984 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
985 SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r));
986 return r;
987 }
988
989 sd_id128_to_string(arg_boot_id, match + 9);
990
991 r = sd_journal_add_match(j, match, sizeof(match) - 1);
992 if (r < 0) {
993 log_error("Failed to add match: %s", strerror(-r));
994 return r;
995 }
996
997 r = sd_journal_add_conjunction(j);
998 if (r < 0)
999 return r;
1000
1001 return 0;
1002 }
1003
1004 static int add_dmesg(sd_journal *j) {
1005 int r;
1006 assert(j);
1007
1008 if (!arg_dmesg)
1009 return 0;
1010
1011 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
1012 if (r < 0) {
1013 log_error("Failed to add match: %s", strerror(-r));
1014 return r;
1015 }
1016
1017 r = sd_journal_add_conjunction(j);
1018 if (r < 0)
1019 return r;
1020
1021 return 0;
1022 }
1023
1024 static int get_possible_units(sd_journal *j,
1025 const char *fields,
1026 char **patterns,
1027 Set **units) {
1028 _cleanup_set_free_free_ Set *found;
1029 const char *field;
1030 int r;
1031
1032 found = set_new(&string_hash_ops);
1033 if (!found)
1034 return log_oom();
1035
1036 NULSTR_FOREACH(field, fields) {
1037 const void *data;
1038 size_t size;
1039
1040 r = sd_journal_query_unique(j, field);
1041 if (r < 0)
1042 return r;
1043
1044 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1045 char **pattern, *eq;
1046 size_t prefix;
1047 _cleanup_free_ char *u = NULL;
1048
1049 eq = memchr(data, '=', size);
1050 if (eq)
1051 prefix = eq - (char*) data + 1;
1052 else
1053 prefix = 0;
1054
1055 u = strndup((char*) data + prefix, size - prefix);
1056 if (!u)
1057 return log_oom();
1058
1059 STRV_FOREACH(pattern, patterns)
1060 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1061 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1062
1063 r = set_consume(found, u);
1064 u = NULL;
1065 if (r < 0 && r != -EEXIST)
1066 return r;
1067
1068 break;
1069 }
1070 }
1071 }
1072
1073 *units = found;
1074 found = NULL;
1075 return 0;
1076 }
1077
1078 /* This list is supposed to return the superset of unit names
1079 * possibly matched by rules added with add_matches_for_unit... */
1080 #define SYSTEM_UNITS \
1081 "_SYSTEMD_UNIT\0" \
1082 "COREDUMP_UNIT\0" \
1083 "UNIT\0" \
1084 "OBJECT_SYSTEMD_UNIT\0" \
1085 "_SYSTEMD_SLICE\0"
1086
1087 /* ... and add_matches_for_user_unit */
1088 #define USER_UNITS \
1089 "_SYSTEMD_USER_UNIT\0" \
1090 "USER_UNIT\0" \
1091 "COREDUMP_USER_UNIT\0" \
1092 "OBJECT_SYSTEMD_USER_UNIT\0"
1093
1094 static int add_units(sd_journal *j) {
1095 _cleanup_strv_free_ char **patterns = NULL;
1096 int r, count = 0;
1097 char **i;
1098
1099 assert(j);
1100
1101 STRV_FOREACH(i, arg_system_units) {
1102 _cleanup_free_ char *u = NULL;
1103
1104 u = unit_name_mangle(*i, MANGLE_GLOB);
1105 if (!u)
1106 return log_oom();
1107
1108 if (string_is_glob(u)) {
1109 r = strv_push(&patterns, u);
1110 if (r < 0)
1111 return r;
1112 u = NULL;
1113 } else {
1114 r = add_matches_for_unit(j, u);
1115 if (r < 0)
1116 return r;
1117 r = sd_journal_add_disjunction(j);
1118 if (r < 0)
1119 return r;
1120 count ++;
1121 }
1122 }
1123
1124 if (!strv_isempty(patterns)) {
1125 _cleanup_set_free_free_ Set *units = NULL;
1126 Iterator it;
1127 char *u;
1128
1129 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
1130 if (r < 0)
1131 return r;
1132
1133 SET_FOREACH(u, units, it) {
1134 r = add_matches_for_unit(j, u);
1135 if (r < 0)
1136 return r;
1137 r = sd_journal_add_disjunction(j);
1138 if (r < 0)
1139 return r;
1140 count ++;
1141 }
1142 }
1143
1144 strv_free(patterns);
1145 patterns = NULL;
1146
1147 STRV_FOREACH(i, arg_user_units) {
1148 _cleanup_free_ char *u = NULL;
1149
1150 u = unit_name_mangle(*i, MANGLE_GLOB);
1151 if (!u)
1152 return log_oom();
1153
1154 if (string_is_glob(u)) {
1155 r = strv_push(&patterns, u);
1156 if (r < 0)
1157 return r;
1158 u = NULL;
1159 } else {
1160 r = add_matches_for_user_unit(j, u, getuid());
1161 if (r < 0)
1162 return r;
1163 r = sd_journal_add_disjunction(j);
1164 if (r < 0)
1165 return r;
1166 count ++;
1167 }
1168 }
1169
1170 if (!strv_isempty(patterns)) {
1171 _cleanup_set_free_free_ Set *units = NULL;
1172 Iterator it;
1173 char *u;
1174
1175 r = get_possible_units(j, USER_UNITS, patterns, &units);
1176 if (r < 0)
1177 return r;
1178
1179 SET_FOREACH(u, units, it) {
1180 r = add_matches_for_user_unit(j, u, getuid());
1181 if (r < 0)
1182 return r;
1183 r = sd_journal_add_disjunction(j);
1184 if (r < 0)
1185 return r;
1186 count ++;
1187 }
1188 }
1189
1190 /* Complain if the user request matches but nothing whatsoever was
1191 * found, since otherwise everything would be matched. */
1192 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1193 return -ENODATA;
1194
1195 r = sd_journal_add_conjunction(j);
1196 if (r < 0)
1197 return r;
1198
1199 return 0;
1200 }
1201
1202 static int add_priorities(sd_journal *j) {
1203 char match[] = "PRIORITY=0";
1204 int i, r;
1205 assert(j);
1206
1207 if (arg_priorities == 0xFF)
1208 return 0;
1209
1210 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1211 if (arg_priorities & (1 << i)) {
1212 match[sizeof(match)-2] = '0' + i;
1213
1214 r = sd_journal_add_match(j, match, strlen(match));
1215 if (r < 0) {
1216 log_error("Failed to add match: %s", strerror(-r));
1217 return r;
1218 }
1219 }
1220
1221 r = sd_journal_add_conjunction(j);
1222 if (r < 0)
1223 return r;
1224
1225 return 0;
1226 }
1227
1228
1229 static int add_syslog_identifier(sd_journal *j) {
1230 int r;
1231 char **i;
1232
1233 assert(j);
1234
1235 STRV_FOREACH(i, arg_syslog_identifier) {
1236 char *u;
1237
1238 u = strappenda("SYSLOG_IDENTIFIER=", *i);
1239 r = sd_journal_add_match(j, u, 0);
1240 if (r < 0)
1241 return r;
1242 r = sd_journal_add_disjunction(j);
1243 if (r < 0)
1244 return r;
1245 }
1246
1247 r = sd_journal_add_conjunction(j);
1248 if (r < 0)
1249 return r;
1250
1251 return 0;
1252 }
1253
1254 static int setup_keys(void) {
1255 #ifdef HAVE_GCRYPT
1256 size_t mpk_size, seed_size, state_size, i;
1257 uint8_t *mpk, *seed, *state;
1258 ssize_t l;
1259 int fd = -1, r, attr = 0;
1260 sd_id128_t machine, boot;
1261 char *p = NULL, *k = NULL;
1262 struct FSSHeader h;
1263 uint64_t n;
1264 struct stat st;
1265
1266 r = stat("/var/log/journal", &st);
1267 if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
1268 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
1269 return -errno;
1270 }
1271
1272 if (r < 0 || !S_ISDIR(st.st_mode)) {
1273 log_error("%s is not a directory, must be using persistent logging for FSS.",
1274 "/var/log/journal");
1275 return r < 0 ? -errno : -ENOTDIR;
1276 }
1277
1278 r = sd_id128_get_machine(&machine);
1279 if (r < 0) {
1280 log_error("Failed to get machine ID: %s", strerror(-r));
1281 return r;
1282 }
1283
1284 r = sd_id128_get_boot(&boot);
1285 if (r < 0) {
1286 log_error("Failed to get boot ID: %s", strerror(-r));
1287 return r;
1288 }
1289
1290 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
1291 SD_ID128_FORMAT_VAL(machine)) < 0)
1292 return log_oom();
1293
1294 if (access(p, F_OK) >= 0) {
1295 if (arg_force) {
1296 r = unlink(p);
1297 if (r < 0) {
1298 log_error("unlink(\"%s\") failed: %m", p);
1299 r = -errno;
1300 goto finish;
1301 }
1302 } else {
1303 log_error("Sealing key file %s exists already. (--force to recreate)", p);
1304 r = -EEXIST;
1305 goto finish;
1306 }
1307 }
1308
1309 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
1310 SD_ID128_FORMAT_VAL(machine)) < 0) {
1311 r = log_oom();
1312 goto finish;
1313 }
1314
1315 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1316 mpk = alloca(mpk_size);
1317
1318 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1319 seed = alloca(seed_size);
1320
1321 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1322 state = alloca(state_size);
1323
1324 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1325 if (fd < 0) {
1326 log_error("Failed to open /dev/random: %m");
1327 r = -errno;
1328 goto finish;
1329 }
1330
1331 log_info("Generating seed...");
1332 l = loop_read(fd, seed, seed_size, true);
1333 if (l < 0 || (size_t) l != seed_size) {
1334 log_error("Failed to read random seed: %s", strerror(EIO));
1335 r = -EIO;
1336 goto finish;
1337 }
1338
1339 log_info("Generating key pair...");
1340 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1341
1342 log_info("Generating sealing key...");
1343 FSPRG_GenState0(state, mpk, seed, seed_size);
1344
1345 assert(arg_interval > 0);
1346
1347 n = now(CLOCK_REALTIME);
1348 n /= arg_interval;
1349
1350 safe_close(fd);
1351 fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
1352 if (fd < 0) {
1353 log_error("Failed to open %s: %m", k);
1354 r = -errno;
1355 goto finish;
1356 }
1357
1358 /* Enable secure remove, exclusion from dump, synchronous
1359 * writing and in-place updating */
1360 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
1361 log_warning("FS_IOC_GETFLAGS failed: %m");
1362
1363 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
1364
1365 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
1366 log_warning("FS_IOC_SETFLAGS failed: %m");
1367
1368 zero(h);
1369 memcpy(h.signature, "KSHHRHLP", 8);
1370 h.machine_id = machine;
1371 h.boot_id = boot;
1372 h.header_size = htole64(sizeof(h));
1373 h.start_usec = htole64(n * arg_interval);
1374 h.interval_usec = htole64(arg_interval);
1375 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1376 h.fsprg_state_size = htole64(state_size);
1377
1378 l = loop_write(fd, &h, sizeof(h), false);
1379 if (l < 0 || (size_t) l != sizeof(h)) {
1380 log_error("Failed to write header: %s", strerror(EIO));
1381 r = -EIO;
1382 goto finish;
1383 }
1384
1385 l = loop_write(fd, state, state_size, false);
1386 if (l < 0 || (size_t) l != state_size) {
1387 log_error("Failed to write state: %s", strerror(EIO));
1388 r = -EIO;
1389 goto finish;
1390 }
1391
1392 if (link(k, p) < 0) {
1393 log_error("Failed to link file: %m");
1394 r = -errno;
1395 goto finish;
1396 }
1397
1398 if (on_tty()) {
1399 fprintf(stderr,
1400 "\n"
1401 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
1402 "the following local file. This key file is automatically updated when the\n"
1403 "sealing key is advanced. It should not be used on multiple hosts.\n"
1404 "\n"
1405 "\t%s\n"
1406 "\n"
1407 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1408 "at a safe location and should not be saved locally on disk.\n"
1409 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1410 fflush(stderr);
1411 }
1412 for (i = 0; i < seed_size; i++) {
1413 if (i > 0 && i % 3 == 0)
1414 putchar('-');
1415 printf("%02x", ((uint8_t*) seed)[i]);
1416 }
1417
1418 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1419
1420 if (on_tty()) {
1421 char tsb[FORMAT_TIMESPAN_MAX], *hn;
1422
1423 fprintf(stderr,
1424 ANSI_HIGHLIGHT_OFF "\n"
1425 "The sealing key is automatically changed every %s.\n",
1426 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
1427
1428 hn = gethostname_malloc();
1429
1430 if (hn) {
1431 hostname_cleanup(hn, false);
1432 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
1433 } else
1434 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
1435
1436 #ifdef HAVE_QRENCODE
1437 /* If this is not an UTF-8 system don't print any QR codes */
1438 if (is_locale_utf8()) {
1439 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1440 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1441 }
1442 #endif
1443 free(hn);
1444 }
1445
1446 r = 0;
1447
1448 finish:
1449 safe_close(fd);
1450
1451 if (k) {
1452 unlink(k);
1453 free(k);
1454 }
1455
1456 free(p);
1457
1458 return r;
1459 #else
1460 log_error("Forward-secure sealing not available.");
1461 return -ENOTSUP;
1462 #endif
1463 }
1464
1465 static int verify(sd_journal *j) {
1466 int r = 0;
1467 Iterator i;
1468 JournalFile *f;
1469
1470 assert(j);
1471
1472 log_show_color(true);
1473
1474 HASHMAP_FOREACH(f, j->files, i) {
1475 int k;
1476 usec_t first, validated, last;
1477
1478 #ifdef HAVE_GCRYPT
1479 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
1480 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
1481 #endif
1482
1483 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
1484 if (k == -EINVAL) {
1485 /* If the key was invalid give up right-away. */
1486 return k;
1487 } else if (k < 0) {
1488 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
1489 r = k;
1490 } else {
1491 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
1492 log_info("PASS: %s", f->path);
1493
1494 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
1495 if (validated > 0) {
1496 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1497 format_timestamp(a, sizeof(a), first),
1498 format_timestamp(b, sizeof(b), validated),
1499 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
1500 } else if (last > 0)
1501 log_info("=> No sealing yet, %s of entries not sealed.",
1502 format_timespan(c, sizeof(c), last - first, 0));
1503 else
1504 log_info("=> No sealing yet, no entries in file.");
1505 }
1506 }
1507 }
1508
1509 return r;
1510 }
1511
1512 #ifdef HAVE_ACL
1513 static int access_check_var_log_journal(sd_journal *j) {
1514 _cleanup_strv_free_ char **g = NULL;
1515 bool have_access;
1516 int r;
1517
1518 assert(j);
1519
1520 have_access = in_group("systemd-journal") > 0;
1521
1522 if (!have_access) {
1523 /* Let's enumerate all groups from the default ACL of
1524 * the directory, which generally should allow access
1525 * to most journal files too */
1526 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
1527 if (r < 0)
1528 return r;
1529 }
1530
1531 if (!have_access) {
1532
1533 if (strv_isempty(g))
1534 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1535 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1536 " turn off this notice.");
1537 else {
1538 _cleanup_free_ char *s = NULL;
1539
1540 r = strv_extend(&g, "systemd-journal");
1541 if (r < 0)
1542 return log_oom();
1543
1544 strv_sort(g);
1545 strv_uniq(g);
1546
1547 s = strv_join(g, "', '");
1548 if (!s)
1549 return log_oom();
1550
1551 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1552 " Users in the groups '%s' can see all messages.\n"
1553 " Pass -q to turn off this notice.", s);
1554 }
1555 }
1556
1557 return 0;
1558 }
1559 #endif
1560
1561 static int access_check(sd_journal *j) {
1562 Iterator it;
1563 void *code;
1564 int r = 0;
1565
1566 assert(j);
1567
1568 if (set_isempty(j->errors)) {
1569 if (hashmap_isempty(j->files))
1570 log_notice("No journal files were found.");
1571 return 0;
1572 }
1573
1574 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
1575 #ifdef HAVE_ACL
1576 /* If /var/log/journal doesn't even exist,
1577 * unprivileged users have no access at all */
1578 if (access("/var/log/journal", F_OK) < 0 &&
1579 geteuid() != 0 &&
1580 in_group("systemd-journal") <= 0) {
1581 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1582 "enabled. Users in the 'systemd-journal' group may always access messages.");
1583 return -EACCES;
1584 }
1585
1586 /* If /var/log/journal exists, try to pring a nice
1587 notice if the user lacks access to it */
1588 if (!arg_quiet && geteuid() != 0) {
1589 r = access_check_var_log_journal(j);
1590 if (r < 0)
1591 return r;
1592 }
1593 #else
1594 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1595 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1596 "group may access messages.");
1597 return -EACCES;
1598 }
1599 #endif
1600
1601 if (hashmap_isempty(j->files)) {
1602 log_error("No journal files were opened due to insufficient permissions.");
1603 r = -EACCES;
1604 }
1605 }
1606
1607 SET_FOREACH(code, j->errors, it) {
1608 int err;
1609
1610 err = -PTR_TO_INT(code);
1611 assert(err > 0);
1612
1613 if (err != EACCES)
1614 log_warning("Error was encountered while opening journal files: %s",
1615 strerror(err));
1616 }
1617
1618 return r;
1619 }
1620
1621 int main(int argc, char *argv[]) {
1622 int r;
1623 _cleanup_journal_close_ sd_journal *j = NULL;
1624 bool need_seek = false;
1625 sd_id128_t previous_boot_id;
1626 bool previous_boot_id_valid = false, first_line = true;
1627 int n_shown = 0;
1628 bool ellipsized = false;
1629
1630 setlocale(LC_ALL, "");
1631 log_parse_environment();
1632 log_open();
1633
1634 r = parse_argv(argc, argv);
1635 if (r <= 0)
1636 goto finish;
1637
1638 signal(SIGWINCH, columns_lines_cache_reset);
1639
1640 if (arg_action == ACTION_NEW_ID128) {
1641 r = generate_new_id128();
1642 goto finish;
1643 }
1644
1645 if (arg_action == ACTION_SETUP_KEYS) {
1646 r = setup_keys();
1647 goto finish;
1648 }
1649
1650 if (arg_action == ACTION_UPDATE_CATALOG ||
1651 arg_action == ACTION_LIST_CATALOG ||
1652 arg_action == ACTION_DUMP_CATALOG) {
1653
1654 _cleanup_free_ char *database;
1655
1656 database = path_join(arg_root, CATALOG_DATABASE, NULL);
1657 if (!database) {
1658 r = log_oom();
1659 goto finish;
1660 }
1661
1662 if (arg_action == ACTION_UPDATE_CATALOG) {
1663 r = catalog_update(database, arg_root, catalog_file_dirs);
1664 if (r < 0)
1665 log_error("Failed to list catalog: %s", strerror(-r));
1666 } else {
1667 bool oneline = arg_action == ACTION_LIST_CATALOG;
1668
1669 if (optind < argc)
1670 r = catalog_list_items(stdout, database,
1671 oneline, argv + optind);
1672 else
1673 r = catalog_list(stdout, database, oneline);
1674 if (r < 0)
1675 log_error("Failed to list catalog: %s", strerror(-r));
1676 }
1677
1678 goto finish;
1679 }
1680
1681 if (arg_directory)
1682 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
1683 else if (arg_file)
1684 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
1685 else if (arg_machine)
1686 r = sd_journal_open_container(&j, arg_machine, 0);
1687 else
1688 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
1689 if (r < 0) {
1690 log_error("Failed to open %s: %s",
1691 arg_directory ? arg_directory : arg_file ? "files" : "journal",
1692 strerror(-r));
1693 return EXIT_FAILURE;
1694 }
1695
1696 r = access_check(j);
1697 if (r < 0)
1698 return EXIT_FAILURE;
1699
1700 if (arg_action == ACTION_VERIFY) {
1701 r = verify(j);
1702 goto finish;
1703 }
1704
1705 if (arg_action == ACTION_PRINT_HEADER) {
1706 journal_print_header(j);
1707 return EXIT_SUCCESS;
1708 }
1709
1710 if (arg_action == ACTION_DISK_USAGE) {
1711 uint64_t bytes = 0;
1712 char sbytes[FORMAT_BYTES_MAX];
1713
1714 r = sd_journal_get_usage(j, &bytes);
1715 if (r < 0)
1716 return EXIT_FAILURE;
1717
1718 printf("Journals take up %s on disk.\n",
1719 format_bytes(sbytes, sizeof(sbytes), bytes));
1720 return EXIT_SUCCESS;
1721 }
1722
1723 if (arg_action == ACTION_LIST_BOOTS) {
1724 r = list_boots(j);
1725 goto finish;
1726 }
1727
1728 /* add_boot() must be called first!
1729 * It may need to seek the journal to find parent boot IDs. */
1730 r = add_boot(j);
1731 if (r < 0)
1732 return EXIT_FAILURE;
1733
1734 r = add_dmesg(j);
1735 if (r < 0)
1736 return EXIT_FAILURE;
1737
1738 r = add_units(j);
1739 strv_free(arg_system_units);
1740 strv_free(arg_user_units);
1741
1742 if (r < 0) {
1743 log_error("Failed to add filter for units: %s", strerror(-r));
1744 return EXIT_FAILURE;
1745 }
1746
1747 r = add_syslog_identifier(j);
1748 if (r < 0) {
1749 log_error("Failed to add filter for syslog identifiers: %s", strerror(-r));
1750 return EXIT_FAILURE;
1751 }
1752
1753 r = add_priorities(j);
1754 if (r < 0) {
1755 log_error("Failed to add filter for priorities: %s", strerror(-r));
1756 return EXIT_FAILURE;
1757 }
1758
1759 r = add_matches(j, argv + optind);
1760 if (r < 0) {
1761 log_error("Failed to add filters: %s", strerror(-r));
1762 return EXIT_FAILURE;
1763 }
1764
1765 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1766 _cleanup_free_ char *filter;
1767
1768 filter = journal_make_match_string(j);
1769 log_debug("Journal filter: %s", filter);
1770 }
1771
1772 if (arg_field) {
1773 const void *data;
1774 size_t size;
1775
1776 r = sd_journal_set_data_threshold(j, 0);
1777 if (r < 0) {
1778 log_error("Failed to unset data size threshold");
1779 return EXIT_FAILURE;
1780 }
1781
1782 r = sd_journal_query_unique(j, arg_field);
1783 if (r < 0) {
1784 log_error("Failed to query unique data objects: %s", strerror(-r));
1785 return EXIT_FAILURE;
1786 }
1787
1788 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1789 const void *eq;
1790
1791 if (arg_lines >= 0 && n_shown >= arg_lines)
1792 break;
1793
1794 eq = memchr(data, '=', size);
1795 if (eq)
1796 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1797 else
1798 printf("%.*s\n", (int) size, (const char*) data);
1799
1800 n_shown ++;
1801 }
1802
1803 return EXIT_SUCCESS;
1804 }
1805
1806 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1807 if (arg_follow) {
1808 r = sd_journal_get_fd(j);
1809 if (r < 0)
1810 return EXIT_FAILURE;
1811 }
1812
1813 if (arg_cursor || arg_after_cursor) {
1814 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
1815 if (r < 0) {
1816 log_error("Failed to seek to cursor: %s", strerror(-r));
1817 return EXIT_FAILURE;
1818 }
1819 if (!arg_reverse)
1820 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
1821 else
1822 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
1823
1824 if (arg_after_cursor && r < 2 && !arg_follow)
1825 /* We couldn't find the next entry after the cursor. */
1826 arg_lines = 0;
1827
1828 } else if (arg_since_set && !arg_reverse) {
1829 r = sd_journal_seek_realtime_usec(j, arg_since);
1830 if (r < 0) {
1831 log_error("Failed to seek to date: %s", strerror(-r));
1832 return EXIT_FAILURE;
1833 }
1834 r = sd_journal_next(j);
1835
1836 } else if (arg_until_set && arg_reverse) {
1837 r = sd_journal_seek_realtime_usec(j, arg_until);
1838 if (r < 0) {
1839 log_error("Failed to seek to date: %s", strerror(-r));
1840 return EXIT_FAILURE;
1841 }
1842 r = sd_journal_previous(j);
1843
1844 } else if (arg_lines >= 0) {
1845 r = sd_journal_seek_tail(j);
1846 if (r < 0) {
1847 log_error("Failed to seek to tail: %s", strerror(-r));
1848 return EXIT_FAILURE;
1849 }
1850
1851 r = sd_journal_previous_skip(j, arg_lines);
1852
1853 } else if (arg_reverse) {
1854 r = sd_journal_seek_tail(j);
1855 if (r < 0) {
1856 log_error("Failed to seek to tail: %s", strerror(-r));
1857 return EXIT_FAILURE;
1858 }
1859
1860 r = sd_journal_previous(j);
1861
1862 } else {
1863 r = sd_journal_seek_head(j);
1864 if (r < 0) {
1865 log_error("Failed to seek to head: %s", strerror(-r));
1866 return EXIT_FAILURE;
1867 }
1868
1869 r = sd_journal_next(j);
1870 }
1871
1872 if (r < 0) {
1873 log_error("Failed to iterate through journal: %s", strerror(-r));
1874 return EXIT_FAILURE;
1875 }
1876
1877 if (!arg_follow)
1878 pager_open_if_enabled();
1879
1880 if (!arg_quiet) {
1881 usec_t start, end;
1882 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1883
1884 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1885 if (r < 0) {
1886 log_error("Failed to get cutoff: %s", strerror(-r));
1887 goto finish;
1888 }
1889
1890 if (r > 0) {
1891 if (arg_follow)
1892 printf("-- Logs begin at %s. --\n",
1893 format_timestamp(start_buf, sizeof(start_buf), start));
1894 else
1895 printf("-- Logs begin at %s, end at %s. --\n",
1896 format_timestamp(start_buf, sizeof(start_buf), start),
1897 format_timestamp(end_buf, sizeof(end_buf), end));
1898 }
1899 }
1900
1901 for (;;) {
1902 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1903 int flags;
1904
1905 if (need_seek) {
1906 if (!arg_reverse)
1907 r = sd_journal_next(j);
1908 else
1909 r = sd_journal_previous(j);
1910 if (r < 0) {
1911 log_error("Failed to iterate through journal: %s", strerror(-r));
1912 goto finish;
1913 }
1914 if (r == 0)
1915 break;
1916 }
1917
1918 if (arg_until_set && !arg_reverse) {
1919 usec_t usec;
1920
1921 r = sd_journal_get_realtime_usec(j, &usec);
1922 if (r < 0) {
1923 log_error("Failed to determine timestamp: %s", strerror(-r));
1924 goto finish;
1925 }
1926 if (usec > arg_until)
1927 goto finish;
1928 }
1929
1930 if (arg_since_set && arg_reverse) {
1931 usec_t usec;
1932
1933 r = sd_journal_get_realtime_usec(j, &usec);
1934 if (r < 0) {
1935 log_error("Failed to determine timestamp: %s", strerror(-r));
1936 goto finish;
1937 }
1938 if (usec < arg_since)
1939 goto finish;
1940 }
1941
1942 if (!arg_merge) {
1943 sd_id128_t boot_id;
1944
1945 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1946 if (r >= 0) {
1947 if (previous_boot_id_valid &&
1948 !sd_id128_equal(boot_id, previous_boot_id))
1949 printf("%s-- Reboot --%s\n",
1950 ansi_highlight(), ansi_highlight_off());
1951
1952 previous_boot_id = boot_id;
1953 previous_boot_id_valid = true;
1954 }
1955 }
1956
1957 flags =
1958 arg_all * OUTPUT_SHOW_ALL |
1959 arg_full * OUTPUT_FULL_WIDTH |
1960 on_tty() * OUTPUT_COLOR |
1961 arg_catalog * OUTPUT_CATALOG;
1962
1963 r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
1964 need_seek = true;
1965 if (r == -EADDRNOTAVAIL)
1966 break;
1967 else if (r < 0 || ferror(stdout))
1968 goto finish;
1969
1970 n_shown++;
1971 }
1972
1973 if (!arg_follow) {
1974 if (arg_show_cursor) {
1975 _cleanup_free_ char *cursor = NULL;
1976
1977 r = sd_journal_get_cursor(j, &cursor);
1978 if (r < 0 && r != -EADDRNOTAVAIL)
1979 log_error("Failed to get cursor: %s", strerror(-r));
1980 else if (r >= 0)
1981 printf("-- cursor: %s\n", cursor);
1982 }
1983
1984 break;
1985 }
1986
1987 r = sd_journal_wait(j, (uint64_t) -1);
1988 if (r < 0) {
1989 log_error("Couldn't wait for journal event: %s", strerror(-r));
1990 goto finish;
1991 }
1992
1993 first_line = false;
1994 }
1995
1996 finish:
1997 pager_close();
1998
1999 strv_free(arg_file);
2000
2001 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2002 }