1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
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.
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.
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/>.
34 #include <sys/ioctl.h>
42 #include <systemd/sd-journal.h>
45 #include "logs-show.h"
47 #include "path-util.h"
51 #include "logs-show.h"
53 #include "journal-internal.h"
54 #include "journal-def.h"
55 #include "journal-verify.h"
56 #include "journal-authenticate.h"
57 #include "journal-qrcode.h"
59 #include "unit-name.h"
62 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
64 static OutputMode arg_output
= OUTPUT_SHORT
;
65 static bool arg_pager_end
= false;
66 static bool arg_follow
= false;
67 static bool arg_full
= false;
68 static bool arg_all
= false;
69 static bool arg_no_pager
= false;
70 static int arg_lines
= -1;
71 static bool arg_no_tail
= false;
72 static bool arg_quiet
= false;
73 static bool arg_merge
= false;
74 static bool arg_boot
= false;
75 static char *arg_boot_descriptor
= NULL
;
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
;
85 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
86 static bool arg_force
= false;
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
;
107 ACTION_UPDATE_CATALOG
108 } arg_action
= ACTION_SHOW
;
110 typedef struct boot_id_t
{
115 static int help(void) {
117 printf("%s [OPTIONS...] [MATCHES...]\n\n"
118 "Query the journal.\n\n"
120 " --system Show only the system journal\n"
121 " --user Show only the user journal for current user\n"
122 " --since=DATE Start showing entries newer or of the specified date\n"
123 " --until=DATE Stop showing entries older or of the specified date\n"
124 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
125 " --after-cursor=CURSOR Start showing entries from specified cursor\n"
126 " --show-cursor Print the cursor after all the entries\n"
127 " -b --boot[=ID] Show data only from ID or current boot if unspecified\n"
128 " -k --dmesg Show kernel message log from current boot\n"
129 " -u --unit=UNIT Show data only from the specified unit\n"
130 " --user-unit=UNIT Show data only from the specified user session unit\n"
131 " -p --priority=RANGE Show only messages within the specified priority range\n"
132 " -e --pager-end Immediately jump to end of the journal in the pager\n"
133 " -f --follow Follow journal\n"
134 " -n --lines[=INTEGER] Number of journal entries to show\n"
135 " --no-tail Show all lines, even in follow mode\n"
136 " -r --reverse Show the newest entries first\n"
137 " -o --output=STRING Change journal output mode (short, short-iso,\n"
138 " short-precise, short-monotonic, verbose,\n"
139 " export, json, json-pretty, json-sse, cat)\n"
140 " -x --catalog Add message explanations where available\n"
141 " -l --full Do not ellipsize fields\n"
142 " -a --all Show all fields, including long and unprintable\n"
143 " -q --quiet Don't show privilege warning\n"
144 " --no-pager Do not pipe output into a pager\n"
145 " -m --merge Show entries from all available journals\n"
146 " -D --directory=PATH Show journal files from directory\n"
147 " --file=PATH Show journal file\n"
148 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
150 " --interval=TIME Time interval for changing the FSS sealing key\n"
151 " --verify-key=KEY Specify FSS verification key\n"
152 " --force Force overriding new FSS key pair with --setup-keys\n"
155 " -h --help Show this help\n"
156 " --version Show package version\n"
157 " --new-id128 Generate a new 128 Bit ID\n"
158 " --header Show journal header information\n"
159 " --disk-usage Show total disk usage\n"
160 " -F --field=FIELD List all values a certain field takes\n"
161 " --list-catalog Show message IDs of all entries in the message catalog\n"
162 " --dump-catalog Show entries in the message catalog\n"
163 " --update-catalog Update the message catalog database\n"
165 " --setup-keys Generate new FSS key pair\n"
166 " --verify Verify journal file consistency\n"
168 , program_invocation_short_name
);
173 static int parse_argv(int argc
, char *argv
[]) {
201 static const struct option options
[] = {
202 { "help", no_argument
, NULL
, 'h' },
203 { "version" , no_argument
, NULL
, ARG_VERSION
},
204 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
205 { "pager-end", no_argument
, NULL
, 'e' },
206 { "follow", no_argument
, NULL
, 'f' },
207 { "force", no_argument
, NULL
, ARG_FORCE
},
208 { "output", required_argument
, NULL
, 'o' },
209 { "all", no_argument
, NULL
, 'a' },
210 { "full", no_argument
, NULL
, 'l' },
211 { "lines", optional_argument
, NULL
, 'n' },
212 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
213 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
214 { "quiet", no_argument
, NULL
, 'q' },
215 { "merge", no_argument
, NULL
, 'm' },
216 { "boot", optional_argument
, NULL
, 'b' },
217 { "this-boot", optional_argument
, NULL
, 'b' }, /* deprecated */
218 { "dmesg", no_argument
, NULL
, 'k' },
219 { "system", no_argument
, NULL
, ARG_SYSTEM
},
220 { "user", no_argument
, NULL
, ARG_USER
},
221 { "directory", required_argument
, NULL
, 'D' },
222 { "file", required_argument
, NULL
, ARG_FILE
},
223 { "root", required_argument
, NULL
, ARG_ROOT
},
224 { "header", no_argument
, NULL
, ARG_HEADER
},
225 { "priority", required_argument
, NULL
, 'p' },
226 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
227 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
228 { "verify", no_argument
, NULL
, ARG_VERIFY
},
229 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
230 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
231 { "cursor", required_argument
, NULL
, 'c' },
232 { "after-cursor", required_argument
, NULL
, ARG_AFTER_CURSOR
},
233 { "show-cursor", no_argument
, NULL
, ARG_SHOW_CURSOR
},
234 { "since", required_argument
, NULL
, ARG_SINCE
},
235 { "until", required_argument
, NULL
, ARG_UNTIL
},
236 { "unit", required_argument
, NULL
, 'u' },
237 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
238 { "field", required_argument
, NULL
, 'F' },
239 { "catalog", no_argument
, NULL
, 'x' },
240 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
241 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
242 { "update-catalog", no_argument
, NULL
, ARG_UPDATE_CATALOG
},
243 { "reverse", no_argument
, NULL
, 'r' },
252 while ((c
= getopt_long(argc
, argv
, "hefo:aln::qmb::kD:p:c:u:F:xr", options
, NULL
)) >= 0) {
261 puts(PACKAGE_STRING
);
262 puts(SYSTEMD_FEATURES
);
270 arg_pager_end
= true;
282 arg_output
= output_mode_from_string(optarg
);
283 if (arg_output
< 0) {
284 log_error("Unknown output format '%s'.", optarg
);
288 if (arg_output
== OUTPUT_EXPORT
||
289 arg_output
== OUTPUT_JSON
||
290 arg_output
== OUTPUT_JSON_PRETTY
||
291 arg_output
== OUTPUT_JSON_SSE
||
292 arg_output
== OUTPUT_CAT
)
307 r
= safe_atoi(optarg
, &arg_lines
);
308 if (r
< 0 || arg_lines
< 0) {
309 log_error("Failed to parse lines '%s'", optarg
);
315 /* Hmm, no argument? Maybe the next
316 * word on the command line is
317 * supposed to be the argument? Let's
318 * see if there is one, and is
319 * parsable as a positive
323 safe_atoi(argv
[optind
], &n
) >= 0 &&
339 arg_action
= ACTION_NEW_ID128
;
354 arg_boot_descriptor
= optarg
;
355 else if (optind
< argc
) {
358 if (argv
[optind
][0] != '-' ||
359 safe_atoi(argv
[optind
], &boot
) >= 0) {
360 arg_boot_descriptor
= argv
[optind
];
368 arg_boot
= arg_dmesg
= true;
372 arg_journal_type
|= SD_JOURNAL_SYSTEM
;
376 arg_journal_type
|= SD_JOURNAL_CURRENT_USER
;
380 arg_directory
= optarg
;
384 r
= glob_extend(&arg_file
, optarg
);
386 log_error("Failed to add paths: %s", strerror(-r
));
399 case ARG_AFTER_CURSOR
:
400 arg_after_cursor
= optarg
;
403 case ARG_SHOW_CURSOR
:
404 arg_show_cursor
= true;
408 arg_action
= ACTION_PRINT_HEADER
;
412 arg_action
= ACTION_VERIFY
;
416 arg_action
= ACTION_DISK_USAGE
;
425 arg_action
= ACTION_SETUP_KEYS
;
430 arg_action
= ACTION_VERIFY
;
431 arg_verify_key
= optarg
;
436 r
= parse_sec(optarg
, &arg_interval
);
437 if (r
< 0 || arg_interval
<= 0) {
438 log_error("Failed to parse sealing key change interval: %s", optarg
);
447 log_error("Forward-secure sealing not available.");
454 dots
= strstr(optarg
, "..");
460 a
= strndup(optarg
, dots
- optarg
);
464 from
= log_level_from_string(a
);
465 to
= log_level_from_string(dots
+ 2);
468 if (from
< 0 || to
< 0) {
469 log_error("Failed to parse log level range %s", optarg
);
476 for (i
= from
; i
<= to
; i
++)
477 arg_priorities
|= 1 << i
;
479 for (i
= to
; i
<= from
; i
++)
480 arg_priorities
|= 1 << i
;
486 p
= log_level_from_string(optarg
);
488 log_error("Unknown log level %s", optarg
);
494 for (i
= 0; i
<= p
; i
++)
495 arg_priorities
|= 1 << i
;
502 r
= parse_timestamp(optarg
, &arg_since
);
504 log_error("Failed to parse timestamp: %s", optarg
);
507 arg_since_set
= true;
511 r
= parse_timestamp(optarg
, &arg_until
);
513 log_error("Failed to parse timestamp: %s", optarg
);
516 arg_until_set
= true;
520 r
= strv_extend(&arg_system_units
, optarg
);
526 r
= strv_extend(&arg_user_units
, optarg
);
542 case ARG_LIST_CATALOG
:
543 arg_action
= ACTION_LIST_CATALOG
;
546 case ARG_DUMP_CATALOG
:
547 arg_action
= ACTION_DUMP_CATALOG
;
550 case ARG_UPDATE_CATALOG
:
551 arg_action
= ACTION_UPDATE_CATALOG
;
559 log_error("Unknown option code %c", c
);
564 if (arg_follow
&& !arg_no_tail
&& arg_lines
< 0)
567 if (arg_directory
&& arg_file
) {
568 log_error("Please specify either -D/--directory= or --file=, not both.");
572 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
573 log_error("--since= must be before --until=.");
577 if (!!arg_cursor
+ !!arg_after_cursor
+ !!arg_since_set
> 1) {
578 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
582 if (arg_follow
&& arg_reverse
) {
583 log_error("Please specify either --reverse= or --follow=, not both.");
590 static int generate_new_id128(void) {
595 r
= sd_id128_randomize(&id
);
597 log_error("Failed to generate ID: %s", strerror(-r
));
601 printf("As string:\n"
602 SD_ID128_FORMAT_STR
"\n\n"
604 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
606 "#define MESSAGE_XYZ SD_ID128_MAKE(",
607 SD_ID128_FORMAT_VAL(id
),
608 SD_ID128_FORMAT_VAL(id
));
609 for (i
= 0; i
< 16; i
++)
610 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
611 fputs(")\n\n", stdout
);
613 printf("As Python constant:\n"
615 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
616 SD_ID128_FORMAT_VAL(id
));
621 static int add_matches(sd_journal
*j
, char **args
) {
626 STRV_FOREACH(i
, args
) {
630 r
= sd_journal_add_disjunction(j
);
631 else if (path_is_absolute(*i
)) {
632 _cleanup_free_
char *p
, *t
= NULL
, *t2
= NULL
;
634 _cleanup_free_
char *interpreter
= NULL
;
637 p
= canonicalize_file_name(*i
);
640 if (stat(path
, &st
) < 0) {
641 log_error("Couldn't stat file: %m");
645 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
)) {
646 if (executable_is_script(path
, &interpreter
) > 0) {
647 _cleanup_free_
char *comm
;
649 comm
= strndup(path_get_file_name(path
), 15);
653 t
= strappend("_COMM=", comm
);
655 /* Append _EXE only if the interpreter is not a link.
656 Otherwise it might be outdated often. */
657 if (lstat(interpreter
, &st
) == 0 &&
658 !S_ISLNK(st
.st_mode
)) {
659 t2
= strappend("_EXE=", interpreter
);
664 t
= strappend("_EXE=", path
);
665 } else if (S_ISCHR(st
.st_mode
))
666 asprintf(&t
, "_KERNEL_DEVICE=c%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
667 else if (S_ISBLK(st
.st_mode
))
668 asprintf(&t
, "_KERNEL_DEVICE=b%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
670 log_error("File is neither a device node, nor regular file, nor executable: %s", *i
);
677 r
= sd_journal_add_match(j
, t
, 0);
679 r
= sd_journal_add_match(j
, t2
, 0);
681 r
= sd_journal_add_match(j
, *i
, 0);
684 log_error("Failed to add match '%s': %s", *i
, strerror(-r
));
692 static int boot_id_cmp(const void *a
, const void *b
) {
695 _a
= ((const boot_id_t
*)a
)->timestamp
;
696 _b
= ((const boot_id_t
*)b
)->timestamp
;
698 return _a
< _b
? -1 : (_a
> _b
? 1 : 0);
701 static int get_relative_boot_id(sd_journal
*j
, sd_id128_t
*boot_id
, int relative
) {
704 unsigned int count
= 0;
705 size_t length
, allocated
= 0;
706 boot_id_t ref_boot_id
= {SD_ID128_NULL
}, *id
;
707 _cleanup_free_ boot_id_t
*all_ids
= NULL
;
712 if (relative
== 0 && !sd_id128_equal(*boot_id
, SD_ID128_NULL
))
715 r
= sd_journal_query_unique(j
, "_BOOT_ID");
719 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, length
) {
720 if (length
< strlen("_BOOT_ID="))
723 if (!GREEDY_REALLOC(all_ids
, allocated
, count
+ 1))
726 id
= &all_ids
[count
];
728 r
= sd_id128_from_string(((const char *)data
) + strlen("_BOOT_ID="), &id
->id
);
732 r
= sd_journal_add_match(j
, data
, length
);
736 r
= sd_journal_seek_head(j
);
740 r
= sd_journal_next(j
);
746 r
= sd_journal_get_realtime_usec(j
, &id
->timestamp
);
750 if (sd_id128_equal(id
->id
, *boot_id
))
755 sd_journal_flush_matches(j
);
758 qsort(all_ids
, count
, sizeof(boot_id_t
), boot_id_cmp
);
760 if (sd_id128_equal(*boot_id
, SD_ID128_NULL
)) {
761 if (relative
> (int) count
|| relative
<= -(int)count
)
762 return -EADDRNOTAVAIL
;
764 *boot_id
= all_ids
[(relative
<= 0)*count
+ relative
- 1].id
;
766 id
= bsearch(&ref_boot_id
, all_ids
, count
, sizeof(boot_id_t
), boot_id_cmp
);
769 relative
<= 0 ? (id
- all_ids
) + relative
< 0 :
770 (id
- all_ids
) + relative
>= (int) count
)
771 return -EADDRNOTAVAIL
;
773 *boot_id
= (id
+ relative
)->id
;
779 static int add_boot(sd_journal
*j
) {
780 char match
[9+32+1] = "_BOOT_ID=";
782 sd_id128_t boot_id
= SD_ID128_NULL
;
790 if (!arg_boot_descriptor
)
791 return add_match_this_boot(j
);
793 if (strlen(arg_boot_descriptor
) >= 32) {
794 char tmp
= arg_boot_descriptor
[32];
795 arg_boot_descriptor
[32] = '\0';
796 r
= sd_id128_from_string(arg_boot_descriptor
, &boot_id
);
797 arg_boot_descriptor
[32] = tmp
;
800 log_error("Failed to parse boot ID '%.32s': %s",
801 arg_boot_descriptor
, strerror(-r
));
805 offset
= arg_boot_descriptor
+ 32;
807 if (*offset
&& *offset
!= '-' && *offset
!= '+') {
808 log_error("Relative boot ID offset must start with a '+' or a '-', found '%s' ", offset
);
812 offset
= arg_boot_descriptor
;
815 r
= safe_atoi(offset
, &relative
);
817 log_error("Failed to parse relative boot ID number '%s'", offset
);
822 r
= get_relative_boot_id(j
, &boot_id
, relative
);
824 if (sd_id128_equal(boot_id
, SD_ID128_NULL
))
825 log_error("Failed to look up boot %+d: %s", relative
, strerror(-r
));
827 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR
"%+d: %s",
828 SD_ID128_FORMAT_VAL(boot_id
), relative
, strerror(-r
));
832 sd_id128_to_string(boot_id
, match
+ 9);
834 r
= sd_journal_add_match(j
, match
, sizeof(match
) - 1);
836 log_error("Failed to add match: %s", strerror(-r
));
840 r
= sd_journal_add_conjunction(j
);
847 static int add_dmesg(sd_journal
*j
) {
854 r
= sd_journal_add_match(j
, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
856 log_error("Failed to add match: %s", strerror(-r
));
860 r
= sd_journal_add_conjunction(j
);
867 static int add_units(sd_journal
*j
) {
868 _cleanup_free_
char *u
= NULL
;
874 STRV_FOREACH(i
, arg_system_units
) {
875 u
= unit_name_mangle(*i
);
878 r
= add_matches_for_unit(j
, u
);
881 r
= sd_journal_add_disjunction(j
);
886 STRV_FOREACH(i
, arg_user_units
) {
887 u
= unit_name_mangle(*i
);
891 r
= add_matches_for_user_unit(j
, u
, getuid());
895 r
= sd_journal_add_disjunction(j
);
901 r
= sd_journal_add_conjunction(j
);
908 static int add_priorities(sd_journal
*j
) {
909 char match
[] = "PRIORITY=0";
913 if (arg_priorities
== 0xFF)
916 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
917 if (arg_priorities
& (1 << i
)) {
918 match
[sizeof(match
)-2] = '0' + i
;
920 r
= sd_journal_add_match(j
, match
, strlen(match
));
922 log_error("Failed to add match: %s", strerror(-r
));
927 r
= sd_journal_add_conjunction(j
);
934 static int setup_keys(void) {
936 size_t mpk_size
, seed_size
, state_size
, i
;
937 uint8_t *mpk
, *seed
, *state
;
939 int fd
= -1, r
, attr
= 0;
940 sd_id128_t machine
, boot
;
941 char *p
= NULL
, *k
= NULL
;
946 r
= stat("/var/log/journal", &st
);
947 if (r
< 0 && errno
!= ENOENT
&& errno
!= ENOTDIR
) {
948 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
952 if (r
< 0 || !S_ISDIR(st
.st_mode
)) {
953 log_error("%s is not a directory, must be using persistent logging for FSS.",
955 return r
< 0 ? -errno
: -ENOTDIR
;
958 r
= sd_id128_get_machine(&machine
);
960 log_error("Failed to get machine ID: %s", strerror(-r
));
964 r
= sd_id128_get_boot(&boot
);
966 log_error("Failed to get boot ID: %s", strerror(-r
));
970 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
971 SD_ID128_FORMAT_VAL(machine
)) < 0)
974 if (access(p
, F_OK
) >= 0) {
978 log_error("unlink(\"%s\") failed: %m", p
);
983 log_error("Sealing key file %s exists already. (--force to recreate)", p
);
989 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
990 SD_ID128_FORMAT_VAL(machine
)) < 0) {
995 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
996 mpk
= alloca(mpk_size
);
998 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
999 seed
= alloca(seed_size
);
1001 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
1002 state
= alloca(state_size
);
1004 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1006 log_error("Failed to open /dev/random: %m");
1011 log_info("Generating seed...");
1012 l
= loop_read(fd
, seed
, seed_size
, true);
1013 if (l
< 0 || (size_t) l
!= seed_size
) {
1014 log_error("Failed to read random seed: %s", strerror(EIO
));
1019 log_info("Generating key pair...");
1020 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
1022 log_info("Generating sealing key...");
1023 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
1025 assert(arg_interval
> 0);
1027 n
= now(CLOCK_REALTIME
);
1030 close_nointr_nofail(fd
);
1031 fd
= mkostemp(k
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
1033 log_error("Failed to open %s: %m", k
);
1038 /* Enable secure remove, exclusion from dump, synchronous
1039 * writing and in-place updating */
1040 if (ioctl(fd
, FS_IOC_GETFLAGS
, &attr
) < 0)
1041 log_warning("FS_IOC_GETFLAGS failed: %m");
1043 attr
|= FS_SECRM_FL
|FS_NODUMP_FL
|FS_SYNC_FL
|FS_NOCOW_FL
;
1045 if (ioctl(fd
, FS_IOC_SETFLAGS
, &attr
) < 0)
1046 log_warning("FS_IOC_SETFLAGS failed: %m");
1049 memcpy(h
.signature
, "KSHHRHLP", 8);
1050 h
.machine_id
= machine
;
1052 h
.header_size
= htole64(sizeof(h
));
1053 h
.start_usec
= htole64(n
* arg_interval
);
1054 h
.interval_usec
= htole64(arg_interval
);
1055 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
1056 h
.fsprg_state_size
= htole64(state_size
);
1058 l
= loop_write(fd
, &h
, sizeof(h
), false);
1059 if (l
< 0 || (size_t) l
!= sizeof(h
)) {
1060 log_error("Failed to write header: %s", strerror(EIO
));
1065 l
= loop_write(fd
, state
, state_size
, false);
1066 if (l
< 0 || (size_t) l
!= state_size
) {
1067 log_error("Failed to write state: %s", strerror(EIO
));
1072 if (link(k
, p
) < 0) {
1073 log_error("Failed to link file: %m");
1081 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON
"secret sealing key" ANSI_HIGHLIGHT_OFF
" has been written to\n"
1082 "the following local file. This key file is automatically updated when the\n"
1083 "sealing key is advanced. It should not be used on multiple hosts.\n"
1087 "Please write down the following " ANSI_HIGHLIGHT_ON
"secret verification key" ANSI_HIGHLIGHT_OFF
". It should be stored\n"
1088 "at a safe location and should not be saved locally on disk.\n"
1089 "\n\t" ANSI_HIGHLIGHT_RED_ON
, p
);
1092 for (i
= 0; i
< seed_size
; i
++) {
1093 if (i
> 0 && i
% 3 == 0)
1095 printf("%02x", ((uint8_t*) seed
)[i
]);
1098 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
1101 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
1104 ANSI_HIGHLIGHT_OFF
"\n"
1105 "The sealing key is automatically changed every %s.\n",
1106 format_timespan(tsb
, sizeof(tsb
), arg_interval
, 0));
1108 hn
= gethostname_malloc();
1111 hostname_cleanup(hn
, false);
1112 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
1114 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
1116 #ifdef HAVE_QRENCODE
1117 /* If this is not an UTF-8 system don't print any QR codes */
1118 if (is_locale_utf8()) {
1119 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
1120 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
1130 close_nointr_nofail(fd
);
1141 log_error("Forward-secure sealing not available.");
1146 static int verify(sd_journal
*j
) {
1153 log_show_color(true);
1155 HASHMAP_FOREACH(f
, j
->files
, i
) {
1157 usec_t first
, validated
, last
;
1160 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
1161 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
1164 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
1166 /* If the key was invalid give up right-away. */
1169 log_warning("FAIL: %s (%s)", f
->path
, strerror(-k
));
1172 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
1173 log_info("PASS: %s", f
->path
);
1175 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
1176 if (validated
> 0) {
1177 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1178 format_timestamp(a
, sizeof(a
), first
),
1179 format_timestamp(b
, sizeof(b
), validated
),
1180 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0, 0));
1181 } else if (last
> 0)
1182 log_info("=> No sealing yet, %s of entries not sealed.",
1183 format_timespan(c
, sizeof(c
), last
- first
, 0));
1185 log_info("=> No sealing yet, no entries in file.");
1194 static int access_check_var_log_journal(sd_journal
*j
) {
1195 _cleanup_strv_free_
char **g
= NULL
;
1201 have_access
= in_group("systemd-journal") > 0;
1204 /* Let's enumerate all groups from the default ACL of
1205 * the directory, which generally should allow access
1206 * to most journal files too */
1207 r
= search_acl_groups(&g
, "/var/log/journal/", &have_access
);
1214 if (strv_isempty(g
))
1215 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1216 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1217 " turn off this notice.");
1219 _cleanup_free_
char *s
= NULL
;
1221 r
= strv_extend(&g
, "systemd-journal");
1228 s
= strv_join(g
, "', '");
1232 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1233 " Users in the groups '%s' can see all messages.\n"
1234 " Pass -q to turn off this notice.", s
);
1242 static int access_check(sd_journal
*j
) {
1249 if (set_isempty(j
->errors
)) {
1250 if (hashmap_isempty(j
->files
))
1251 log_notice("No journal files were found.");
1255 if (set_contains(j
->errors
, INT_TO_PTR(-EACCES
))) {
1257 /* If /var/log/journal doesn't even exist,
1258 * unprivileged users have no access at all */
1259 if (access("/var/log/journal", F_OK
) < 0 &&
1261 in_group("systemd-journal") <= 0) {
1262 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1263 "enabled. Users in the 'systemd-journal' group may always access messages.");
1267 /* If /var/log/journal exists, try to pring a nice
1268 notice if the user lacks access to it */
1269 if (!arg_quiet
&& geteuid() != 0) {
1270 r
= access_check_var_log_journal(j
);
1275 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1276 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1277 "group may access messages.");
1282 if (hashmap_isempty(j
->files
)) {
1283 log_error("No journal files were opened due to insufficient permissions.");
1288 SET_FOREACH(code
, j
->errors
, it
) {
1291 err
= -PTR_TO_INT(code
);
1295 log_warning("Error was encountered while opening journal files: %s",
1302 int main(int argc
, char *argv
[]) {
1304 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1305 bool need_seek
= false;
1306 sd_id128_t previous_boot_id
;
1307 bool previous_boot_id_valid
= false, first_line
= true;
1309 bool ellipsized
= false;
1311 setlocale(LC_ALL
, "");
1312 log_parse_environment();
1315 r
= parse_argv(argc
, argv
);
1319 signal(SIGWINCH
, columns_lines_cache_reset
);
1321 if (arg_action
== ACTION_NEW_ID128
) {
1322 r
= generate_new_id128();
1326 if (arg_action
== ACTION_SETUP_KEYS
) {
1331 if (arg_action
== ACTION_UPDATE_CATALOG
||
1332 arg_action
== ACTION_LIST_CATALOG
||
1333 arg_action
== ACTION_DUMP_CATALOG
) {
1335 const char* database
= CATALOG_DATABASE
;
1336 _cleanup_free_
char *copy
= NULL
;
1338 copy
= strjoin(arg_root
, "/", CATALOG_DATABASE
, NULL
);
1343 path_kill_slashes(copy
);
1347 if (arg_action
== ACTION_UPDATE_CATALOG
) {
1348 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
1350 log_error("Failed to list catalog: %s", strerror(-r
));
1352 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
1355 r
= catalog_list_items(stdout
, database
,
1356 oneline
, argv
+ optind
);
1358 r
= catalog_list(stdout
, database
, oneline
);
1360 log_error("Failed to list catalog: %s", strerror(-r
));
1367 r
= sd_journal_open_directory(&j
, arg_directory
, arg_journal_type
);
1369 r
= sd_journal_open_files(&j
, (const char**) arg_file
, 0);
1371 r
= sd_journal_open(&j
, !arg_merge
*SD_JOURNAL_LOCAL_ONLY
+ arg_journal_type
);
1373 log_error("Failed to open %s: %s",
1374 arg_directory
? arg_directory
: arg_file
? "files" : "journal",
1376 return EXIT_FAILURE
;
1379 r
= access_check(j
);
1381 return EXIT_FAILURE
;
1383 if (arg_action
== ACTION_VERIFY
) {
1388 if (arg_action
== ACTION_PRINT_HEADER
) {
1389 journal_print_header(j
);
1390 return EXIT_SUCCESS
;
1393 if (arg_action
== ACTION_DISK_USAGE
) {
1395 char sbytes
[FORMAT_BYTES_MAX
];
1397 r
= sd_journal_get_usage(j
, &bytes
);
1399 return EXIT_FAILURE
;
1401 printf("Journals take up %s on disk.\n",
1402 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
1403 return EXIT_SUCCESS
;
1406 /* add_boot() must be called first!
1407 * It may need to seek the journal to find parent boot IDs. */
1410 return EXIT_FAILURE
;
1414 return EXIT_FAILURE
;
1417 strv_free(arg_system_units
);
1418 strv_free(arg_user_units
);
1421 return EXIT_FAILURE
;
1423 r
= add_priorities(j
);
1425 return EXIT_FAILURE
;
1427 r
= add_matches(j
, argv
+ optind
);
1429 return EXIT_FAILURE
;
1431 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG
))) {
1432 _cleanup_free_
char *filter
;
1434 filter
= journal_make_match_string(j
);
1435 log_debug("Journal filter: %s", filter
);
1442 r
= sd_journal_set_data_threshold(j
, 0);
1444 log_error("Failed to unset data size threshold");
1445 return EXIT_FAILURE
;
1448 r
= sd_journal_query_unique(j
, arg_field
);
1450 log_error("Failed to query unique data objects: %s", strerror(-r
));
1451 return EXIT_FAILURE
;
1454 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1457 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
1460 eq
= memchr(data
, '=', size
);
1462 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
1464 printf("%.*s\n", (int) size
, (const char*) data
);
1469 return EXIT_SUCCESS
;
1472 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1474 r
= sd_journal_get_fd(j
);
1476 return EXIT_FAILURE
;
1479 if (arg_cursor
|| arg_after_cursor
) {
1480 r
= sd_journal_seek_cursor(j
, arg_cursor
? arg_cursor
: arg_after_cursor
);
1482 log_error("Failed to seek to cursor: %s", strerror(-r
));
1483 return EXIT_FAILURE
;
1486 r
= sd_journal_next_skip(j
, 1 + !!arg_after_cursor
);
1488 r
= sd_journal_previous_skip(j
, 1 + !!arg_after_cursor
);
1490 if (arg_after_cursor
&& r
< 2 && !arg_follow
)
1491 /* We couldn't find the next entry after the cursor. */
1494 } else if (arg_since_set
&& !arg_reverse
) {
1495 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
1497 log_error("Failed to seek to date: %s", strerror(-r
));
1498 return EXIT_FAILURE
;
1500 r
= sd_journal_next(j
);
1502 } else if (arg_until_set
&& arg_reverse
) {
1503 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
1505 log_error("Failed to seek to date: %s", strerror(-r
));
1506 return EXIT_FAILURE
;
1508 r
= sd_journal_previous(j
);
1510 } else if (arg_lines
>= 0) {
1511 r
= sd_journal_seek_tail(j
);
1513 log_error("Failed to seek to tail: %s", strerror(-r
));
1514 return EXIT_FAILURE
;
1517 r
= sd_journal_previous_skip(j
, arg_lines
);
1519 } else if (arg_reverse
) {
1520 r
= sd_journal_seek_tail(j
);
1522 log_error("Failed to seek to tail: %s", strerror(-r
));
1523 return EXIT_FAILURE
;
1526 r
= sd_journal_previous(j
);
1529 r
= sd_journal_seek_head(j
);
1531 log_error("Failed to seek to head: %s", strerror(-r
));
1532 return EXIT_FAILURE
;
1535 r
= sd_journal_next(j
);
1539 log_error("Failed to iterate through journal: %s", strerror(-r
));
1540 return EXIT_FAILURE
;
1543 if (!arg_no_pager
&& !arg_follow
)
1544 pager_open(arg_pager_end
);
1548 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
1550 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
1552 log_error("Failed to get cutoff: %s", strerror(-r
));
1558 printf("-- Logs begin at %s. --\n",
1559 format_timestamp(start_buf
, sizeof(start_buf
), start
));
1561 printf("-- Logs begin at %s, end at %s. --\n",
1562 format_timestamp(start_buf
, sizeof(start_buf
), start
),
1563 format_timestamp(end_buf
, sizeof(end_buf
), end
));
1568 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
1573 r
= sd_journal_next(j
);
1575 r
= sd_journal_previous(j
);
1577 log_error("Failed to iterate through journal: %s", strerror(-r
));
1584 if (arg_until_set
&& !arg_reverse
) {
1587 r
= sd_journal_get_realtime_usec(j
, &usec
);
1589 log_error("Failed to determine timestamp: %s", strerror(-r
));
1592 if (usec
> arg_until
)
1596 if (arg_since_set
&& arg_reverse
) {
1599 r
= sd_journal_get_realtime_usec(j
, &usec
);
1601 log_error("Failed to determine timestamp: %s", strerror(-r
));
1604 if (usec
< arg_since
)
1611 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1613 if (previous_boot_id_valid
&&
1614 !sd_id128_equal(boot_id
, previous_boot_id
))
1615 printf("%s-- Reboot --%s\n",
1616 ansi_highlight(), ansi_highlight_off());
1618 previous_boot_id
= boot_id
;
1619 previous_boot_id_valid
= true;
1624 arg_all
* OUTPUT_SHOW_ALL
|
1625 (arg_full
|| !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
1626 on_tty() * OUTPUT_COLOR
|
1627 arg_catalog
* OUTPUT_CATALOG
;
1629 r
= output_journal(stdout
, j
, arg_output
, 0, flags
, &ellipsized
);
1631 if (r
== -EADDRNOTAVAIL
)
1633 else if (r
< 0 || ferror(stdout
))
1640 if (arg_show_cursor
) {
1641 _cleanup_free_
char *cursor
= NULL
;
1643 r
= sd_journal_get_cursor(j
, &cursor
);
1644 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
1645 log_error("Failed to get cursor: %s", strerror(-r
));
1647 printf("-- cursor: %s\n", cursor
);
1653 r
= sd_journal_wait(j
, (uint64_t) -1);
1655 log_error("Couldn't wait for journal event: %s", strerror(-r
));
1665 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;