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"
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_this_boot = false;
75 static const char *arg_cursor = NULL;
76 static const char *arg_directory = NULL;
77 static int arg_priorities = 0xFF;
78 static const char *arg_verify_key = NULL;
80 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
82 static usec_t arg_since, arg_until;
83 static bool arg_since_set = false, arg_until_set = false;
84 static const char *arg_unit = NULL;
85 static bool arg_unit_system;
86 static const char *arg_field = NULL;
87 static bool arg_catalog = false;
88 static bool arg_reverse = false;
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"
129 " --interval=TIME Time interval for changing the FSS sealing key\n"
130 " --verify-key=KEY Specify FSS verification key\n"
133 " -h --help Show this help\n"
134 " --version Show package version\n"
135 " --new-id128 Generate a new 128 Bit ID\n"
136 " --header Show journal header information\n"
137 " --disk-usage Show total disk usage\n"
138 " -F --field=FIELD List all values a certain field takes\n"
139 " --list-catalog Show message IDs of all entries in the message catalog\n"
140 " --dump-catalog Show entries in the message catalog\n"
141 " --update-catalog Update the message catalog database\n"
143 " --setup-keys Generate new FSS key pair\n"
144 " --verify Verify journal file consistency\n"
146 , program_invocation_short_name);
151 static int parse_argv(int argc, char *argv[]) {
173 static const struct option options[] = {
174 { "help", no_argument, NULL, 'h' },
175 { "version" , no_argument, NULL, ARG_VERSION },
176 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
177 { "pager-end", no_argument, NULL, 'e' },
178 { "follow", no_argument, NULL, 'f' },
179 { "output", required_argument, NULL, 'o' },
180 { "all", no_argument, NULL, 'a' },
181 { "full", no_argument, NULL, ARG_FULL },
182 { "lines", optional_argument, NULL, 'n' },
183 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
184 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
185 { "quiet", no_argument, NULL, 'q' },
186 { "merge", no_argument, NULL, 'm' },
187 { "this-boot", no_argument, NULL, 'b' },
188 { "directory", required_argument, NULL, 'D' },
189 { "header", no_argument, NULL, ARG_HEADER },
190 { "priority", required_argument, NULL, 'p' },
191 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
192 { "interval", required_argument, NULL, ARG_INTERVAL },
193 { "verify", no_argument, NULL, ARG_VERIFY },
194 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
195 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
196 { "cursor", required_argument, NULL, 'c' },
197 { "since", required_argument, NULL, ARG_SINCE },
198 { "until", required_argument, NULL, ARG_UNTIL },
199 { "unit", required_argument, NULL, 'u' },
200 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
201 { "field", required_argument, NULL, 'F' },
202 { "catalog", no_argument, NULL, 'x' },
203 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
204 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
205 { "update-catalog",no_argument, NULL, ARG_UPDATE_CATALOG },
206 { "reverse", no_argument, NULL, 'r' },
215 while ((c = getopt_long(argc, argv, "hefo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) {
224 puts(PACKAGE_STRING);
225 puts(SYSTEMD_FEATURES);
233 arg_pager_end = true;
245 arg_output = output_mode_from_string(optarg);
246 if (arg_output < 0) {
247 log_error("Unknown output format '%s'.", optarg);
251 if (arg_output == OUTPUT_EXPORT ||
252 arg_output == OUTPUT_JSON ||
253 arg_output == OUTPUT_JSON_PRETTY ||
254 arg_output == OUTPUT_JSON_SSE ||
255 arg_output == OUTPUT_CAT)
270 r = safe_atoi(optarg, &arg_lines);
271 if (r < 0 || arg_lines < 0) {
272 log_error("Failed to parse lines '%s'", optarg);
278 /* Hmm, no argument? Maybe the next
279 * word on the command line is
280 * supposed to be the argument? Let's
281 * see if there is one, and is
282 * parsable as a positive
286 safe_atoi(argv[optind], &n) >= 0 &&
302 arg_action = ACTION_NEW_ID128;
314 arg_this_boot = true;
318 arg_directory = optarg;
326 arg_action = ACTION_PRINT_HEADER;
330 arg_action = ACTION_VERIFY;
334 arg_action = ACTION_DISK_USAGE;
339 arg_action = ACTION_SETUP_KEYS;
344 arg_action = ACTION_VERIFY;
345 arg_verify_key = optarg;
350 r = parse_usec(optarg, &arg_interval);
351 if (r < 0 || arg_interval <= 0) {
352 log_error("Failed to parse sealing key change interval: %s", optarg);
360 log_error("Forward-secure sealing not available.");
367 dots = strstr(optarg, "..");
373 a = strndup(optarg, dots - optarg);
377 from = log_level_from_string(a);
378 to = log_level_from_string(dots + 2);
381 if (from < 0 || to < 0) {
382 log_error("Failed to parse log level range %s", optarg);
389 for (i = from; i <= to; i++)
390 arg_priorities |= 1 << i;
392 for (i = to; i <= from; i++)
393 arg_priorities |= 1 << i;
399 p = log_level_from_string(optarg);
401 log_error("Unknown log level %s", optarg);
407 for (i = 0; i <= p; i++)
408 arg_priorities |= 1 << i;
415 r = parse_timestamp(optarg, &arg_since);
417 log_error("Failed to parse timestamp: %s", optarg);
420 arg_since_set = true;
424 r = parse_timestamp(optarg, &arg_until);
426 log_error("Failed to parse timestamp: %s", optarg);
429 arg_until_set = true;
434 arg_unit_system = true;
439 arg_unit_system = false;
453 case ARG_LIST_CATALOG:
454 arg_action = ACTION_LIST_CATALOG;
457 case ARG_DUMP_CATALOG:
458 arg_action = ACTION_DUMP_CATALOG;
461 case ARG_UPDATE_CATALOG:
462 arg_action = ACTION_UPDATE_CATALOG;
470 log_error("Unknown option code %c", c);
475 if (arg_follow && !arg_no_tail && arg_lines < 0)
478 if (arg_since_set && arg_until_set && arg_since > arg_until) {
479 log_error("--since= must be before --until=.");
483 if (arg_cursor && arg_since_set) {
484 log_error("Please specify either --since= or --cursor=, not both.");
488 if (arg_follow && arg_reverse) {
489 log_error("Please specify either --reverse= or --follow=, not both.");
496 static int generate_new_id128(void) {
501 r = sd_id128_randomize(&id);
503 log_error("Failed to generate ID: %s", strerror(-r));
507 printf("As string:\n"
508 SD_ID128_FORMAT_STR "\n\n"
510 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
512 "#define MESSAGE_XYZ SD_ID128_MAKE(",
513 SD_ID128_FORMAT_VAL(id),
514 SD_ID128_FORMAT_VAL(id));
515 for (i = 0; i < 16; i++)
516 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
517 fputs(")\n\n", stdout);
519 printf("As Python constant:\n"
521 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
522 SD_ID128_FORMAT_VAL(id));
527 static int add_matches(sd_journal *j, char **args) {
532 STRV_FOREACH(i, args) {
536 r = sd_journal_add_disjunction(j);
537 else if (path_is_absolute(*i)) {
538 char _cleanup_free_ *p, *t = NULL;
542 p = canonicalize_file_name(*i);
545 if (stat(path, &st) < 0) {
546 log_error("Couldn't stat file: %m");
550 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
551 t = strappend("_EXE=", path);
552 else if (S_ISCHR(st.st_mode))
553 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
554 else if (S_ISBLK(st.st_mode))
555 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
557 log_error("File is not a device node, regular file or is not executable: %s", *i);
564 r = sd_journal_add_match(j, t, 0);
566 r = sd_journal_add_match(j, *i, 0);
569 log_error("Failed to add match '%s': %s", *i, strerror(-r));
577 static int add_this_boot(sd_journal *j) {
578 char match[9+32+1] = "_BOOT_ID=";
587 r = sd_id128_get_boot(&boot_id);
589 log_error("Failed to get boot id: %s", strerror(-r));
593 sd_id128_to_string(boot_id, match + 9);
594 r = sd_journal_add_match(j, match, strlen(match));
596 log_error("Failed to add match: %s", strerror(-r));
603 static int add_unit(sd_journal *j) {
604 _cleanup_free_ char *u = NULL;
609 if (isempty(arg_unit))
612 u = unit_name_mangle(arg_unit);
617 r = add_matches_for_unit(j, u);
619 r = add_matches_for_user_unit(j, u, getuid());
626 static int add_priorities(sd_journal *j) {
627 char match[] = "PRIORITY=0";
632 if (arg_priorities == 0xFF)
635 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
636 if (arg_priorities & (1 << i)) {
637 match[sizeof(match)-2] = '0' + i;
639 r = sd_journal_add_match(j, match, strlen(match));
641 log_error("Failed to add match: %s", strerror(-r));
649 static int setup_keys(void) {
651 size_t mpk_size, seed_size, state_size, i;
652 uint8_t *mpk, *seed, *state;
654 int fd = -1, r, attr = 0;
655 sd_id128_t machine, boot;
656 char *p = NULL, *k = NULL;
660 r = sd_id128_get_machine(&machine);
662 log_error("Failed to get machine ID: %s", strerror(-r));
666 r = sd_id128_get_boot(&boot);
668 log_error("Failed to get boot ID: %s", strerror(-r));
672 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
673 SD_ID128_FORMAT_VAL(machine)) < 0)
676 if (access(p, F_OK) >= 0) {
677 log_error("Sealing key file %s exists already.", p);
682 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
683 SD_ID128_FORMAT_VAL(machine)) < 0) {
688 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
689 mpk = alloca(mpk_size);
691 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
692 seed = alloca(seed_size);
694 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
695 state = alloca(state_size);
697 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
699 log_error("Failed to open /dev/random: %m");
704 log_info("Generating seed...");
705 l = loop_read(fd, seed, seed_size, true);
706 if (l < 0 || (size_t) l != seed_size) {
707 log_error("Failed to read random seed: %s", strerror(EIO));
712 log_info("Generating key pair...");
713 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
715 log_info("Generating sealing key...");
716 FSPRG_GenState0(state, mpk, seed, seed_size);
718 assert(arg_interval > 0);
720 n = now(CLOCK_REALTIME);
723 close_nointr_nofail(fd);
724 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
726 log_error("Failed to open %s: %m", k);
731 /* Enable secure remove, exclusion from dump, synchronous
732 * writing and in-place updating */
733 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
734 log_warning("FS_IOC_GETFLAGS failed: %m");
736 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
738 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
739 log_warning("FS_IOC_SETFLAGS failed: %m");
742 memcpy(h.signature, "KSHHRHLP", 8);
743 h.machine_id = machine;
745 h.header_size = htole64(sizeof(h));
746 h.start_usec = htole64(n * arg_interval);
747 h.interval_usec = htole64(arg_interval);
748 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
749 h.fsprg_state_size = htole64(state_size);
751 l = loop_write(fd, &h, sizeof(h), false);
752 if (l < 0 || (size_t) l != sizeof(h)) {
753 log_error("Failed to write header: %s", strerror(EIO));
758 l = loop_write(fd, state, state_size, false);
759 if (l < 0 || (size_t) l != state_size) {
760 log_error("Failed to write state: %s", strerror(EIO));
765 if (link(k, p) < 0) {
766 log_error("Failed to link file: %m");
774 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
775 "the following local file. This key file is automatically updated when the\n"
776 "sealing key is advanced. It should not be used on multiple hosts.\n"
780 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
781 "at a safe location and should not be saved locally on disk.\n"
782 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
785 for (i = 0; i < seed_size; i++) {
786 if (i > 0 && i % 3 == 0)
788 printf("%02x", ((uint8_t*) seed)[i]);
791 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
794 char tsb[FORMAT_TIMESPAN_MAX], *hn;
797 ANSI_HIGHLIGHT_OFF "\n"
798 "The sealing key is automatically changed every %s.\n",
799 format_timespan(tsb, sizeof(tsb), arg_interval));
801 hn = gethostname_malloc();
804 hostname_cleanup(hn);
805 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
807 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
810 /* If this is not an UTF-8 system don't print any QR codes */
811 if (is_locale_utf8()) {
812 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
813 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
823 close_nointr_nofail(fd);
834 log_error("Forward-secure sealing not available.");
839 static int verify(sd_journal *j) {
846 log_show_color(true);
848 HASHMAP_FOREACH(f, j->files, i) {
850 usec_t first, validated, last;
853 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
854 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
857 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
859 /* If the key was invalid give up right-away. */
862 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
865 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
866 log_info("PASS: %s", f->path);
868 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
870 log_info("=> Validated from %s to %s, final %s entries not sealed.",
871 format_timestamp(a, sizeof(a), first),
872 format_timestamp(b, sizeof(b), validated),
873 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
875 log_info("=> No sealing yet, %s of entries not sealed.",
876 format_timespan(c, sizeof(c), last - first));
878 log_info("=> No sealing yet, no entries in file.");
887 static int access_check_var_log_journal(sd_journal *j) {
888 _cleanup_strv_free_ char **g = NULL;
894 have_access = in_group("systemd-journal") > 0;
897 /* Let's enumerate all groups from the default ACL of
898 * the directory, which generally should allow access
899 * to most journal files too */
900 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
908 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
909 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
910 " turn off this notice.");
912 _cleanup_free_ char *s = NULL;
914 r = strv_extend(&g, "systemd-journal");
921 s = strv_join(g, "', '");
925 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
926 " Users in the groups '%s' can see all messages.\n"
927 " Pass -q to turn off this notice.", s);
935 static int access_check(sd_journal *j) {
942 if (set_isempty(j->errors)) {
943 if (hashmap_isempty(j->files))
944 log_notice("No journal files were found.");
948 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
950 /* If /var/log/journal doesn't even exist,
951 * unprivileged users have no access at all */
952 if (access("/var/log/journal", F_OK) < 0 &&
954 in_group("systemd-journal") <= 0) {
955 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
956 "enabled. Users in the 'systemd-journal' group may always access messages.");
960 /* If /var/log/journal exists, try to pring a nice
961 notice if the user lacks access to it */
962 if (!arg_quiet && geteuid() != 0) {
963 r = access_check_var_log_journal(j);
968 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
969 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
970 "group may access messages.");
975 if (hashmap_isempty(j->files)) {
976 log_error("No journal files were opened due to insufficient permissions.");
981 SET_FOREACH(code, j->errors, it) {
984 err = -PTR_TO_INT(code);
988 log_warning("Error was encountered while opening journal files: %s",
995 int main(int argc, char *argv[]) {
997 sd_journal _cleanup_journal_close_ *j = NULL;
998 bool need_seek = false;
999 sd_id128_t previous_boot_id;
1000 bool previous_boot_id_valid = false, first_line = true;
1003 setlocale(LC_ALL, "");
1004 log_parse_environment();
1007 r = parse_argv(argc, argv);
1011 signal(SIGWINCH, columns_lines_cache_reset);
1013 if (arg_action == ACTION_NEW_ID128) {
1014 r = generate_new_id128();
1018 if (arg_action == ACTION_SETUP_KEYS) {
1023 if (arg_action == ACTION_UPDATE_CATALOG ||
1024 arg_action == ACTION_LIST_CATALOG ||
1025 arg_action == ACTION_DUMP_CATALOG) {
1027 if (arg_action == ACTION_UPDATE_CATALOG) {
1028 r = catalog_update(CATALOG_DATABASE, NULL, catalog_file_dirs);
1030 log_error("Failed to list catalog: %s", strerror(-r));
1032 bool oneline = arg_action == ACTION_LIST_CATALOG;
1035 r = catalog_list_items(stdout, CATALOG_DATABASE,
1036 oneline, argv + optind);
1038 r = catalog_list(stdout, CATALOG_DATABASE, oneline);
1040 log_error("Failed to list catalog: %s", strerror(-r));
1047 r = sd_journal_open_directory(&j, arg_directory, 0);
1049 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
1051 log_error("Failed to open journal: %s", strerror(-r));
1052 return EXIT_FAILURE;
1055 r = access_check(j);
1057 return EXIT_FAILURE;
1059 if (arg_action == ACTION_VERIFY) {
1064 if (arg_action == ACTION_PRINT_HEADER) {
1065 journal_print_header(j);
1066 return EXIT_SUCCESS;
1069 if (arg_action == ACTION_DISK_USAGE) {
1071 char sbytes[FORMAT_BYTES_MAX];
1073 r = sd_journal_get_usage(j, &bytes);
1075 return EXIT_FAILURE;
1077 printf("Journals take up %s on disk.\n",
1078 format_bytes(sbytes, sizeof(sbytes), bytes));
1079 return EXIT_SUCCESS;
1082 r = add_this_boot(j);
1084 return EXIT_FAILURE;
1088 return EXIT_FAILURE;
1090 r = add_matches(j, argv + optind);
1092 return EXIT_FAILURE;
1094 r = add_priorities(j);
1096 return EXIT_FAILURE;
1098 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1099 r = sd_journal_get_fd(j);
1101 return EXIT_FAILURE;
1107 r = sd_journal_query_unique(j, arg_field);
1109 log_error("Failed to query unique data objects: %s", strerror(-r));
1110 return EXIT_FAILURE;
1113 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1116 if (arg_lines >= 0 && n_shown >= arg_lines)
1119 eq = memchr(data, '=', size);
1121 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1123 printf("%.*s\n", (int) size, (const char*) data);
1128 return EXIT_SUCCESS;
1132 r = sd_journal_seek_cursor(j, arg_cursor);
1134 log_error("Failed to seek to cursor: %s", strerror(-r));
1135 return EXIT_FAILURE;
1138 r = sd_journal_next(j);
1140 r = sd_journal_previous(j);
1142 } else if (arg_since_set && !arg_reverse) {
1143 r = sd_journal_seek_realtime_usec(j, arg_since);
1145 log_error("Failed to seek to date: %s", strerror(-r));
1146 return EXIT_FAILURE;
1148 r = sd_journal_next(j);
1150 } else if (arg_until_set && arg_reverse) {
1151 r = sd_journal_seek_realtime_usec(j, arg_until);
1153 log_error("Failed to seek to date: %s", strerror(-r));
1154 return EXIT_FAILURE;
1156 r = sd_journal_previous(j);
1158 } else if (arg_lines >= 0) {
1159 r = sd_journal_seek_tail(j);
1161 log_error("Failed to seek to tail: %s", strerror(-r));
1162 return EXIT_FAILURE;
1165 r = sd_journal_previous_skip(j, arg_lines);
1167 } else if (arg_reverse) {
1168 r = sd_journal_seek_tail(j);
1170 log_error("Failed to seek to tail: %s", strerror(-r));
1171 return EXIT_FAILURE;
1174 r = sd_journal_previous(j);
1177 r = sd_journal_seek_head(j);
1179 log_error("Failed to seek to head: %s", strerror(-r));
1180 return EXIT_FAILURE;
1183 r = sd_journal_next(j);
1187 log_error("Failed to iterate through journal: %s", strerror(-r));
1188 return EXIT_FAILURE;
1191 if (!arg_no_pager && !arg_follow)
1192 pager_open(arg_pager_end);
1196 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1198 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1200 log_error("Failed to get cutoff: %s", strerror(-r));
1206 printf("-- Logs begin at %s. --\n",
1207 format_timestamp(start_buf, sizeof(start_buf), start));
1209 printf("-- Logs begin at %s, end at %s. --\n",
1210 format_timestamp(start_buf, sizeof(start_buf), start),
1211 format_timestamp(end_buf, sizeof(end_buf), end));
1216 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1221 r = sd_journal_next(j);
1223 r = sd_journal_previous(j);
1225 log_error("Failed to iterate through journal: %s", strerror(-r));
1233 if (arg_until_set && !arg_reverse) {
1236 r = sd_journal_get_realtime_usec(j, &usec);
1238 log_error("Failed to determine timestamp: %s", strerror(-r));
1241 if (usec > arg_until)
1245 if (arg_since_set && arg_reverse) {
1248 r = sd_journal_get_realtime_usec(j, &usec);
1250 log_error("Failed to determine timestamp: %s", strerror(-r));
1253 if (usec < arg_since)
1260 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1262 if (previous_boot_id_valid &&
1263 !sd_id128_equal(boot_id, previous_boot_id))
1264 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1266 previous_boot_id = boot_id;
1267 previous_boot_id_valid = true;
1272 arg_all * OUTPUT_SHOW_ALL |
1273 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1274 on_tty() * OUTPUT_COLOR |
1275 arg_catalog * OUTPUT_CATALOG;
1277 r = output_journal(stdout, j, arg_output, 0, flags);
1278 if (r < 0 || ferror(stdout))
1288 r = sd_journal_wait(j, (uint64_t) -1);
1290 log_error("Couldn't wait for journal event: %s", strerror(-r));
1300 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;