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