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"
50 #include "logs-show.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"
58 #include "unit-name.h"
61 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
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 = false;
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_this_boot = false;
74 static bool arg_dmesg = false;
75 static const char *arg_cursor = NULL;
76 static const char *arg_directory = NULL;
77 static char **arg_file = NULL;
78 static int arg_priorities = 0xFF;
79 static const char *arg_verify_key = NULL;
81 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
83 static usec_t arg_since, arg_until;
84 static bool arg_since_set = false, arg_until_set = false;
85 static char **arg_system_units = NULL;
86 static char **arg_user_units = NULL;
87 static const char *arg_field = NULL;
88 static bool arg_catalog = false;
89 static bool arg_reverse = false;
90 static int arg_journal_type = 0;
91 static const char *arg_root = NULL;
102 ACTION_UPDATE_CATALOG
103 } arg_action = ACTION_SHOW;
105 static int help(void) {
107 printf("%s [OPTIONS...] [MATCHES...]\n\n"
108 "Query the journal.\n\n"
110 " --system Show only the system journal\n"
111 " --user Show only the user journal for current user\n"
112 " --since=DATE Start showing entries newer or of the specified date\n"
113 " --until=DATE Stop showing entries older or of the specified date\n"
114 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
115 " -b --this-boot Show data only from current boot\n"
116 " -k --dmesg Show kmsg log from current boot\n"
117 " -u --unit=UNIT Show data only from the specified unit\n"
118 " --user-unit=UNIT Show data only from the specified user session unit\n"
119 " -p --priority=RANGE Show only messages within the specified priority range\n"
120 " -e --pager-end Immediately jump to end of the journal in the pager\n"
121 " -f --follow Follow journal\n"
122 " -n --lines[=INTEGER] Number of journal entries to show\n"
123 " --no-tail Show all lines, even in follow mode\n"
124 " -r --reverse Show the newest entries first\n"
125 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
126 " verbose, export, json, json-pretty, json-sse, cat)\n"
127 " -x --catalog Add message explanations where available\n"
128 " -l --full Do not ellipsize fields\n"
129 " -a --all Show all fields, including long and unprintable\n"
130 " -q --quiet Don't show privilege warning\n"
131 " --no-pager Do not pipe output into a pager\n"
132 " -m --merge Show entries from all available journals\n"
133 " -D --directory=PATH Show journal files from directory\n"
134 " --file=PATH Show journal file\n"
135 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
137 " --interval=TIME Time interval for changing the FSS sealing key\n"
138 " --verify-key=KEY Specify FSS verification key\n"
141 " -h --help Show this help\n"
142 " --version Show package version\n"
143 " --new-id128 Generate a new 128 Bit ID\n"
144 " --header Show journal header information\n"
145 " --disk-usage Show total disk usage\n"
146 " -F --field=FIELD List all values a certain field takes\n"
147 " --list-catalog Show message IDs of all entries in the message catalog\n"
148 " --dump-catalog Show entries in the message catalog\n"
149 " --update-catalog Update the message catalog database\n"
151 " --setup-keys Generate new FSS key pair\n"
152 " --verify Verify journal file consistency\n"
154 , program_invocation_short_name);
159 static int parse_argv(int argc, char *argv[]) {
184 static const struct option options[] = {
185 { "help", no_argument, NULL, 'h' },
186 { "version" , no_argument, NULL, ARG_VERSION },
187 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
188 { "pager-end", no_argument, NULL, 'e' },
189 { "follow", no_argument, NULL, 'f' },
190 { "output", required_argument, NULL, 'o' },
191 { "all", no_argument, NULL, 'a' },
192 { "full", no_argument, NULL, 'l' },
193 { "lines", optional_argument, NULL, 'n' },
194 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
195 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
196 { "quiet", no_argument, NULL, 'q' },
197 { "merge", no_argument, NULL, 'm' },
198 { "this-boot", no_argument, NULL, 'b' },
199 { "dmesg", no_argument, NULL, 'k' },
200 { "system", no_argument, NULL, ARG_SYSTEM },
201 { "user", no_argument, NULL, ARG_USER },
202 { "directory", required_argument, NULL, 'D' },
203 { "file", required_argument, NULL, ARG_FILE },
204 { "root", required_argument, NULL, ARG_ROOT },
205 { "header", no_argument, NULL, ARG_HEADER },
206 { "priority", required_argument, NULL, 'p' },
207 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
208 { "interval", required_argument, NULL, ARG_INTERVAL },
209 { "verify", no_argument, NULL, ARG_VERIFY },
210 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
211 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
212 { "cursor", required_argument, NULL, 'c' },
213 { "since", required_argument, NULL, ARG_SINCE },
214 { "until", required_argument, NULL, ARG_UNTIL },
215 { "unit", required_argument, NULL, 'u' },
216 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
217 { "field", required_argument, NULL, 'F' },
218 { "catalog", no_argument, NULL, 'x' },
219 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
220 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
221 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
222 { "reverse", no_argument, NULL, 'r' },
231 while ((c = getopt_long(argc, argv, "hefo:aln::qmbkD:p:c:u:F:xr", options, NULL)) >= 0) {
240 puts(PACKAGE_STRING);
241 puts(SYSTEMD_FEATURES);
249 arg_pager_end = true;
261 arg_output = output_mode_from_string(optarg);
262 if (arg_output < 0) {
263 log_error("Unknown output format '%s'.", optarg);
267 if (arg_output == OUTPUT_EXPORT ||
268 arg_output == OUTPUT_JSON ||
269 arg_output == OUTPUT_JSON_PRETTY ||
270 arg_output == OUTPUT_JSON_SSE ||
271 arg_output == OUTPUT_CAT)
286 r = safe_atoi(optarg, &arg_lines);
287 if (r < 0 || arg_lines < 0) {
288 log_error("Failed to parse lines '%s'", optarg);
294 /* Hmm, no argument? Maybe the next
295 * word on the command line is
296 * supposed to be the argument? Let's
297 * see if there is one, and is
298 * parsable as a positive
302 safe_atoi(argv[optind], &n) >= 0 &&
318 arg_action = ACTION_NEW_ID128;
330 arg_this_boot = true;
334 arg_this_boot = arg_dmesg = true;
338 arg_journal_type |= SD_JOURNAL_SYSTEM;
342 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
346 arg_directory = optarg;
350 r = glob_extend(&arg_file, optarg);
352 log_error("Failed to add paths: %s", strerror(-r));
366 arg_action = ACTION_PRINT_HEADER;
370 arg_action = ACTION_VERIFY;
374 arg_action = ACTION_DISK_USAGE;
379 arg_action = ACTION_SETUP_KEYS;
384 arg_action = ACTION_VERIFY;
385 arg_verify_key = optarg;
390 r = parse_sec(optarg, &arg_interval);
391 if (r < 0 || arg_interval <= 0) {
392 log_error("Failed to parse sealing key change interval: %s", optarg);
400 log_error("Forward-secure sealing not available.");
407 dots = strstr(optarg, "..");
413 a = strndup(optarg, dots - optarg);
417 from = log_level_from_string(a);
418 to = log_level_from_string(dots + 2);
421 if (from < 0 || to < 0) {
422 log_error("Failed to parse log level range %s", optarg);
429 for (i = from; i <= to; i++)
430 arg_priorities |= 1 << i;
432 for (i = to; i <= from; i++)
433 arg_priorities |= 1 << i;
439 p = log_level_from_string(optarg);
441 log_error("Unknown log level %s", optarg);
447 for (i = 0; i <= p; i++)
448 arg_priorities |= 1 << i;
455 r = parse_timestamp(optarg, &arg_since);
457 log_error("Failed to parse timestamp: %s", optarg);
460 arg_since_set = true;
464 r = parse_timestamp(optarg, &arg_until);
466 log_error("Failed to parse timestamp: %s", optarg);
469 arg_until_set = true;
473 r = strv_extend(&arg_system_units, optarg);
479 r = strv_extend(&arg_user_units, optarg);
495 case ARG_LIST_CATALOG:
496 arg_action = ACTION_LIST_CATALOG;
499 case ARG_DUMP_CATALOG:
500 arg_action = ACTION_DUMP_CATALOG;
503 case ARG_UPDATE_CATALOG:
504 arg_action = ACTION_UPDATE_CATALOG;
512 log_error("Unknown option code %c", c);
517 if (arg_follow && !arg_no_tail && arg_lines < 0)
520 if (arg_directory && arg_file) {
521 log_error("Please specify either -D/--directory= or --file=, not both.");
525 if (arg_since_set && arg_until_set && arg_since > arg_until) {
526 log_error("--since= must be before --until=.");
530 if (arg_cursor && arg_since_set) {
531 log_error("Please specify either --since= or --cursor=, not both.");
535 if (arg_follow && arg_reverse) {
536 log_error("Please specify either --reverse= or --follow=, not both.");
543 static int generate_new_id128(void) {
548 r = sd_id128_randomize(&id);
550 log_error("Failed to generate ID: %s", strerror(-r));
554 printf("As string:\n"
555 SD_ID128_FORMAT_STR "\n\n"
557 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
559 "#define MESSAGE_XYZ SD_ID128_MAKE(",
560 SD_ID128_FORMAT_VAL(id),
561 SD_ID128_FORMAT_VAL(id));
562 for (i = 0; i < 16; i++)
563 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
564 fputs(")\n\n", stdout);
566 printf("As Python constant:\n"
568 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
569 SD_ID128_FORMAT_VAL(id));
574 static int add_matches(sd_journal *j, char **args) {
579 STRV_FOREACH(i, args) {
583 r = sd_journal_add_disjunction(j);
584 else if (path_is_absolute(*i)) {
585 _cleanup_free_ char *p, *t = NULL;
589 p = canonicalize_file_name(*i);
592 if (stat(path, &st) < 0) {
593 log_error("Couldn't stat file: %m");
597 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
598 t = strappend("_EXE=", path);
599 else if (S_ISCHR(st.st_mode))
600 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
601 else if (S_ISBLK(st.st_mode))
602 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
604 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
611 r = sd_journal_add_match(j, t, 0);
613 r = sd_journal_add_match(j, *i, 0);
616 log_error("Failed to add match '%s': %s", *i, strerror(-r));
624 static int add_this_boot(sd_journal *j) {
628 return add_match_this_boot(j);
631 static int add_dmesg(sd_journal *j) {
638 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
640 log_error("Failed to add match: %s", strerror(-r));
644 r = sd_journal_add_conjunction(j);
651 static int add_units(sd_journal *j) {
652 _cleanup_free_ char *u = NULL;
658 STRV_FOREACH(i, arg_system_units) {
659 u = unit_name_mangle(*i);
662 r = add_matches_for_unit(j, u);
665 r = sd_journal_add_disjunction(j);
670 STRV_FOREACH(i, arg_user_units) {
671 u = unit_name_mangle(*i);
675 r = add_matches_for_user_unit(j, u, getuid());
679 r = sd_journal_add_disjunction(j);
685 r = sd_journal_add_conjunction(j);
692 static int add_priorities(sd_journal *j) {
693 char match[] = "PRIORITY=0";
697 if (arg_priorities == 0xFF)
700 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
701 if (arg_priorities & (1 << i)) {
702 match[sizeof(match)-2] = '0' + i;
704 r = sd_journal_add_match(j, match, strlen(match));
706 log_error("Failed to add match: %s", strerror(-r));
711 r = sd_journal_add_conjunction(j);
718 static int setup_keys(void) {
720 size_t mpk_size, seed_size, state_size, i;
721 uint8_t *mpk, *seed, *state;
723 int fd = -1, r, attr = 0;
724 sd_id128_t machine, boot;
725 char *p = NULL, *k = NULL;
730 r = stat("/var/log/journal", &st);
731 if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
732 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
736 if (r < 0 || !S_ISDIR(st.st_mode)) {
737 log_error("%s is not a directory, must be using persistent logging for FSS.",
739 return r < 0 ? -errno : -ENOTDIR;
742 r = sd_id128_get_machine(&machine);
744 log_error("Failed to get machine ID: %s", strerror(-r));
748 r = sd_id128_get_boot(&boot);
750 log_error("Failed to get boot ID: %s", strerror(-r));
754 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
755 SD_ID128_FORMAT_VAL(machine)) < 0)
758 if (access(p, F_OK) >= 0) {
759 log_error("Sealing key file %s exists already.", p);
764 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
765 SD_ID128_FORMAT_VAL(machine)) < 0) {
770 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
771 mpk = alloca(mpk_size);
773 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
774 seed = alloca(seed_size);
776 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
777 state = alloca(state_size);
779 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
781 log_error("Failed to open /dev/random: %m");
786 log_info("Generating seed...");
787 l = loop_read(fd, seed, seed_size, true);
788 if (l < 0 || (size_t) l != seed_size) {
789 log_error("Failed to read random seed: %s", strerror(EIO));
794 log_info("Generating key pair...");
795 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
797 log_info("Generating sealing key...");
798 FSPRG_GenState0(state, mpk, seed, seed_size);
800 assert(arg_interval > 0);
802 n = now(CLOCK_REALTIME);
805 close_nointr_nofail(fd);
806 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
808 log_error("Failed to open %s: %m", k);
813 /* Enable secure remove, exclusion from dump, synchronous
814 * writing and in-place updating */
815 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
816 log_warning("FS_IOC_GETFLAGS failed: %m");
818 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
820 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
821 log_warning("FS_IOC_SETFLAGS failed: %m");
824 memcpy(h.signature, "KSHHRHLP", 8);
825 h.machine_id = machine;
827 h.header_size = htole64(sizeof(h));
828 h.start_usec = htole64(n * arg_interval);
829 h.interval_usec = htole64(arg_interval);
830 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
831 h.fsprg_state_size = htole64(state_size);
833 l = loop_write(fd, &h, sizeof(h), false);
834 if (l < 0 || (size_t) l != sizeof(h)) {
835 log_error("Failed to write header: %s", strerror(EIO));
840 l = loop_write(fd, state, state_size, false);
841 if (l < 0 || (size_t) l != state_size) {
842 log_error("Failed to write state: %s", strerror(EIO));
847 if (link(k, p) < 0) {
848 log_error("Failed to link file: %m");
856 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
857 "the following local file. This key file is automatically updated when the\n"
858 "sealing key is advanced. It should not be used on multiple hosts.\n"
862 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
863 "at a safe location and should not be saved locally on disk.\n"
864 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
867 for (i = 0; i < seed_size; i++) {
868 if (i > 0 && i % 3 == 0)
870 printf("%02x", ((uint8_t*) seed)[i]);
873 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
876 char tsb[FORMAT_TIMESPAN_MAX], *hn;
879 ANSI_HIGHLIGHT_OFF "\n"
880 "The sealing key is automatically changed every %s.\n",
881 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
883 hn = gethostname_malloc();
886 hostname_cleanup(hn, false);
887 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
889 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
892 /* If this is not an UTF-8 system don't print any QR codes */
893 if (is_locale_utf8()) {
894 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
895 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
905 close_nointr_nofail(fd);
916 log_error("Forward-secure sealing not available.");
921 static int verify(sd_journal *j) {
928 log_show_color(true);
930 HASHMAP_FOREACH(f, j->files, i) {
932 usec_t first, validated, last;
935 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
936 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
939 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
941 /* If the key was invalid give up right-away. */
944 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
947 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
948 log_info("PASS: %s", f->path);
950 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
952 log_info("=> Validated from %s to %s, final %s entries not sealed.",
953 format_timestamp(a, sizeof(a), first),
954 format_timestamp(b, sizeof(b), validated),
955 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
957 log_info("=> No sealing yet, %s of entries not sealed.",
958 format_timespan(c, sizeof(c), last - first, 0));
960 log_info("=> No sealing yet, no entries in file.");
969 static int access_check_var_log_journal(sd_journal *j) {
970 _cleanup_strv_free_ char **g = NULL;
976 have_access = in_group("systemd-journal") > 0;
979 /* Let's enumerate all groups from the default ACL of
980 * the directory, which generally should allow access
981 * to most journal files too */
982 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
990 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
991 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
992 " turn off this notice.");
994 _cleanup_free_ char *s = NULL;
996 r = strv_extend(&g, "systemd-journal");
1003 s = strv_join(g, "', '");
1007 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1008 " Users in the groups '%s' can see all messages.\n"
1009 " Pass -q to turn off this notice.", s);
1017 static int access_check(sd_journal *j) {
1024 if (set_isempty(j->errors)) {
1025 if (hashmap_isempty(j->files))
1026 log_notice("No journal files were found.");
1030 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
1032 /* If /var/log/journal doesn't even exist,
1033 * unprivileged users have no access at all */
1034 if (access("/var/log/journal", F_OK) < 0 &&
1036 in_group("systemd-journal") <= 0) {
1037 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1038 "enabled. Users in the 'systemd-journal' group may always access messages.");
1042 /* If /var/log/journal exists, try to pring a nice
1043 notice if the user lacks access to it */
1044 if (!arg_quiet && geteuid() != 0) {
1045 r = access_check_var_log_journal(j);
1050 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1051 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1052 "group may access messages.");
1057 if (hashmap_isempty(j->files)) {
1058 log_error("No journal files were opened due to insufficient permissions.");
1063 SET_FOREACH(code, j->errors, it) {
1066 err = -PTR_TO_INT(code);
1070 log_warning("Error was encountered while opening journal files: %s",
1077 int main(int argc, char *argv[]) {
1079 _cleanup_journal_close_ sd_journal*j = NULL;
1080 bool need_seek = false;
1081 sd_id128_t previous_boot_id;
1082 bool previous_boot_id_valid = false, first_line = true;
1085 setlocale(LC_ALL, "");
1086 log_parse_environment();
1089 r = parse_argv(argc, argv);
1093 signal(SIGWINCH, columns_lines_cache_reset);
1095 if (arg_action == ACTION_NEW_ID128) {
1096 r = generate_new_id128();
1100 if (arg_action == ACTION_SETUP_KEYS) {
1105 if (arg_action == ACTION_UPDATE_CATALOG ||
1106 arg_action == ACTION_LIST_CATALOG ||
1107 arg_action == ACTION_DUMP_CATALOG) {
1109 const char* database = CATALOG_DATABASE;
1110 _cleanup_free_ char *copy = NULL;
1112 copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1117 path_kill_slashes(copy);
1121 if (arg_action == ACTION_UPDATE_CATALOG) {
1122 r = catalog_update(database, arg_root, catalog_file_dirs);
1124 log_error("Failed to list catalog: %s", strerror(-r));
1126 bool oneline = arg_action == ACTION_LIST_CATALOG;
1129 r = catalog_list_items(stdout, database,
1130 oneline, argv + optind);
1132 r = catalog_list(stdout, database, oneline);
1134 log_error("Failed to list catalog: %s", strerror(-r));
1141 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
1143 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
1145 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
1147 log_error("Failed to open %s: %s",
1148 arg_directory ? arg_directory : arg_file ? "files" : "journal",
1150 return EXIT_FAILURE;
1153 r = access_check(j);
1155 return EXIT_FAILURE;
1157 if (arg_action == ACTION_VERIFY) {
1162 if (arg_action == ACTION_PRINT_HEADER) {
1163 journal_print_header(j);
1164 return EXIT_SUCCESS;
1167 if (arg_action == ACTION_DISK_USAGE) {
1169 char sbytes[FORMAT_BYTES_MAX];
1171 r = sd_journal_get_usage(j, &bytes);
1173 return EXIT_FAILURE;
1175 printf("Journals take up %s on disk.\n",
1176 format_bytes(sbytes, sizeof(sbytes), bytes));
1177 return EXIT_SUCCESS;
1180 r = add_this_boot(j);
1182 return EXIT_FAILURE;
1186 return EXIT_FAILURE;
1189 strv_free(arg_system_units);
1190 strv_free(arg_user_units);
1193 return EXIT_FAILURE;
1195 r = add_priorities(j);
1197 return EXIT_FAILURE;
1199 r = add_matches(j, argv + optind);
1201 return EXIT_FAILURE;
1203 log_debug("Journal filter: %s", j->level0 ? journal_make_match_string(j) : "none");
1209 r = sd_journal_set_data_threshold(j, 0);
1211 log_error("Failed to unset data size threshold");
1212 return EXIT_FAILURE;
1215 r = sd_journal_query_unique(j, arg_field);
1217 log_error("Failed to query unique data objects: %s", strerror(-r));
1218 return EXIT_FAILURE;
1221 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1224 if (arg_lines >= 0 && n_shown >= arg_lines)
1227 eq = memchr(data, '=', size);
1229 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1231 printf("%.*s\n", (int) size, (const char*) data);
1236 return EXIT_SUCCESS;
1239 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1241 r = sd_journal_get_fd(j);
1243 return EXIT_FAILURE;
1247 r = sd_journal_seek_cursor(j, arg_cursor);
1249 log_error("Failed to seek to cursor: %s", strerror(-r));
1250 return EXIT_FAILURE;
1253 r = sd_journal_next(j);
1255 r = sd_journal_previous(j);
1257 } else if (arg_since_set && !arg_reverse) {
1258 r = sd_journal_seek_realtime_usec(j, arg_since);
1260 log_error("Failed to seek to date: %s", strerror(-r));
1261 return EXIT_FAILURE;
1263 r = sd_journal_next(j);
1265 } else if (arg_until_set && arg_reverse) {
1266 r = sd_journal_seek_realtime_usec(j, arg_until);
1268 log_error("Failed to seek to date: %s", strerror(-r));
1269 return EXIT_FAILURE;
1271 r = sd_journal_previous(j);
1273 } else if (arg_lines >= 0) {
1274 r = sd_journal_seek_tail(j);
1276 log_error("Failed to seek to tail: %s", strerror(-r));
1277 return EXIT_FAILURE;
1280 r = sd_journal_previous_skip(j, arg_lines);
1282 } else if (arg_reverse) {
1283 r = sd_journal_seek_tail(j);
1285 log_error("Failed to seek to tail: %s", strerror(-r));
1286 return EXIT_FAILURE;
1289 r = sd_journal_previous(j);
1292 r = sd_journal_seek_head(j);
1294 log_error("Failed to seek to head: %s", strerror(-r));
1295 return EXIT_FAILURE;
1298 r = sd_journal_next(j);
1302 log_error("Failed to iterate through journal: %s", strerror(-r));
1303 return EXIT_FAILURE;
1306 if (!arg_no_pager && !arg_follow)
1307 pager_open(arg_pager_end);
1311 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1313 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1315 log_error("Failed to get cutoff: %s", strerror(-r));
1321 printf("-- Logs begin at %s. --\n",
1322 format_timestamp(start_buf, sizeof(start_buf), start));
1324 printf("-- Logs begin at %s, end at %s. --\n",
1325 format_timestamp(start_buf, sizeof(start_buf), start),
1326 format_timestamp(end_buf, sizeof(end_buf), end));
1331 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1336 r = sd_journal_next(j);
1338 r = sd_journal_previous(j);
1340 log_error("Failed to iterate through journal: %s", strerror(-r));
1347 if (arg_until_set && !arg_reverse) {
1350 r = sd_journal_get_realtime_usec(j, &usec);
1352 log_error("Failed to determine timestamp: %s", strerror(-r));
1355 if (usec > arg_until)
1359 if (arg_since_set && arg_reverse) {
1362 r = sd_journal_get_realtime_usec(j, &usec);
1364 log_error("Failed to determine timestamp: %s", strerror(-r));
1367 if (usec < arg_since)
1373 const char *color_on = on_tty() ? ANSI_HIGHLIGHT_ON : "",
1374 *color_off = on_tty() ? ANSI_HIGHLIGHT_OFF : "";
1376 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1378 if (previous_boot_id_valid &&
1379 !sd_id128_equal(boot_id, previous_boot_id))
1380 printf("%s-- Reboot --%s\n", color_on, color_off);
1382 previous_boot_id = boot_id;
1383 previous_boot_id_valid = true;
1388 arg_all * OUTPUT_SHOW_ALL |
1389 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1390 on_tty() * OUTPUT_COLOR |
1391 arg_catalog * OUTPUT_CATALOG;
1393 r = output_journal(stdout, j, arg_output, 0, flags);
1395 if (r == -EADDRNOTAVAIL)
1397 else if (r < 0 || ferror(stdout))
1406 r = sd_journal_wait(j, (uint64_t) -1);
1408 log_error("Couldn't wait for journal event: %s", strerror(-r));
1418 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;