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\n"
909 "the system. Users in the group 'systemd-journal' can see all messages.\n"
910 "Pass -q to turn this notice off.");
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 this notice off.", s);
935 static int access_check(sd_journal *j) {
936 uint64_t eacces = EACCES, *code;
944 if (set_isempty(j->errors)) {
945 if (hashmap_isempty(j->files))
946 log_info("No journal files were found.");
950 if (!set_contains(j->errors, &eacces)) {
952 /* If /var/log/journal doesn't even exist,
953 unprivileged users have no access at all */
954 if (access("/var/log/journal", F_OK) < 0 &&
956 in_group("systemd-journal") <= 0) {
957 log_error("Unprivileged users can't see messages unless persistent log storage\n"
958 "is enabled. Users in the group 'systemd-journal' can always see messages.");
962 /* If /var/log/journal exists, try to pring a nice
963 notice if the user lacks access to it */
964 if (!arg_quiet && geteuid() != 0) {
965 r = access_check_var_log_journal(j);
970 if (geteuid() != 0 && in_group("systemd-journal") <= 0)
971 log_error("No access to messages.\n"
972 "Users in the group 'systemd-journal' can see messages.");
974 if (hashmap_isempty(j->files)) {
975 log_error("No journal files were opened, due to insufficient permissions.");
980 SET_FOREACH(code, j->errors, it) {
981 int err = -PTR_TO_INT(code);
984 log_warning("Error was encountered while opening journal files: %s",
988 log_notice("Hint: run journalctl in debug mode: SYSTEMD_LOG_LEVEL=debug journalct ...");
993 int main(int argc, char *argv[]) {
995 sd_journal _cleanup_journal_close_ *j = NULL;
996 bool need_seek = false;
997 sd_id128_t previous_boot_id;
998 bool previous_boot_id_valid = false, first_line = true;
1001 setlocale(LC_ALL, "");
1002 log_parse_environment();
1005 r = parse_argv(argc, argv);
1009 signal(SIGWINCH, columns_lines_cache_reset);
1011 if (arg_action == ACTION_NEW_ID128) {
1012 r = generate_new_id128();
1016 if (arg_action == ACTION_SETUP_KEYS) {
1021 if (arg_action == ACTION_LIST_CATALOG ||
1022 arg_action == ACTION_DUMP_CATALOG) {
1023 bool oneline = arg_action == ACTION_LIST_CATALOG;
1025 r = catalog_list_items(stdout, oneline, argv + optind);
1027 r = catalog_list(stdout, oneline);
1029 log_error("Failed to list catalog: %s", strerror(-r));
1033 if (arg_action == ACTION_UPDATE_CATALOG) {
1034 r = catalog_update();
1039 r = sd_journal_open_directory(&j, arg_directory, 0);
1041 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
1043 log_error("Failed to open journal: %s", strerror(-r));
1044 return EXIT_FAILURE;
1047 r = access_check(j);
1049 return EXIT_FAILURE;
1051 if (arg_action == ACTION_VERIFY) {
1056 if (arg_action == ACTION_PRINT_HEADER) {
1057 journal_print_header(j);
1058 return EXIT_SUCCESS;
1061 if (arg_action == ACTION_DISK_USAGE) {
1063 char sbytes[FORMAT_BYTES_MAX];
1065 r = sd_journal_get_usage(j, &bytes);
1067 return EXIT_FAILURE;
1069 printf("Journals take up %s on disk.\n",
1070 format_bytes(sbytes, sizeof(sbytes), bytes));
1071 return EXIT_SUCCESS;
1074 r = add_this_boot(j);
1076 return EXIT_FAILURE;
1080 return EXIT_FAILURE;
1082 r = add_matches(j, argv + optind);
1084 return EXIT_FAILURE;
1086 r = add_priorities(j);
1088 return EXIT_FAILURE;
1090 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1091 r = sd_journal_get_fd(j);
1093 return EXIT_FAILURE;
1099 r = sd_journal_query_unique(j, arg_field);
1101 log_error("Failed to query unique data objects: %s", strerror(-r));
1102 return EXIT_FAILURE;
1105 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1108 if (arg_lines >= 0 && n_shown >= arg_lines)
1111 eq = memchr(data, '=', size);
1113 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1115 printf("%.*s\n", (int) size, (const char*) data);
1120 return EXIT_SUCCESS;
1124 r = sd_journal_seek_cursor(j, arg_cursor);
1126 log_error("Failed to seek to cursor: %s", strerror(-r));
1127 return EXIT_FAILURE;
1130 r = sd_journal_next(j);
1132 r = sd_journal_previous(j);
1134 } else if (arg_since_set && !arg_reverse) {
1135 r = sd_journal_seek_realtime_usec(j, arg_since);
1137 log_error("Failed to seek to date: %s", strerror(-r));
1138 return EXIT_FAILURE;
1140 r = sd_journal_next(j);
1142 } else if (arg_until_set && arg_reverse) {
1143 r = sd_journal_seek_realtime_usec(j, arg_until);
1145 log_error("Failed to seek to date: %s", strerror(-r));
1146 return EXIT_FAILURE;
1148 r = sd_journal_previous(j);
1150 } else if (arg_lines >= 0) {
1151 r = sd_journal_seek_tail(j);
1153 log_error("Failed to seek to tail: %s", strerror(-r));
1154 return EXIT_FAILURE;
1157 r = sd_journal_previous_skip(j, arg_lines);
1159 } else if (arg_reverse) {
1160 r = sd_journal_seek_tail(j);
1162 log_error("Failed to seek to tail: %s", strerror(-r));
1163 return EXIT_FAILURE;
1166 r = sd_journal_previous(j);
1169 r = sd_journal_seek_head(j);
1171 log_error("Failed to seek to head: %s", strerror(-r));
1172 return EXIT_FAILURE;
1175 r = sd_journal_next(j);
1179 log_error("Failed to iterate through journal: %s", strerror(-r));
1180 return EXIT_FAILURE;
1183 if (!arg_no_pager && !arg_follow)
1184 pager_open(arg_pager_end);
1188 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1190 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1192 log_error("Failed to get cutoff: %s", strerror(-r));
1198 printf("-- Logs begin at %s. --\n",
1199 format_timestamp(start_buf, sizeof(start_buf), start));
1201 printf("-- Logs begin at %s, end at %s. --\n",
1202 format_timestamp(start_buf, sizeof(start_buf), start),
1203 format_timestamp(end_buf, sizeof(end_buf), end));
1208 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1213 r = sd_journal_next(j);
1215 r = sd_journal_previous(j);
1217 log_error("Failed to iterate through journal: %s", strerror(-r));
1225 if (arg_until_set && !arg_reverse) {
1228 r = sd_journal_get_realtime_usec(j, &usec);
1230 log_error("Failed to determine timestamp: %s", strerror(-r));
1233 if (usec > arg_until)
1237 if (arg_since_set && arg_reverse) {
1240 r = sd_journal_get_realtime_usec(j, &usec);
1242 log_error("Failed to determine timestamp: %s", strerror(-r));
1245 if (usec < arg_since)
1252 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1254 if (previous_boot_id_valid &&
1255 !sd_id128_equal(boot_id, previous_boot_id))
1256 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1258 previous_boot_id = boot_id;
1259 previous_boot_id_valid = true;
1264 arg_all * OUTPUT_SHOW_ALL |
1265 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1266 on_tty() * OUTPUT_COLOR |
1267 arg_catalog * OUTPUT_CATALOG;
1269 r = output_journal(stdout, j, arg_output, 0, flags);
1270 if (r < 0 || ferror(stdout))
1280 r = sd_journal_wait(j, (uint64_t) -1);
1282 log_error("Couldn't wait for journal event: %s", strerror(-r));
1292 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;