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));
607 r = sd_journal_add_conjunction(j);
614 static int add_unit(sd_journal *j) {
615 _cleanup_free_ char *u = NULL;
620 if (isempty(arg_unit))
623 u = unit_name_mangle(arg_unit);
628 r = add_matches_for_unit(j, u);
630 r = add_matches_for_user_unit(j, u, getuid());
634 r = sd_journal_add_conjunction(j);
641 static int add_priorities(sd_journal *j) {
642 char match[] = "PRIORITY=0";
646 if (arg_priorities == 0xFF)
649 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
650 if (arg_priorities & (1 << i)) {
651 match[sizeof(match)-2] = '0' + i;
653 r = sd_journal_add_match(j, match, strlen(match));
655 log_error("Failed to add match: %s", strerror(-r));
660 r = sd_journal_add_conjunction(j);
667 static int setup_keys(void) {
669 size_t mpk_size, seed_size, state_size, i;
670 uint8_t *mpk, *seed, *state;
672 int fd = -1, r, attr = 0;
673 sd_id128_t machine, boot;
674 char *p = NULL, *k = NULL;
678 r = sd_id128_get_machine(&machine);
680 log_error("Failed to get machine ID: %s", strerror(-r));
684 r = sd_id128_get_boot(&boot);
686 log_error("Failed to get boot ID: %s", strerror(-r));
690 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
691 SD_ID128_FORMAT_VAL(machine)) < 0)
694 if (access(p, F_OK) >= 0) {
695 log_error("Sealing key file %s exists already.", p);
700 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
701 SD_ID128_FORMAT_VAL(machine)) < 0) {
706 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
707 mpk = alloca(mpk_size);
709 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
710 seed = alloca(seed_size);
712 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
713 state = alloca(state_size);
715 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
717 log_error("Failed to open /dev/random: %m");
722 log_info("Generating seed...");
723 l = loop_read(fd, seed, seed_size, true);
724 if (l < 0 || (size_t) l != seed_size) {
725 log_error("Failed to read random seed: %s", strerror(EIO));
730 log_info("Generating key pair...");
731 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
733 log_info("Generating sealing key...");
734 FSPRG_GenState0(state, mpk, seed, seed_size);
736 assert(arg_interval > 0);
738 n = now(CLOCK_REALTIME);
741 close_nointr_nofail(fd);
742 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
744 log_error("Failed to open %s: %m", k);
749 /* Enable secure remove, exclusion from dump, synchronous
750 * writing and in-place updating */
751 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
752 log_warning("FS_IOC_GETFLAGS failed: %m");
754 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
756 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
757 log_warning("FS_IOC_SETFLAGS failed: %m");
760 memcpy(h.signature, "KSHHRHLP", 8);
761 h.machine_id = machine;
763 h.header_size = htole64(sizeof(h));
764 h.start_usec = htole64(n * arg_interval);
765 h.interval_usec = htole64(arg_interval);
766 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
767 h.fsprg_state_size = htole64(state_size);
769 l = loop_write(fd, &h, sizeof(h), false);
770 if (l < 0 || (size_t) l != sizeof(h)) {
771 log_error("Failed to write header: %s", strerror(EIO));
776 l = loop_write(fd, state, state_size, false);
777 if (l < 0 || (size_t) l != state_size) {
778 log_error("Failed to write state: %s", strerror(EIO));
783 if (link(k, p) < 0) {
784 log_error("Failed to link file: %m");
792 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
793 "the following local file. This key file is automatically updated when the\n"
794 "sealing key is advanced. It should not be used on multiple hosts.\n"
798 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
799 "at a safe location and should not be saved locally on disk.\n"
800 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
803 for (i = 0; i < seed_size; i++) {
804 if (i > 0 && i % 3 == 0)
806 printf("%02x", ((uint8_t*) seed)[i]);
809 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
812 char tsb[FORMAT_TIMESPAN_MAX], *hn;
815 ANSI_HIGHLIGHT_OFF "\n"
816 "The sealing key is automatically changed every %s.\n",
817 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
819 hn = gethostname_malloc();
822 hostname_cleanup(hn);
823 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
825 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
828 /* If this is not an UTF-8 system don't print any QR codes */
829 if (is_locale_utf8()) {
830 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
831 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
841 close_nointr_nofail(fd);
852 log_error("Forward-secure sealing not available.");
857 static int verify(sd_journal *j) {
864 log_show_color(true);
866 HASHMAP_FOREACH(f, j->files, i) {
868 usec_t first, validated, last;
871 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
872 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
875 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
877 /* If the key was invalid give up right-away. */
880 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
883 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
884 log_info("PASS: %s", f->path);
886 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
888 log_info("=> Validated from %s to %s, final %s entries not sealed.",
889 format_timestamp(a, sizeof(a), first),
890 format_timestamp(b, sizeof(b), validated),
891 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
893 log_info("=> No sealing yet, %s of entries not sealed.",
894 format_timespan(c, sizeof(c), last - first, 0));
896 log_info("=> No sealing yet, no entries in file.");
905 static int access_check_var_log_journal(sd_journal *j) {
906 _cleanup_strv_free_ char **g = NULL;
912 have_access = in_group("systemd-journal") > 0;
915 /* Let's enumerate all groups from the default ACL of
916 * the directory, which generally should allow access
917 * to most journal files too */
918 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
926 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
927 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
928 " turn off this notice.");
930 _cleanup_free_ char *s = NULL;
932 r = strv_extend(&g, "systemd-journal");
939 s = strv_join(g, "', '");
943 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
944 " Users in the groups '%s' can see all messages.\n"
945 " Pass -q to turn off this notice.", s);
953 static int access_check(sd_journal *j) {
960 if (set_isempty(j->errors)) {
961 if (hashmap_isempty(j->files))
962 log_notice("No journal files were found.");
966 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
968 /* If /var/log/journal doesn't even exist,
969 * unprivileged users have no access at all */
970 if (access("/var/log/journal", F_OK) < 0 &&
972 in_group("systemd-journal") <= 0) {
973 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
974 "enabled. Users in the 'systemd-journal' group may always access messages.");
978 /* If /var/log/journal exists, try to pring a nice
979 notice if the user lacks access to it */
980 if (!arg_quiet && geteuid() != 0) {
981 r = access_check_var_log_journal(j);
986 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
987 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
988 "group may access messages.");
993 if (hashmap_isempty(j->files)) {
994 log_error("No journal files were opened due to insufficient permissions.");
999 SET_FOREACH(code, j->errors, it) {
1002 err = -PTR_TO_INT(code);
1006 log_warning("Error was encountered while opening journal files: %s",
1013 int main(int argc, char *argv[]) {
1015 sd_journal _cleanup_journal_close_ *j = NULL;
1016 bool need_seek = false;
1017 sd_id128_t previous_boot_id;
1018 bool previous_boot_id_valid = false, first_line = true;
1021 setlocale(LC_ALL, "");
1022 log_parse_environment();
1025 r = parse_argv(argc, argv);
1029 signal(SIGWINCH, columns_lines_cache_reset);
1031 if (arg_action == ACTION_NEW_ID128) {
1032 r = generate_new_id128();
1036 if (arg_action == ACTION_SETUP_KEYS) {
1041 if (arg_action == ACTION_UPDATE_CATALOG ||
1042 arg_action == ACTION_LIST_CATALOG ||
1043 arg_action == ACTION_DUMP_CATALOG) {
1045 const char* database = CATALOG_DATABASE;
1046 char _cleanup_free_ *copy = NULL;
1048 copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1053 path_kill_slashes(copy);
1057 if (arg_action == ACTION_UPDATE_CATALOG) {
1058 r = catalog_update(database, arg_root, catalog_file_dirs);
1060 log_error("Failed to list catalog: %s", strerror(-r));
1062 bool oneline = arg_action == ACTION_LIST_CATALOG;
1065 r = catalog_list_items(stdout, database,
1066 oneline, argv + optind);
1068 r = catalog_list(stdout, database, oneline);
1070 log_error("Failed to list catalog: %s", strerror(-r));
1077 r = sd_journal_open_directory(&j, arg_directory, 0);
1079 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
1081 log_error("Failed to open journal: %s", strerror(-r));
1082 return EXIT_FAILURE;
1085 r = access_check(j);
1087 return EXIT_FAILURE;
1089 if (arg_action == ACTION_VERIFY) {
1094 if (arg_action == ACTION_PRINT_HEADER) {
1095 journal_print_header(j);
1096 return EXIT_SUCCESS;
1099 if (arg_action == ACTION_DISK_USAGE) {
1101 char sbytes[FORMAT_BYTES_MAX];
1103 r = sd_journal_get_usage(j, &bytes);
1105 return EXIT_FAILURE;
1107 printf("Journals take up %s on disk.\n",
1108 format_bytes(sbytes, sizeof(sbytes), bytes));
1109 return EXIT_SUCCESS;
1112 r = add_this_boot(j);
1114 return EXIT_FAILURE;
1118 return EXIT_FAILURE;
1120 r = add_priorities(j);
1122 return EXIT_FAILURE;
1124 r = add_matches(j, argv + optind);
1126 return EXIT_FAILURE;
1128 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1129 r = sd_journal_get_fd(j);
1131 return EXIT_FAILURE;
1137 r = sd_journal_set_data_threshold(j, 0);
1139 log_error("Failed to unset data size threshold");
1140 return EXIT_FAILURE;
1143 r = sd_journal_query_unique(j, arg_field);
1145 log_error("Failed to query unique data objects: %s", strerror(-r));
1146 return EXIT_FAILURE;
1149 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1152 if (arg_lines >= 0 && n_shown >= arg_lines)
1155 eq = memchr(data, '=', size);
1157 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1159 printf("%.*s\n", (int) size, (const char*) data);
1164 return EXIT_SUCCESS;
1168 r = sd_journal_seek_cursor(j, arg_cursor);
1170 log_error("Failed to seek to cursor: %s", strerror(-r));
1171 return EXIT_FAILURE;
1174 r = sd_journal_next(j);
1176 r = sd_journal_previous(j);
1178 } else if (arg_since_set && !arg_reverse) {
1179 r = sd_journal_seek_realtime_usec(j, arg_since);
1181 log_error("Failed to seek to date: %s", strerror(-r));
1182 return EXIT_FAILURE;
1184 r = sd_journal_next(j);
1186 } else if (arg_until_set && arg_reverse) {
1187 r = sd_journal_seek_realtime_usec(j, arg_until);
1189 log_error("Failed to seek to date: %s", strerror(-r));
1190 return EXIT_FAILURE;
1192 r = sd_journal_previous(j);
1194 } else if (arg_lines >= 0) {
1195 r = sd_journal_seek_tail(j);
1197 log_error("Failed to seek to tail: %s", strerror(-r));
1198 return EXIT_FAILURE;
1201 r = sd_journal_previous_skip(j, arg_lines);
1203 } else if (arg_reverse) {
1204 r = sd_journal_seek_tail(j);
1206 log_error("Failed to seek to tail: %s", strerror(-r));
1207 return EXIT_FAILURE;
1210 r = sd_journal_previous(j);
1213 r = sd_journal_seek_head(j);
1215 log_error("Failed to seek to head: %s", strerror(-r));
1216 return EXIT_FAILURE;
1219 r = sd_journal_next(j);
1223 log_error("Failed to iterate through journal: %s", strerror(-r));
1224 return EXIT_FAILURE;
1227 if (!arg_no_pager && !arg_follow)
1228 pager_open(arg_pager_end);
1232 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1234 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1236 log_error("Failed to get cutoff: %s", strerror(-r));
1242 printf("-- Logs begin at %s. --\n",
1243 format_timestamp(start_buf, sizeof(start_buf), start));
1245 printf("-- Logs begin at %s, end at %s. --\n",
1246 format_timestamp(start_buf, sizeof(start_buf), start),
1247 format_timestamp(end_buf, sizeof(end_buf), end));
1252 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1257 r = sd_journal_next(j);
1259 r = sd_journal_previous(j);
1261 log_error("Failed to iterate through journal: %s", strerror(-r));
1269 if (arg_until_set && !arg_reverse) {
1272 r = sd_journal_get_realtime_usec(j, &usec);
1274 log_error("Failed to determine timestamp: %s", strerror(-r));
1277 if (usec > arg_until)
1281 if (arg_since_set && arg_reverse) {
1284 r = sd_journal_get_realtime_usec(j, &usec);
1286 log_error("Failed to determine timestamp: %s", strerror(-r));
1289 if (usec < arg_since)
1296 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1298 if (previous_boot_id_valid &&
1299 !sd_id128_equal(boot_id, previous_boot_id))
1300 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1302 previous_boot_id = boot_id;
1303 previous_boot_id_valid = true;
1308 arg_all * OUTPUT_SHOW_ALL |
1309 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1310 on_tty() * OUTPUT_COLOR |
1311 arg_catalog * OUTPUT_CATALOG;
1313 r = output_journal(stdout, j, arg_output, 0, flags);
1314 if (r < 0 || ferror(stdout))
1324 r = sd_journal_wait(j, (uint64_t) -1);
1326 log_error("Couldn't wait for journal event: %s", strerror(-r));
1336 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;