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 const char *arg_cursor = NULL;
75 static const char *arg_directory = NULL;
76 static int arg_priorities = 0xFF;
77 static const char *arg_verify_key = NULL;
79 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
81 static usec_t arg_since, arg_until;
82 static bool arg_since_set = false, arg_until_set = false;
83 static const char *arg_unit = NULL;
84 static bool arg_unit_system;
85 static const char *arg_field = NULL;
86 static bool arg_catalog = false;
87 static bool arg_reverse = false;
88 static const char *arg_root = NULL;
100 } arg_action = ACTION_SHOW;
102 static int help(void) {
104 printf("%s [OPTIONS...] [MATCHES...]\n\n"
105 "Query the journal.\n\n"
107 " --since=DATE Start showing entries newer or of the specified date\n"
108 " --until=DATE Stop showing entries older or of the specified date\n"
109 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
110 " -b --this-boot Show data only from current boot\n"
111 " -u --unit=UNIT Show data only from the specified unit\n"
112 " --user-unit=UNIT Show data only from the specified user session unit\n"
113 " -p --priority=RANGE Show only messages within the specified priority range\n"
114 " -e --pager-end Immediately jump to end of the journal in the pager\n"
115 " -f --follow Follow journal\n"
116 " -n --lines[=INTEGER] Number of journal entries to show\n"
117 " --no-tail Show all lines, even in follow mode\n"
118 " -r --reverse Show the newest entries first\n"
119 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
120 " verbose, export, json, json-pretty, json-sse, cat)\n"
121 " -x --catalog Add message explanations where available\n"
122 " --full Do not ellipsize fields\n"
123 " -a --all Show all fields, including long and unprintable\n"
124 " -q --quiet Don't show privilege warning\n"
125 " --no-pager Do not pipe output into a pager\n"
126 " -m --merge Show entries from all available journals\n"
127 " -D --directory=PATH Show journal files from directory\n"
128 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
130 " --interval=TIME Time interval for changing the FSS sealing key\n"
131 " --verify-key=KEY Specify FSS verification key\n"
134 " -h --help Show this help\n"
135 " --version Show package version\n"
136 " --new-id128 Generate a new 128 Bit ID\n"
137 " --header Show journal header information\n"
138 " --disk-usage Show total disk usage\n"
139 " -F --field=FIELD List all values a certain field takes\n"
140 " --list-catalog Show message IDs of all entries in the message catalog\n"
141 " --dump-catalog Show entries in the message catalog\n"
142 " --update-catalog Update the message catalog database\n"
144 " --setup-keys Generate new FSS key pair\n"
145 " --verify Verify journal file consistency\n"
147 , program_invocation_short_name);
152 static int parse_argv(int argc, char *argv[]) {
175 static const struct option options[] = {
176 { "help", no_argument, NULL, 'h' },
177 { "version" , no_argument, NULL, ARG_VERSION },
178 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
179 { "pager-end", no_argument, NULL, 'e' },
180 { "follow", no_argument, NULL, 'f' },
181 { "output", required_argument, NULL, 'o' },
182 { "all", no_argument, NULL, 'a' },
183 { "full", no_argument, NULL, ARG_FULL },
184 { "lines", optional_argument, NULL, 'n' },
185 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
186 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
187 { "quiet", no_argument, NULL, 'q' },
188 { "merge", no_argument, NULL, 'm' },
189 { "this-boot", no_argument, NULL, 'b' },
190 { "directory", required_argument, NULL, 'D' },
191 { "root", required_argument, NULL, ARG_ROOT },
192 { "header", no_argument, NULL, ARG_HEADER },
193 { "priority", required_argument, NULL, 'p' },
194 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
195 { "interval", required_argument, NULL, ARG_INTERVAL },
196 { "verify", no_argument, NULL, ARG_VERIFY },
197 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
198 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
199 { "cursor", required_argument, NULL, 'c' },
200 { "since", required_argument, NULL, ARG_SINCE },
201 { "until", required_argument, NULL, ARG_UNTIL },
202 { "unit", required_argument, NULL, 'u' },
203 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
204 { "field", required_argument, NULL, 'F' },
205 { "catalog", no_argument, NULL, 'x' },
206 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
207 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
208 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
209 { "reverse", no_argument, NULL, 'r' },
218 while ((c = getopt_long(argc, argv, "hefo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) {
227 puts(PACKAGE_STRING);
228 puts(SYSTEMD_FEATURES);
236 arg_pager_end = true;
248 arg_output = output_mode_from_string(optarg);
249 if (arg_output < 0) {
250 log_error("Unknown output format '%s'.", optarg);
254 if (arg_output == OUTPUT_EXPORT ||
255 arg_output == OUTPUT_JSON ||
256 arg_output == OUTPUT_JSON_PRETTY ||
257 arg_output == OUTPUT_JSON_SSE ||
258 arg_output == OUTPUT_CAT)
273 r = safe_atoi(optarg, &arg_lines);
274 if (r < 0 || arg_lines < 0) {
275 log_error("Failed to parse lines '%s'", optarg);
281 /* Hmm, no argument? Maybe the next
282 * word on the command line is
283 * supposed to be the argument? Let's
284 * see if there is one, and is
285 * parsable as a positive
289 safe_atoi(argv[optind], &n) >= 0 &&
305 arg_action = ACTION_NEW_ID128;
317 arg_this_boot = true;
321 arg_directory = optarg;
333 arg_action = ACTION_PRINT_HEADER;
337 arg_action = ACTION_VERIFY;
341 arg_action = ACTION_DISK_USAGE;
346 arg_action = ACTION_SETUP_KEYS;
351 arg_action = ACTION_VERIFY;
352 arg_verify_key = optarg;
357 r = parse_sec(optarg, &arg_interval);
358 if (r < 0 || arg_interval <= 0) {
359 log_error("Failed to parse sealing key change interval: %s", optarg);
367 log_error("Forward-secure sealing not available.");
374 dots = strstr(optarg, "..");
380 a = strndup(optarg, dots - optarg);
384 from = log_level_from_string(a);
385 to = log_level_from_string(dots + 2);
388 if (from < 0 || to < 0) {
389 log_error("Failed to parse log level range %s", optarg);
396 for (i = from; i <= to; i++)
397 arg_priorities |= 1 << i;
399 for (i = to; i <= from; i++)
400 arg_priorities |= 1 << i;
406 p = log_level_from_string(optarg);
408 log_error("Unknown log level %s", optarg);
414 for (i = 0; i <= p; i++)
415 arg_priorities |= 1 << i;
422 r = parse_timestamp(optarg, &arg_since);
424 log_error("Failed to parse timestamp: %s", optarg);
427 arg_since_set = true;
431 r = parse_timestamp(optarg, &arg_until);
433 log_error("Failed to parse timestamp: %s", optarg);
436 arg_until_set = true;
441 arg_unit_system = true;
446 arg_unit_system = false;
460 case ARG_LIST_CATALOG:
461 arg_action = ACTION_LIST_CATALOG;
464 case ARG_DUMP_CATALOG:
465 arg_action = ACTION_DUMP_CATALOG;
468 case ARG_UPDATE_CATALOG:
469 arg_action = ACTION_UPDATE_CATALOG;
477 log_error("Unknown option code %c", c);
482 if (arg_follow && !arg_no_tail && arg_lines < 0)
485 if (arg_since_set && arg_until_set && arg_since > arg_until) {
486 log_error("--since= must be before --until=.");
490 if (arg_cursor && arg_since_set) {
491 log_error("Please specify either --since= or --cursor=, not both.");
495 if (arg_follow && arg_reverse) {
496 log_error("Please specify either --reverse= or --follow=, not both.");
503 static int generate_new_id128(void) {
508 r = sd_id128_randomize(&id);
510 log_error("Failed to generate ID: %s", strerror(-r));
514 printf("As string:\n"
515 SD_ID128_FORMAT_STR "\n\n"
517 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
519 "#define MESSAGE_XYZ SD_ID128_MAKE(",
520 SD_ID128_FORMAT_VAL(id),
521 SD_ID128_FORMAT_VAL(id));
522 for (i = 0; i < 16; i++)
523 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
524 fputs(")\n\n", stdout);
526 printf("As Python constant:\n"
528 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
529 SD_ID128_FORMAT_VAL(id));
534 static int add_matches(sd_journal *j, char **args) {
539 STRV_FOREACH(i, args) {
543 r = sd_journal_add_disjunction(j);
544 else if (path_is_absolute(*i)) {
545 char _cleanup_free_ *p, *t = NULL;
549 p = canonicalize_file_name(*i);
552 if (stat(path, &st) < 0) {
553 log_error("Couldn't stat file: %m");
557 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
558 t = strappend("_EXE=", path);
559 else if (S_ISCHR(st.st_mode))
560 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
561 else if (S_ISBLK(st.st_mode))
562 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
564 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
571 r = sd_journal_add_match(j, t, 0);
573 r = sd_journal_add_match(j, *i, 0);
576 log_error("Failed to add match '%s': %s", *i, strerror(-r));
584 static int add_this_boot(sd_journal *j) {
585 char match[9+32+1] = "_BOOT_ID=";
594 r = sd_id128_get_boot(&boot_id);
596 log_error("Failed to get boot id: %s", strerror(-r));
600 sd_id128_to_string(boot_id, match + 9);
601 r = sd_journal_add_match(j, match, strlen(match));
603 log_error("Failed to add match: %s", strerror(-r));
610 static int add_unit(sd_journal *j) {
611 _cleanup_free_ char *u = NULL;
616 if (isempty(arg_unit))
619 u = unit_name_mangle(arg_unit);
624 r = add_matches_for_unit(j, u);
626 r = add_matches_for_user_unit(j, u, getuid());
633 static int add_priorities(sd_journal *j) {
634 char match[] = "PRIORITY=0";
639 if (arg_priorities == 0xFF)
642 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
643 if (arg_priorities & (1 << i)) {
644 match[sizeof(match)-2] = '0' + i;
646 r = sd_journal_add_match(j, match, strlen(match));
648 log_error("Failed to add match: %s", strerror(-r));
656 static int setup_keys(void) {
658 size_t mpk_size, seed_size, state_size, i;
659 uint8_t *mpk, *seed, *state;
661 int fd = -1, r, attr = 0;
662 sd_id128_t machine, boot;
663 char *p = NULL, *k = NULL;
667 r = sd_id128_get_machine(&machine);
669 log_error("Failed to get machine ID: %s", strerror(-r));
673 r = sd_id128_get_boot(&boot);
675 log_error("Failed to get boot ID: %s", strerror(-r));
679 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
680 SD_ID128_FORMAT_VAL(machine)) < 0)
683 if (access(p, F_OK) >= 0) {
684 log_error("Sealing key file %s exists already.", p);
689 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
690 SD_ID128_FORMAT_VAL(machine)) < 0) {
695 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
696 mpk = alloca(mpk_size);
698 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
699 seed = alloca(seed_size);
701 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
702 state = alloca(state_size);
704 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
706 log_error("Failed to open /dev/random: %m");
711 log_info("Generating seed...");
712 l = loop_read(fd, seed, seed_size, true);
713 if (l < 0 || (size_t) l != seed_size) {
714 log_error("Failed to read random seed: %s", strerror(EIO));
719 log_info("Generating key pair...");
720 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
722 log_info("Generating sealing key...");
723 FSPRG_GenState0(state, mpk, seed, seed_size);
725 assert(arg_interval > 0);
727 n = now(CLOCK_REALTIME);
730 close_nointr_nofail(fd);
731 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
733 log_error("Failed to open %s: %m", k);
738 /* Enable secure remove, exclusion from dump, synchronous
739 * writing and in-place updating */
740 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
741 log_warning("FS_IOC_GETFLAGS failed: %m");
743 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
745 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
746 log_warning("FS_IOC_SETFLAGS failed: %m");
749 memcpy(h.signature, "KSHHRHLP", 8);
750 h.machine_id = machine;
752 h.header_size = htole64(sizeof(h));
753 h.start_usec = htole64(n * arg_interval);
754 h.interval_usec = htole64(arg_interval);
755 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
756 h.fsprg_state_size = htole64(state_size);
758 l = loop_write(fd, &h, sizeof(h), false);
759 if (l < 0 || (size_t) l != sizeof(h)) {
760 log_error("Failed to write header: %s", strerror(EIO));
765 l = loop_write(fd, state, state_size, false);
766 if (l < 0 || (size_t) l != state_size) {
767 log_error("Failed to write state: %s", strerror(EIO));
772 if (link(k, p) < 0) {
773 log_error("Failed to link file: %m");
781 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
782 "the following local file. This key file is automatically updated when the\n"
783 "sealing key is advanced. It should not be used on multiple hosts.\n"
787 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
788 "at a safe location and should not be saved locally on disk.\n"
789 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
792 for (i = 0; i < seed_size; i++) {
793 if (i > 0 && i % 3 == 0)
795 printf("%02x", ((uint8_t*) seed)[i]);
798 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
801 char tsb[FORMAT_TIMESPAN_MAX], *hn;
804 ANSI_HIGHLIGHT_OFF "\n"
805 "The sealing key is automatically changed every %s.\n",
806 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
808 hn = gethostname_malloc();
811 hostname_cleanup(hn);
812 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
814 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
817 /* If this is not an UTF-8 system don't print any QR codes */
818 if (is_locale_utf8()) {
819 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
820 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
830 close_nointr_nofail(fd);
841 log_error("Forward-secure sealing not available.");
846 static int verify(sd_journal *j) {
853 log_show_color(true);
855 HASHMAP_FOREACH(f, j->files, i) {
857 usec_t first, validated, last;
860 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
861 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
864 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
866 /* If the key was invalid give up right-away. */
869 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
872 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
873 log_info("PASS: %s", f->path);
875 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
877 log_info("=> Validated from %s to %s, final %s entries not sealed.",
878 format_timestamp(a, sizeof(a), first),
879 format_timestamp(b, sizeof(b), validated),
880 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
882 log_info("=> No sealing yet, %s of entries not sealed.",
883 format_timespan(c, sizeof(c), last - first, 0));
885 log_info("=> No sealing yet, no entries in file.");
894 static int access_check_var_log_journal(sd_journal *j) {
895 _cleanup_strv_free_ char **g = NULL;
901 have_access = in_group("systemd-journal") > 0;
904 /* Let's enumerate all groups from the default ACL of
905 * the directory, which generally should allow access
906 * to most journal files too */
907 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
915 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
916 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
917 " turn off this notice.");
919 _cleanup_free_ char *s = NULL;
921 r = strv_extend(&g, "systemd-journal");
928 s = strv_join(g, "', '");
932 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
933 " Users in the groups '%s' can see all messages.\n"
934 " Pass -q to turn off this notice.", s);
942 static int access_check(sd_journal *j) {
949 if (set_isempty(j->errors)) {
950 if (hashmap_isempty(j->files))
951 log_notice("No journal files were found.");
955 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
957 /* If /var/log/journal doesn't even exist,
958 * unprivileged users have no access at all */
959 if (access("/var/log/journal", F_OK) < 0 &&
961 in_group("systemd-journal") <= 0) {
962 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
963 "enabled. Users in the 'systemd-journal' group may always access messages.");
967 /* If /var/log/journal exists, try to pring a nice
968 notice if the user lacks access to it */
969 if (!arg_quiet && geteuid() != 0) {
970 r = access_check_var_log_journal(j);
975 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
976 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
977 "group may access messages.");
982 if (hashmap_isempty(j->files)) {
983 log_error("No journal files were opened due to insufficient permissions.");
988 SET_FOREACH(code, j->errors, it) {
991 err = -PTR_TO_INT(code);
995 log_warning("Error was encountered while opening journal files: %s",
1002 int main(int argc, char *argv[]) {
1004 sd_journal _cleanup_journal_close_ *j = NULL;
1005 bool need_seek = false;
1006 sd_id128_t previous_boot_id;
1007 bool previous_boot_id_valid = false, first_line = true;
1010 setlocale(LC_ALL, "");
1011 log_parse_environment();
1014 r = parse_argv(argc, argv);
1018 signal(SIGWINCH, columns_lines_cache_reset);
1020 if (arg_action == ACTION_NEW_ID128) {
1021 r = generate_new_id128();
1025 if (arg_action == ACTION_SETUP_KEYS) {
1030 if (arg_action == ACTION_UPDATE_CATALOG ||
1031 arg_action == ACTION_LIST_CATALOG ||
1032 arg_action == ACTION_DUMP_CATALOG) {
1034 const char* database = CATALOG_DATABASE;
1035 char _cleanup_free_ *copy = NULL;
1037 copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1042 path_kill_slashes(copy);
1046 if (arg_action == ACTION_UPDATE_CATALOG) {
1047 r = catalog_update(database, arg_root, catalog_file_dirs);
1049 log_error("Failed to list catalog: %s", strerror(-r));
1051 bool oneline = arg_action == ACTION_LIST_CATALOG;
1054 r = catalog_list_items(stdout, database,
1055 oneline, argv + optind);
1057 r = catalog_list(stdout, database, oneline);
1059 log_error("Failed to list catalog: %s", strerror(-r));
1066 r = sd_journal_open_directory(&j, arg_directory, 0);
1068 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
1070 log_error("Failed to open journal: %s", strerror(-r));
1071 return EXIT_FAILURE;
1074 r = access_check(j);
1076 return EXIT_FAILURE;
1078 if (arg_action == ACTION_VERIFY) {
1083 if (arg_action == ACTION_PRINT_HEADER) {
1084 journal_print_header(j);
1085 return EXIT_SUCCESS;
1088 if (arg_action == ACTION_DISK_USAGE) {
1090 char sbytes[FORMAT_BYTES_MAX];
1092 r = sd_journal_get_usage(j, &bytes);
1094 return EXIT_FAILURE;
1096 printf("Journals take up %s on disk.\n",
1097 format_bytes(sbytes, sizeof(sbytes), bytes));
1098 return EXIT_SUCCESS;
1101 r = add_this_boot(j);
1103 return EXIT_FAILURE;
1107 return EXIT_FAILURE;
1109 r = add_matches(j, argv + optind);
1111 return EXIT_FAILURE;
1113 r = add_priorities(j);
1115 return EXIT_FAILURE;
1117 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1118 r = sd_journal_get_fd(j);
1120 return EXIT_FAILURE;
1126 r = sd_journal_query_unique(j, arg_field);
1128 log_error("Failed to query unique data objects: %s", strerror(-r));
1129 return EXIT_FAILURE;
1132 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1135 if (arg_lines >= 0 && n_shown >= arg_lines)
1138 eq = memchr(data, '=', size);
1140 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1142 printf("%.*s\n", (int) size, (const char*) data);
1147 return EXIT_SUCCESS;
1151 r = sd_journal_seek_cursor(j, arg_cursor);
1153 log_error("Failed to seek to cursor: %s", strerror(-r));
1154 return EXIT_FAILURE;
1157 r = sd_journal_next(j);
1159 r = sd_journal_previous(j);
1161 } else if (arg_since_set && !arg_reverse) {
1162 r = sd_journal_seek_realtime_usec(j, arg_since);
1164 log_error("Failed to seek to date: %s", strerror(-r));
1165 return EXIT_FAILURE;
1167 r = sd_journal_next(j);
1169 } else if (arg_until_set && arg_reverse) {
1170 r = sd_journal_seek_realtime_usec(j, arg_until);
1172 log_error("Failed to seek to date: %s", strerror(-r));
1173 return EXIT_FAILURE;
1175 r = sd_journal_previous(j);
1177 } else if (arg_lines >= 0) {
1178 r = sd_journal_seek_tail(j);
1180 log_error("Failed to seek to tail: %s", strerror(-r));
1181 return EXIT_FAILURE;
1184 r = sd_journal_previous_skip(j, arg_lines);
1186 } else if (arg_reverse) {
1187 r = sd_journal_seek_tail(j);
1189 log_error("Failed to seek to tail: %s", strerror(-r));
1190 return EXIT_FAILURE;
1193 r = sd_journal_previous(j);
1196 r = sd_journal_seek_head(j);
1198 log_error("Failed to seek to head: %s", strerror(-r));
1199 return EXIT_FAILURE;
1202 r = sd_journal_next(j);
1206 log_error("Failed to iterate through journal: %s", strerror(-r));
1207 return EXIT_FAILURE;
1210 if (!arg_no_pager && !arg_follow)
1211 pager_open(arg_pager_end);
1215 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1217 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1219 log_error("Failed to get cutoff: %s", strerror(-r));
1225 printf("-- Logs begin at %s. --\n",
1226 format_timestamp(start_buf, sizeof(start_buf), start));
1228 printf("-- Logs begin at %s, end at %s. --\n",
1229 format_timestamp(start_buf, sizeof(start_buf), start),
1230 format_timestamp(end_buf, sizeof(end_buf), end));
1235 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1240 r = sd_journal_next(j);
1242 r = sd_journal_previous(j);
1244 log_error("Failed to iterate through journal: %s", strerror(-r));
1252 if (arg_until_set && !arg_reverse) {
1255 r = sd_journal_get_realtime_usec(j, &usec);
1257 log_error("Failed to determine timestamp: %s", strerror(-r));
1260 if (usec > arg_until)
1264 if (arg_since_set && arg_reverse) {
1267 r = sd_journal_get_realtime_usec(j, &usec);
1269 log_error("Failed to determine timestamp: %s", strerror(-r));
1272 if (usec < arg_since)
1279 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1281 if (previous_boot_id_valid &&
1282 !sd_id128_equal(boot_id, previous_boot_id))
1283 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1285 previous_boot_id = boot_id;
1286 previous_boot_id_valid = true;
1291 arg_all * OUTPUT_SHOW_ALL |
1292 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1293 on_tty() * OUTPUT_COLOR |
1294 arg_catalog * OUTPUT_CATALOG;
1296 r = output_journal(stdout, j, arg_output, 0, flags);
1297 if (r < 0 || ferror(stdout))
1307 r = sd_journal_wait(j, (uint64_t) -1);
1309 log_error("Couldn't wait for journal event: %s", strerror(-r));
1319 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;