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