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