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/>.
35 #include <sys/ioctl.h>
43 #include "systemd/sd-journal.h"
46 #include "logs-show.h"
48 #include "path-util.h"
54 #include "journal-internal.h"
55 #include "journal-def.h"
56 #include "journal-verify.h"
57 #include "journal-authenticate.h"
58 #include "journal-qrcode.h"
60 #include "unit-name.h"
63 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
65 static OutputMode arg_output = OUTPUT_SHORT;
66 static bool arg_pager_end = false;
67 static bool arg_follow = false;
68 static bool arg_full = true;
69 static bool arg_all = false;
70 static bool arg_no_pager = false;
71 static int arg_lines = -2;
72 static bool arg_no_tail = false;
73 static bool arg_quiet = false;
74 static bool arg_merge = false;
75 static bool arg_boot = false;
76 static sd_id128_t arg_boot_id = {};
77 static int arg_boot_offset = 0;
78 static bool arg_dmesg = false;
79 static const char *arg_cursor = NULL;
80 static const char *arg_after_cursor = NULL;
81 static bool arg_show_cursor = false;
82 static const char *arg_directory = NULL;
83 static char **arg_file = NULL;
84 static int arg_priorities = 0xFF;
85 static const char *arg_verify_key = NULL;
87 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
88 static bool arg_force = false;
90 static usec_t arg_since, arg_until;
91 static bool arg_since_set = false, arg_until_set = false;
92 static char **arg_syslog_identifier = NULL;
93 static char **arg_system_units = NULL;
94 static char **arg_user_units = NULL;
95 static const char *arg_field = NULL;
96 static bool arg_catalog = false;
97 static bool arg_reverse = false;
98 static int arg_journal_type = 0;
99 static const char *arg_root = NULL;
100 static const char *arg_machine = NULL;
111 ACTION_UPDATE_CATALOG,
113 } arg_action = ACTION_SHOW;
115 typedef struct boot_id_t {
121 static void pager_open_if_enabled(void) {
126 pager_open(arg_pager_end);
129 static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
130 sd_id128_t id = SD_ID128_NULL;
133 if (strlen(x) >= 32) {
137 r = sd_id128_from_string(t, &id);
141 if (*x != '-' && *x != '+' && *x != 0)
145 r = safe_atoi(x, &off);
150 r = safe_atoi(x, &off);
164 static void help(void) {
166 pager_open_if_enabled();
168 printf("%s [OPTIONS...] [MATCHES...]\n\n"
169 "Query the journal.\n\n"
171 " --system Show the system journal\n"
172 " --user Show the user journal for the current user\n"
173 " -M --machine=CONTAINER Operate on local container\n"
174 " --since=DATE Start showing entries on or newer than the specified date\n"
175 " --until=DATE Stop showing entries on or older than the specified date\n"
176 " -c --cursor=CURSOR Start showing entries from the specified cursor\n"
177 " --after-cursor=CURSOR Start showing entries from after the specified cursor\n"
178 " --show-cursor Print the cursor after all the entries\n"
179 " -b --boot[=ID] Show data only from ID or, if unspecified, the current boot\n"
180 " --list-boots Show terse information about recorded boots\n"
181 " -k --dmesg Show kernel message log from the current boot\n"
182 " -u --unit=UNIT Show data only from the specified unit\n"
183 " --user-unit=UNIT Show data only from the specified user session unit\n"
184 " -t --identifier=STRING Show only messages with the specified syslog identifier\n"
185 " -p --priority=RANGE Show only messages within the specified priority range\n"
186 " -e --pager-end Immediately jump to end of the journal in the pager\n"
187 " -f --follow Follow the journal\n"
188 " -n --lines[=INTEGER] Number of journal entries to show\n"
189 " --no-tail Show all lines, even in follow mode\n"
190 " -r --reverse Show the newest entries first\n"
191 " -o --output=STRING Change journal output mode (short, short-iso,\n"
192 " short-precise, short-monotonic, verbose,\n"
193 " export, json, json-pretty, json-sse, cat)\n"
194 " -x --catalog Add message explanations where available\n"
195 " --no-full Ellipsize fields\n"
196 " -a --all Show all fields, including long and unprintable\n"
197 " -q --quiet Do not show privilege warning\n"
198 " --no-pager Do not pipe output into a pager\n"
199 " -m --merge Show entries from all available journals\n"
200 " -D --directory=PATH Show journal files from directory\n"
201 " --file=PATH Show journal file\n"
202 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
204 " --interval=TIME Time interval for changing the FSS sealing key\n"
205 " --verify-key=KEY Specify FSS verification key\n"
206 " --force Force overriding of the FSS key pair with --setup-keys\n"
209 " -h --help Show this help text\n"
210 " --version Show package version\n"
211 " --new-id128 Generate a new 128-bit ID\n"
212 " --header Show journal header information\n"
213 " --disk-usage Show total disk usage of all journal files\n"
214 " -F --field=FIELD List all values that a specified field takes\n"
215 " --list-catalog Show message IDs of all entries in the message catalog\n"
216 " --dump-catalog Show entries in the message catalog\n"
217 " --update-catalog Update the message catalog database\n"
219 " --setup-keys Generate a new FSS key pair\n"
220 " --verify Verify journal file consistency\n"
222 , program_invocation_short_name);
225 static int parse_argv(int argc, char *argv[]) {
255 static const struct option options[] = {
256 { "help", no_argument, NULL, 'h' },
257 { "version" , no_argument, NULL, ARG_VERSION },
258 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
259 { "pager-end", no_argument, NULL, 'e' },
260 { "follow", no_argument, NULL, 'f' },
261 { "force", no_argument, NULL, ARG_FORCE },
262 { "output", required_argument, NULL, 'o' },
263 { "all", no_argument, NULL, 'a' },
264 { "full", no_argument, NULL, 'l' },
265 { "no-full", no_argument, NULL, ARG_NO_FULL },
266 { "lines", optional_argument, NULL, 'n' },
267 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
268 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
269 { "quiet", no_argument, NULL, 'q' },
270 { "merge", no_argument, NULL, 'm' },
271 { "boot", optional_argument, NULL, 'b' },
272 { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
273 { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */
274 { "dmesg", no_argument, NULL, 'k' },
275 { "system", no_argument, NULL, ARG_SYSTEM },
276 { "user", no_argument, NULL, ARG_USER },
277 { "directory", required_argument, NULL, 'D' },
278 { "file", required_argument, NULL, ARG_FILE },
279 { "root", required_argument, NULL, ARG_ROOT },
280 { "header", no_argument, NULL, ARG_HEADER },
281 { "identifier", required_argument, NULL, 't' },
282 { "priority", required_argument, NULL, 'p' },
283 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
284 { "interval", required_argument, NULL, ARG_INTERVAL },
285 { "verify", no_argument, NULL, ARG_VERIFY },
286 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
287 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
288 { "cursor", required_argument, NULL, 'c' },
289 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
290 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
291 { "since", required_argument, NULL, ARG_SINCE },
292 { "until", required_argument, NULL, ARG_UNTIL },
293 { "unit", required_argument, NULL, 'u' },
294 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
295 { "field", required_argument, NULL, 'F' },
296 { "catalog", no_argument, NULL, 'x' },
297 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
298 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
299 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
300 { "reverse", no_argument, NULL, 'r' },
301 { "machine", required_argument, NULL, 'M' },
310 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
319 puts(PACKAGE_STRING);
320 puts(SYSTEMD_FEATURES);
328 arg_pager_end = true;
340 arg_output = output_mode_from_string(optarg);
341 if (arg_output < 0) {
342 log_error("Unknown output format '%s'.", optarg);
346 if (arg_output == OUTPUT_EXPORT ||
347 arg_output == OUTPUT_JSON ||
348 arg_output == OUTPUT_JSON_PRETTY ||
349 arg_output == OUTPUT_JSON_SSE ||
350 arg_output == OUTPUT_CAT)
369 if (streq(optarg, "all"))
372 r = safe_atoi(optarg, &arg_lines);
373 if (r < 0 || arg_lines < 0) {
374 log_error("Failed to parse lines '%s'", optarg);
381 /* Hmm, no argument? Maybe the next
382 * word on the command line is
383 * supposed to be the argument? Let's
384 * see if there is one, and is
388 if (streq(argv[optind], "all")) {
391 } else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) {
405 arg_action = ACTION_NEW_ID128;
420 r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
422 log_error("Failed to parse boot descriptor '%s'", optarg);
427 /* Hmm, no argument? Maybe the next
428 * word on the command line is
429 * supposed to be the argument? Let's
430 * see if there is one and is parsable
431 * as a boot descriptor... */
434 parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0)
441 arg_action = ACTION_LIST_BOOTS;
445 arg_boot = arg_dmesg = true;
449 arg_journal_type |= SD_JOURNAL_SYSTEM;
453 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
457 arg_machine = optarg;
461 arg_directory = optarg;
465 r = glob_extend(&arg_file, optarg);
467 log_error("Failed to add paths: %s", strerror(-r));
480 case ARG_AFTER_CURSOR:
481 arg_after_cursor = optarg;
484 case ARG_SHOW_CURSOR:
485 arg_show_cursor = true;
489 arg_action = ACTION_PRINT_HEADER;
493 arg_action = ACTION_VERIFY;
497 arg_action = ACTION_DISK_USAGE;
506 arg_action = ACTION_SETUP_KEYS;
511 arg_action = ACTION_VERIFY;
512 arg_verify_key = optarg;
517 r = parse_sec(optarg, &arg_interval);
518 if (r < 0 || arg_interval <= 0) {
519 log_error("Failed to parse sealing key change interval: %s", optarg);
528 log_error("Forward-secure sealing not available.");
535 dots = strstr(optarg, "..");
541 a = strndup(optarg, dots - optarg);
545 from = log_level_from_string(a);
546 to = log_level_from_string(dots + 2);
549 if (from < 0 || to < 0) {
550 log_error("Failed to parse log level range %s", optarg);
557 for (i = from; i <= to; i++)
558 arg_priorities |= 1 << i;
560 for (i = to; i <= from; i++)
561 arg_priorities |= 1 << i;
567 p = log_level_from_string(optarg);
569 log_error("Unknown log level %s", optarg);
575 for (i = 0; i <= p; i++)
576 arg_priorities |= 1 << i;
583 r = parse_timestamp(optarg, &arg_since);
585 log_error("Failed to parse timestamp: %s", optarg);
588 arg_since_set = true;
592 r = parse_timestamp(optarg, &arg_until);
594 log_error("Failed to parse timestamp: %s", optarg);
597 arg_until_set = true;
601 r = strv_extend(&arg_syslog_identifier, optarg);
607 r = strv_extend(&arg_system_units, optarg);
613 r = strv_extend(&arg_user_units, optarg);
626 case ARG_LIST_CATALOG:
627 arg_action = ACTION_LIST_CATALOG;
630 case ARG_DUMP_CATALOG:
631 arg_action = ACTION_DUMP_CATALOG;
634 case ARG_UPDATE_CATALOG:
635 arg_action = ACTION_UPDATE_CATALOG;
646 assert_not_reached("Unhandled option");
649 if (arg_follow && !arg_no_tail && arg_lines < -1)
652 if (!!arg_directory + !!arg_file + !!arg_machine > 1) {
653 log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one.");
657 if (arg_since_set && arg_until_set && arg_since > arg_until) {
658 log_error("--since= must be before --until=.");
662 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
663 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
667 if (arg_follow && arg_reverse) {
668 log_error("Please specify either --reverse= or --follow=, not both.");
672 if (arg_action != ACTION_SHOW && optind < argc) {
673 log_error("Extraneous arguments starting with '%s'", argv[optind]);
680 static int generate_new_id128(void) {
685 r = sd_id128_randomize(&id);
687 log_error("Failed to generate ID: %s", strerror(-r));
691 printf("As string:\n"
692 SD_ID128_FORMAT_STR "\n\n"
694 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
696 "#define MESSAGE_XYZ SD_ID128_MAKE(",
697 SD_ID128_FORMAT_VAL(id),
698 SD_ID128_FORMAT_VAL(id));
699 for (i = 0; i < 16; i++)
700 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
701 fputs(")\n\n", stdout);
703 printf("As Python constant:\n"
705 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
706 SD_ID128_FORMAT_VAL(id));
711 static int add_matches(sd_journal *j, char **args) {
713 bool have_term = false;
717 STRV_FOREACH(i, args) {
720 if (streq(*i, "+")) {
723 r = sd_journal_add_disjunction(j);
726 } else if (path_is_absolute(*i)) {
727 _cleanup_free_ char *p, *t = NULL, *t2 = NULL;
729 _cleanup_free_ char *interpreter = NULL;
732 p = canonicalize_file_name(*i);
735 if (stat(path, &st) < 0) {
736 log_error("Couldn't stat file: %m");
740 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
741 if (executable_is_script(path, &interpreter) > 0) {
742 _cleanup_free_ char *comm;
744 comm = strndup(basename(path), 15);
748 t = strappend("_COMM=", comm);
750 /* Append _EXE only if the interpreter is not a link.
751 Otherwise, it might be outdated often. */
752 if (lstat(interpreter, &st) == 0 &&
753 !S_ISLNK(st.st_mode)) {
754 t2 = strappend("_EXE=", interpreter);
759 t = strappend("_EXE=", path);
760 } else if (S_ISCHR(st.st_mode)) {
761 if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u",
763 minor(st.st_rdev)) < 0)
765 } else if (S_ISBLK(st.st_mode)) {
766 if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u",
768 minor(st.st_rdev)) < 0)
771 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
778 r = sd_journal_add_match(j, t, 0);
780 r = sd_journal_add_match(j, t2, 0);
784 r = sd_journal_add_match(j, *i, 0);
789 log_error("Failed to add match '%s': %s", *i, strerror(-r));
794 if (!strv_isempty(args) && !have_term) {
795 log_error("\"+\" can only be used between terms");
802 static int boot_id_cmp(const void *a, const void *b) {
805 _a = ((const boot_id_t *)a)->first;
806 _b = ((const boot_id_t *)b)->first;
808 return _a < _b ? -1 : (_a > _b ? 1 : 0);
811 static int list_boots(sd_journal *j) {
814 unsigned int count = 0;
816 size_t length, allocated = 0;
818 _cleanup_free_ boot_id_t *all_ids = NULL;
820 r = sd_journal_query_unique(j, "_BOOT_ID");
824 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
825 if (length < strlen("_BOOT_ID="))
828 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
831 id = &all_ids[count];
833 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
837 r = sd_journal_add_match(j, data, length);
841 r = sd_journal_seek_head(j);
845 r = sd_journal_next(j);
851 r = sd_journal_get_realtime_usec(j, &id->first);
855 r = sd_journal_seek_tail(j);
859 r = sd_journal_previous(j);
865 r = sd_journal_get_realtime_usec(j, &id->last);
871 sd_journal_flush_matches(j);
874 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
876 /* numbers are one less, but we need an extra char for the sign */
877 w = DECIMAL_STR_WIDTH(count - 1) + 1;
879 for (id = all_ids, i = 0; id < all_ids + count; id++, i++) {
880 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
882 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
884 SD_ID128_FORMAT_VAL(id->id),
885 format_timestamp(a, sizeof(a), id->first),
886 format_timestamp(b, sizeof(b), id->last));
892 static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
895 unsigned int count = 0;
896 size_t length, allocated = 0;
897 boot_id_t ref_boot_id = {SD_ID128_NULL}, *id;
898 _cleanup_free_ boot_id_t *all_ids = NULL;
903 r = sd_journal_query_unique(j, "_BOOT_ID");
907 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
908 if (length < strlen("_BOOT_ID="))
911 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
914 id = &all_ids[count];
916 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
920 r = sd_journal_add_match(j, data, length);
924 r = sd_journal_seek_head(j);
928 r = sd_journal_next(j);
934 r = sd_journal_get_realtime_usec(j, &id->first);
938 if (sd_id128_equal(id->id, *boot_id))
943 sd_journal_flush_matches(j);
946 qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
948 if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
949 if (relative > (int) count || relative <= -(int)count)
950 return -EADDRNOTAVAIL;
952 *boot_id = all_ids[(relative <= 0)*count + relative - 1].id;
954 id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp);
957 relative <= 0 ? (id - all_ids) + relative < 0 :
958 (id - all_ids) + relative >= (int) count)
959 return -EADDRNOTAVAIL;
961 *boot_id = (id + relative)->id;
967 static int add_boot(sd_journal *j) {
968 char match[9+32+1] = "_BOOT_ID=";
976 if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
977 return add_match_this_boot(j, arg_machine);
979 r = get_relative_boot_id(j, &arg_boot_id, arg_boot_offset);
981 if (sd_id128_equal(arg_boot_id, SD_ID128_NULL))
982 log_error("Failed to look up boot %+i: %s", arg_boot_offset, strerror(-r));
984 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
985 SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r));
989 sd_id128_to_string(arg_boot_id, match + 9);
991 r = sd_journal_add_match(j, match, sizeof(match) - 1);
993 log_error("Failed to add match: %s", strerror(-r));
997 r = sd_journal_add_conjunction(j);
1004 static int add_dmesg(sd_journal *j) {
1011 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
1013 log_error("Failed to add match: %s", strerror(-r));
1017 r = sd_journal_add_conjunction(j);
1024 static int get_possible_units(sd_journal *j,
1028 _cleanup_set_free_free_ Set *found;
1032 found = set_new(string_hash_func, string_compare_func);
1036 NULSTR_FOREACH(field, fields) {
1040 r = sd_journal_query_unique(j, field);
1044 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1045 char **pattern, *eq;
1047 _cleanup_free_ char *u = NULL;
1049 eq = memchr(data, '=', size);
1051 prefix = eq - (char*) data + 1;
1055 u = strndup((char*) data + prefix, size - prefix);
1059 STRV_FOREACH(pattern, patterns)
1060 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1061 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1063 r = set_consume(found, u);
1065 if (r < 0 && r != -EEXIST)
1078 /* This list is supposed to return the superset of unit names
1079 * possibly matched by rules added with add_matches_for_unit... */
1080 #define SYSTEM_UNITS \
1084 "OBJECT_SYSTEMD_UNIT\0" \
1087 /* ... and add_matches_for_user_unit */
1088 #define USER_UNITS \
1089 "_SYSTEMD_USER_UNIT\0" \
1091 "COREDUMP_USER_UNIT\0" \
1092 "OBJECT_SYSTEMD_USER_UNIT\0"
1094 static int add_units(sd_journal *j) {
1095 _cleanup_strv_free_ char **patterns = NULL;
1101 STRV_FOREACH(i, arg_system_units) {
1102 _cleanup_free_ char *u = NULL;
1104 u = unit_name_mangle(*i, MANGLE_GLOB);
1108 if (string_is_glob(u)) {
1109 r = strv_push(&patterns, u);
1114 r = add_matches_for_unit(j, u);
1117 r = sd_journal_add_disjunction(j);
1124 if (!strv_isempty(patterns)) {
1125 _cleanup_set_free_free_ Set *units = NULL;
1129 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
1133 SET_FOREACH(u, units, it) {
1134 r = add_matches_for_unit(j, u);
1137 r = sd_journal_add_disjunction(j);
1144 strv_free(patterns);
1147 STRV_FOREACH(i, arg_user_units) {
1148 _cleanup_free_ char *u = NULL;
1150 u = unit_name_mangle(*i, MANGLE_GLOB);
1154 if (string_is_glob(u)) {
1155 r = strv_push(&patterns, u);
1160 r = add_matches_for_user_unit(j, u, getuid());
1163 r = sd_journal_add_disjunction(j);
1170 if (!strv_isempty(patterns)) {
1171 _cleanup_set_free_free_ Set *units = NULL;
1175 r = get_possible_units(j, USER_UNITS, patterns, &units);
1179 SET_FOREACH(u, units, it) {
1180 r = add_matches_for_user_unit(j, u, getuid());
1183 r = sd_journal_add_disjunction(j);
1190 /* Complain if the user request matches but nothing whatsoever was
1191 * found, since otherwise everything would be matched. */
1192 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1195 r = sd_journal_add_conjunction(j);
1202 static int add_priorities(sd_journal *j) {
1203 char match[] = "PRIORITY=0";
1207 if (arg_priorities == 0xFF)
1210 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1211 if (arg_priorities & (1 << i)) {
1212 match[sizeof(match)-2] = '0' + i;
1214 r = sd_journal_add_match(j, match, strlen(match));
1216 log_error("Failed to add match: %s", strerror(-r));
1221 r = sd_journal_add_conjunction(j);
1229 static int add_syslog_identifier(sd_journal *j) {
1235 STRV_FOREACH(i, arg_syslog_identifier) {
1238 u = strappenda("SYSLOG_IDENTIFIER=", *i);
1239 r = sd_journal_add_match(j, u, 0);
1242 r = sd_journal_add_disjunction(j);
1247 r = sd_journal_add_conjunction(j);
1254 static int setup_keys(void) {
1256 size_t mpk_size, seed_size, state_size, i;
1257 uint8_t *mpk, *seed, *state;
1259 int fd = -1, r, attr = 0;
1260 sd_id128_t machine, boot;
1261 char *p = NULL, *k = NULL;
1266 r = stat("/var/log/journal", &st);
1267 if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
1268 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
1272 if (r < 0 || !S_ISDIR(st.st_mode)) {
1273 log_error("%s is not a directory, must be using persistent logging for FSS.",
1274 "/var/log/journal");
1275 return r < 0 ? -errno : -ENOTDIR;
1278 r = sd_id128_get_machine(&machine);
1280 log_error("Failed to get machine ID: %s", strerror(-r));
1284 r = sd_id128_get_boot(&boot);
1286 log_error("Failed to get boot ID: %s", strerror(-r));
1290 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
1291 SD_ID128_FORMAT_VAL(machine)) < 0)
1294 if (access(p, F_OK) >= 0) {
1298 log_error("unlink(\"%s\") failed: %m", p);
1303 log_error("Sealing key file %s exists already. (--force to recreate)", p);
1309 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
1310 SD_ID128_FORMAT_VAL(machine)) < 0) {
1315 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1316 mpk = alloca(mpk_size);
1318 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1319 seed = alloca(seed_size);
1321 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1322 state = alloca(state_size);
1324 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1326 log_error("Failed to open /dev/random: %m");
1331 log_info("Generating seed...");
1332 l = loop_read(fd, seed, seed_size, true);
1333 if (l < 0 || (size_t) l != seed_size) {
1334 log_error("Failed to read random seed: %s", strerror(EIO));
1339 log_info("Generating key pair...");
1340 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1342 log_info("Generating sealing key...");
1343 FSPRG_GenState0(state, mpk, seed, seed_size);
1345 assert(arg_interval > 0);
1347 n = now(CLOCK_REALTIME);
1351 fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
1353 log_error("Failed to open %s: %m", k);
1358 /* Enable secure remove, exclusion from dump, synchronous
1359 * writing and in-place updating */
1360 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
1361 log_warning("FS_IOC_GETFLAGS failed: %m");
1363 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
1365 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
1366 log_warning("FS_IOC_SETFLAGS failed: %m");
1369 memcpy(h.signature, "KSHHRHLP", 8);
1370 h.machine_id = machine;
1372 h.header_size = htole64(sizeof(h));
1373 h.start_usec = htole64(n * arg_interval);
1374 h.interval_usec = htole64(arg_interval);
1375 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1376 h.fsprg_state_size = htole64(state_size);
1378 l = loop_write(fd, &h, sizeof(h), false);
1379 if (l < 0 || (size_t) l != sizeof(h)) {
1380 log_error("Failed to write header: %s", strerror(EIO));
1385 l = loop_write(fd, state, state_size, false);
1386 if (l < 0 || (size_t) l != state_size) {
1387 log_error("Failed to write state: %s", strerror(EIO));
1392 if (link(k, p) < 0) {
1393 log_error("Failed to link file: %m");
1401 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
1402 "the following local file. This key file is automatically updated when the\n"
1403 "sealing key is advanced. It should not be used on multiple hosts.\n"
1407 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1408 "at a safe location and should not be saved locally on disk.\n"
1409 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1412 for (i = 0; i < seed_size; i++) {
1413 if (i > 0 && i % 3 == 0)
1415 printf("%02x", ((uint8_t*) seed)[i]);
1418 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1421 char tsb[FORMAT_TIMESPAN_MAX], *hn;
1424 ANSI_HIGHLIGHT_OFF "\n"
1425 "The sealing key is automatically changed every %s.\n",
1426 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
1428 hn = gethostname_malloc();
1431 hostname_cleanup(hn, false);
1432 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
1434 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
1436 #ifdef HAVE_QRENCODE
1437 /* If this is not an UTF-8 system don't print any QR codes */
1438 if (is_locale_utf8()) {
1439 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1440 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1460 log_error("Forward-secure sealing not available.");
1465 static int verify(sd_journal *j) {
1472 log_show_color(true);
1474 HASHMAP_FOREACH(f, j->files, i) {
1476 usec_t first, validated, last;
1479 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
1480 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
1483 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
1485 /* If the key was invalid give up right-away. */
1488 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
1491 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
1492 log_info("PASS: %s", f->path);
1494 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
1495 if (validated > 0) {
1496 log_info("=> Validated from %s to %s, final %s entries not sealed.",
1497 format_timestamp(a, sizeof(a), first),
1498 format_timestamp(b, sizeof(b), validated),
1499 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
1500 } else if (last > 0)
1501 log_info("=> No sealing yet, %s of entries not sealed.",
1502 format_timespan(c, sizeof(c), last - first, 0));
1504 log_info("=> No sealing yet, no entries in file.");
1513 static int access_check_var_log_journal(sd_journal *j) {
1514 _cleanup_strv_free_ char **g = NULL;
1520 have_access = in_group("systemd-journal") > 0;
1523 /* Let's enumerate all groups from the default ACL of
1524 * the directory, which generally should allow access
1525 * to most journal files too */
1526 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
1533 if (strv_isempty(g))
1534 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1535 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1536 " turn off this notice.");
1538 _cleanup_free_ char *s = NULL;
1540 r = strv_extend(&g, "systemd-journal");
1547 s = strv_join(g, "', '");
1551 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1552 " Users in the groups '%s' can see all messages.\n"
1553 " Pass -q to turn off this notice.", s);
1561 static int access_check(sd_journal *j) {
1568 if (set_isempty(j->errors)) {
1569 if (hashmap_isempty(j->files))
1570 log_notice("No journal files were found.");
1574 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
1576 /* If /var/log/journal doesn't even exist,
1577 * unprivileged users have no access at all */
1578 if (access("/var/log/journal", F_OK) < 0 &&
1580 in_group("systemd-journal") <= 0) {
1581 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1582 "enabled. Users in the 'systemd-journal' group may always access messages.");
1586 /* If /var/log/journal exists, try to pring a nice
1587 notice if the user lacks access to it */
1588 if (!arg_quiet && geteuid() != 0) {
1589 r = access_check_var_log_journal(j);
1594 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1595 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1596 "group may access messages.");
1601 if (hashmap_isempty(j->files)) {
1602 log_error("No journal files were opened due to insufficient permissions.");
1607 SET_FOREACH(code, j->errors, it) {
1610 err = -PTR_TO_INT(code);
1614 log_warning("Error was encountered while opening journal files: %s",
1621 int main(int argc, char *argv[]) {
1623 _cleanup_journal_close_ sd_journal *j = NULL;
1624 bool need_seek = false;
1625 sd_id128_t previous_boot_id;
1626 bool previous_boot_id_valid = false, first_line = true;
1628 bool ellipsized = false;
1630 setlocale(LC_ALL, "");
1631 log_parse_environment();
1634 r = parse_argv(argc, argv);
1638 signal(SIGWINCH, columns_lines_cache_reset);
1640 if (arg_action == ACTION_NEW_ID128) {
1641 r = generate_new_id128();
1645 if (arg_action == ACTION_SETUP_KEYS) {
1650 if (arg_action == ACTION_UPDATE_CATALOG ||
1651 arg_action == ACTION_LIST_CATALOG ||
1652 arg_action == ACTION_DUMP_CATALOG) {
1654 _cleanup_free_ char *database;
1656 database = path_join(arg_root, CATALOG_DATABASE, NULL);
1662 if (arg_action == ACTION_UPDATE_CATALOG) {
1663 r = catalog_update(database, arg_root, catalog_file_dirs);
1665 log_error("Failed to list catalog: %s", strerror(-r));
1667 bool oneline = arg_action == ACTION_LIST_CATALOG;
1670 r = catalog_list_items(stdout, database,
1671 oneline, argv + optind);
1673 r = catalog_list(stdout, database, oneline);
1675 log_error("Failed to list catalog: %s", strerror(-r));
1682 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
1684 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
1685 else if (arg_machine)
1686 r = sd_journal_open_container(&j, arg_machine, 0);
1688 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
1690 log_error("Failed to open %s: %s",
1691 arg_directory ? arg_directory : arg_file ? "files" : "journal",
1693 return EXIT_FAILURE;
1696 r = access_check(j);
1698 return EXIT_FAILURE;
1700 if (arg_action == ACTION_VERIFY) {
1705 if (arg_action == ACTION_PRINT_HEADER) {
1706 journal_print_header(j);
1707 return EXIT_SUCCESS;
1710 if (arg_action == ACTION_DISK_USAGE) {
1712 char sbytes[FORMAT_BYTES_MAX];
1714 r = sd_journal_get_usage(j, &bytes);
1716 return EXIT_FAILURE;
1718 printf("Journals take up %s on disk.\n",
1719 format_bytes(sbytes, sizeof(sbytes), bytes));
1720 return EXIT_SUCCESS;
1723 if (arg_action == ACTION_LIST_BOOTS) {
1728 /* add_boot() must be called first!
1729 * It may need to seek the journal to find parent boot IDs. */
1732 return EXIT_FAILURE;
1736 return EXIT_FAILURE;
1739 strv_free(arg_system_units);
1740 strv_free(arg_user_units);
1743 log_error("Failed to add filter for units: %s", strerror(-r));
1744 return EXIT_FAILURE;
1747 r = add_syslog_identifier(j);
1749 log_error("Failed to add filter for syslog identifiers: %s", strerror(-r));
1750 return EXIT_FAILURE;
1753 r = add_priorities(j);
1755 log_error("Failed to add filter for priorities: %s", strerror(-r));
1756 return EXIT_FAILURE;
1759 r = add_matches(j, argv + optind);
1761 log_error("Failed to add filters: %s", strerror(-r));
1762 return EXIT_FAILURE;
1765 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1766 _cleanup_free_ char *filter;
1768 filter = journal_make_match_string(j);
1769 log_debug("Journal filter: %s", filter);
1776 r = sd_journal_set_data_threshold(j, 0);
1778 log_error("Failed to unset data size threshold");
1779 return EXIT_FAILURE;
1782 r = sd_journal_query_unique(j, arg_field);
1784 log_error("Failed to query unique data objects: %s", strerror(-r));
1785 return EXIT_FAILURE;
1788 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1791 if (arg_lines >= 0 && n_shown >= arg_lines)
1794 eq = memchr(data, '=', size);
1796 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1798 printf("%.*s\n", (int) size, (const char*) data);
1803 return EXIT_SUCCESS;
1806 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1808 r = sd_journal_get_fd(j);
1810 return EXIT_FAILURE;
1813 if (arg_cursor || arg_after_cursor) {
1814 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
1816 log_error("Failed to seek to cursor: %s", strerror(-r));
1817 return EXIT_FAILURE;
1820 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
1822 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
1824 if (arg_after_cursor && r < 2 && !arg_follow)
1825 /* We couldn't find the next entry after the cursor. */
1828 } else if (arg_since_set && !arg_reverse) {
1829 r = sd_journal_seek_realtime_usec(j, arg_since);
1831 log_error("Failed to seek to date: %s", strerror(-r));
1832 return EXIT_FAILURE;
1834 r = sd_journal_next(j);
1836 } else if (arg_until_set && arg_reverse) {
1837 r = sd_journal_seek_realtime_usec(j, arg_until);
1839 log_error("Failed to seek to date: %s", strerror(-r));
1840 return EXIT_FAILURE;
1842 r = sd_journal_previous(j);
1844 } else if (arg_lines >= 0) {
1845 r = sd_journal_seek_tail(j);
1847 log_error("Failed to seek to tail: %s", strerror(-r));
1848 return EXIT_FAILURE;
1851 r = sd_journal_previous_skip(j, arg_lines);
1853 } else if (arg_reverse) {
1854 r = sd_journal_seek_tail(j);
1856 log_error("Failed to seek to tail: %s", strerror(-r));
1857 return EXIT_FAILURE;
1860 r = sd_journal_previous(j);
1863 r = sd_journal_seek_head(j);
1865 log_error("Failed to seek to head: %s", strerror(-r));
1866 return EXIT_FAILURE;
1869 r = sd_journal_next(j);
1873 log_error("Failed to iterate through journal: %s", strerror(-r));
1874 return EXIT_FAILURE;
1878 pager_open_if_enabled();
1882 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1884 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1886 log_error("Failed to get cutoff: %s", strerror(-r));
1892 printf("-- Logs begin at %s. --\n",
1893 format_timestamp(start_buf, sizeof(start_buf), start));
1895 printf("-- Logs begin at %s, end at %s. --\n",
1896 format_timestamp(start_buf, sizeof(start_buf), start),
1897 format_timestamp(end_buf, sizeof(end_buf), end));
1902 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1907 r = sd_journal_next(j);
1909 r = sd_journal_previous(j);
1911 log_error("Failed to iterate through journal: %s", strerror(-r));
1918 if (arg_until_set && !arg_reverse) {
1921 r = sd_journal_get_realtime_usec(j, &usec);
1923 log_error("Failed to determine timestamp: %s", strerror(-r));
1926 if (usec > arg_until)
1930 if (arg_since_set && arg_reverse) {
1933 r = sd_journal_get_realtime_usec(j, &usec);
1935 log_error("Failed to determine timestamp: %s", strerror(-r));
1938 if (usec < arg_since)
1945 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1947 if (previous_boot_id_valid &&
1948 !sd_id128_equal(boot_id, previous_boot_id))
1949 printf("%s-- Reboot --%s\n",
1950 ansi_highlight(), ansi_highlight_off());
1952 previous_boot_id = boot_id;
1953 previous_boot_id_valid = true;
1958 arg_all * OUTPUT_SHOW_ALL |
1959 arg_full * OUTPUT_FULL_WIDTH |
1960 on_tty() * OUTPUT_COLOR |
1961 arg_catalog * OUTPUT_CATALOG;
1963 r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
1965 if (r == -EADDRNOTAVAIL)
1967 else if (r < 0 || ferror(stdout))
1974 if (arg_show_cursor) {
1975 _cleanup_free_ char *cursor = NULL;
1977 r = sd_journal_get_cursor(j, &cursor);
1978 if (r < 0 && r != -EADDRNOTAVAIL)
1979 log_error("Failed to get cursor: %s", strerror(-r));
1981 printf("-- cursor: %s\n", cursor);
1987 r = sd_journal_wait(j, (uint64_t) -1);
1989 log_error("Couldn't wait for journal event: %s", strerror(-r));
1999 strv_free(arg_file);
2001 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;