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