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/>.
26 #include <sys/inotify.h>
29 #include <linux/magic.h>
31 #include "sd-journal.h"
32 #include "journal-def.h"
33 #include "journal-file.h"
37 #include "path-util.h"
40 #include "journal-internal.h"
43 #include "replace-var.h"
46 #define JOURNAL_FILES_MAX 1024
48 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
50 #define REPLACE_VAR_MAX 256
52 #define DEFAULT_DATA_THRESHOLD (64*1024)
54 static void remove_file_real(sd_journal *j, JournalFile *f);
56 static bool journal_pid_changed(sd_journal *j) {
59 /* We don't support people creating a journal object and
60 * keeping it around over a fork(). Let's complain. */
62 return j->original_pid != getpid();
65 /* We return an error here only if we didn't manage to
66 memorize the real error. */
67 static int set_put_error(sd_journal *j, int r) {
73 k = set_ensure_allocated(&j->errors, NULL);
77 return set_put(j->errors, INT_TO_PTR(r));
80 static void detach_location(sd_journal *j) {
86 j->current_file = NULL;
89 ORDERED_HASHMAP_FOREACH(f, j->files, i)
90 journal_file_reset_location(f);
93 static void reset_location(sd_journal *j) {
97 zero(j->current_location);
100 static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
102 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
104 assert(o->object.type == OBJECT_ENTRY);
107 l->seqnum = le64toh(o->entry.seqnum);
108 l->seqnum_id = f->header->seqnum_id;
109 l->realtime = le64toh(o->entry.realtime);
110 l->monotonic = le64toh(o->entry.monotonic);
111 l->boot_id = o->entry.boot_id;
112 l->xor_hash = le64toh(o->entry.xor_hash);
114 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
117 static void set_location(sd_journal *j, JournalFile *f, Object *o) {
122 init_location(&j->current_location, LOCATION_DISCRETE, f, o);
125 j->current_field = 0;
127 /* Let f know its candidate entry was picked. */
128 assert(f->location_type == LOCATION_SEEK);
129 f->location_type = LOCATION_DISCRETE;
132 static int match_is_valid(const void *data, size_t size) {
140 if (startswith(data, "__"))
144 for (p = b; p < b + size; p++) {
152 if (*p >= 'A' && *p <= 'Z')
155 if (*p >= '0' && *p <= '9')
164 static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
165 const uint8_t *a = _a, *b = _b;
168 for (j = 0; j < s && j < t; j++) {
177 assert_not_reached("\"=\" not found");
180 static Match *match_new(Match *p, MatchType t) {
191 LIST_PREPEND(matches, p->matches, m);
197 static void match_free(Match *m) {
201 match_free(m->matches);
204 LIST_REMOVE(matches, m->parent->matches, m);
210 static void match_free_if_empty(Match *m) {
211 if (!m || m->matches)
217 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
218 Match *l3, *l4, *add_here = NULL, *m;
221 assert_return(j, -EINVAL);
222 assert_return(!journal_pid_changed(j), -ECHILD);
223 assert_return(data, -EINVAL);
228 assert_return(match_is_valid(data, size), -EINVAL);
234 * level 4: concrete matches */
237 j->level0 = match_new(NULL, MATCH_AND_TERM);
243 j->level1 = match_new(j->level0, MATCH_OR_TERM);
249 j->level2 = match_new(j->level1, MATCH_AND_TERM);
254 assert(j->level0->type == MATCH_AND_TERM);
255 assert(j->level1->type == MATCH_OR_TERM);
256 assert(j->level2->type == MATCH_AND_TERM);
258 le_hash = htole64(hash64(data, size));
260 LIST_FOREACH(matches, l3, j->level2->matches) {
261 assert(l3->type == MATCH_OR_TERM);
263 LIST_FOREACH(matches, l4, l3->matches) {
264 assert(l4->type == MATCH_DISCRETE);
266 /* Exactly the same match already? Then ignore
268 if (l4->le_hash == le_hash &&
270 memcmp(l4->data, data, size) == 0)
273 /* Same field? Then let's add this to this OR term */
274 if (same_field(data, size, l4->data, l4->size)) {
285 add_here = match_new(j->level2, MATCH_OR_TERM);
290 m = match_new(add_here, MATCH_DISCRETE);
294 m->le_hash = le_hash;
296 m->data = memdup(data, size);
305 match_free_if_empty(add_here);
306 match_free_if_empty(j->level2);
307 match_free_if_empty(j->level1);
308 match_free_if_empty(j->level0);
313 _public_ int sd_journal_add_conjunction(sd_journal *j) {
314 assert_return(j, -EINVAL);
315 assert_return(!journal_pid_changed(j), -ECHILD);
323 if (!j->level1->matches)
332 _public_ int sd_journal_add_disjunction(sd_journal *j) {
333 assert_return(j, -EINVAL);
334 assert_return(!journal_pid_changed(j), -ECHILD);
345 if (!j->level2->matches)
352 static char *match_make_string(Match *m) {
355 bool enclose = false;
358 return strdup("none");
360 if (m->type == MATCH_DISCRETE)
361 return strndup(m->data, m->size);
364 LIST_FOREACH(matches, i, m->matches) {
367 t = match_make_string(i);
374 k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t, NULL);
389 r = strjoin("(", p, ")", NULL);
397 char *journal_make_match_string(sd_journal *j) {
400 return match_make_string(j->level0);
403 _public_ void sd_journal_flush_matches(sd_journal *j) {
408 match_free(j->level0);
410 j->level0 = j->level1 = j->level2 = NULL;
415 _pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) {
421 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
423 if (l->monotonic_set &&
424 sd_id128_equal(ao->entry.boot_id, l->boot_id) &&
426 le64toh(ao->entry.realtime) == l->realtime &&
428 le64toh(ao->entry.xor_hash) == l->xor_hash)
432 sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) {
434 a = le64toh(ao->entry.seqnum);
442 if (l->monotonic_set &&
443 sd_id128_equal(ao->entry.boot_id, l->boot_id)) {
445 a = le64toh(ao->entry.monotonic);
447 if (a < l->monotonic)
449 if (a > l->monotonic)
453 if (l->realtime_set) {
455 a = le64toh(ao->entry.realtime);
463 if (l->xor_hash_set) {
464 a = le64toh(ao->entry.xor_hash);
475 static int next_for_match(
479 uint64_t after_offset,
480 direction_t direction,
492 if (m->type == MATCH_DISCRETE) {
495 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
499 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
501 } else if (m->type == MATCH_OR_TERM) {
504 /* Find the earliest match beyond after_offset */
506 LIST_FOREACH(matches, i, m->matches) {
509 r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
513 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
521 } else if (m->type == MATCH_AND_TERM) {
522 Match *i, *last_moved;
524 /* Always jump to the next matching entry and repeat
525 * this until we find an offset that matches for all
531 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
535 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
536 last_moved = m->matches;
538 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
541 r = next_for_match(j, i, f, np, direction, NULL, &cp);
545 assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
546 if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
555 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
567 static int find_location_for_match(
571 direction_t direction,
581 if (m->type == MATCH_DISCRETE) {
584 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
588 /* FIXME: missing: find by monotonic */
590 if (j->current_location.type == LOCATION_HEAD)
591 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
592 if (j->current_location.type == LOCATION_TAIL)
593 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
594 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
595 return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
596 if (j->current_location.monotonic_set) {
597 r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
601 if (j->current_location.realtime_set)
602 return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
604 return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
606 } else if (m->type == MATCH_OR_TERM) {
611 /* Find the earliest match */
613 LIST_FOREACH(matches, i, m->matches) {
616 r = find_location_for_match(j, i, f, direction, NULL, &cp);
620 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
628 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
643 assert(m->type == MATCH_AND_TERM);
645 /* First jump to the last match, and then find the
646 * next one where all matches match */
651 LIST_FOREACH(matches, i, m->matches) {
654 r = find_location_for_match(j, i, f, direction, NULL, &cp);
658 if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
662 return next_for_match(j, m, f, np, direction, ret, offset);
666 static int find_location_with_matches(
669 direction_t direction,
681 /* No matches is simple */
683 if (j->current_location.type == LOCATION_HEAD)
684 return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
685 if (j->current_location.type == LOCATION_TAIL)
686 return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
687 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
688 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
689 if (j->current_location.monotonic_set) {
690 r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
694 if (j->current_location.realtime_set)
695 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
697 return journal_file_next_entry(f, 0, direction, ret, offset);
699 return find_location_for_match(j, j->level0, f, direction, ret, offset);
702 static int next_with_matches(
705 direction_t direction,
718 /* No matches is easy. We simple advance the file
721 return journal_file_next_entry(f, cp, direction, ret, offset);
723 /* If we have a match then we look for the next matching entry
724 * with an offset at least one step larger */
725 return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset);
728 static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) {
730 uint64_t cp, n_entries;
736 /* If we hit EOF before, recheck if any new entries arrived. */
737 n_entries = le64toh(f->header->n_entries);
738 if (f->location_type == LOCATION_TAIL && n_entries == f->last_n_entries)
740 f->last_n_entries = n_entries;
742 if (f->last_direction == direction && f->current_offset > 0) {
743 /* LOCATION_SEEK here means we did the work in a previous
744 * iteration and the current location already points to a
745 * candidate entry. */
746 if (f->location_type == LOCATION_SEEK)
749 cp = f->current_offset;
751 r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c);
755 r = next_with_matches(j, f, direction, &c, &cp);
759 r = find_location_with_matches(j, f, direction, &c, &cp);
764 /* OK, we found the spot, now let's advance until an entry
765 * that is actually different from what we were previously
766 * looking at. This is necessary to handle entries which exist
767 * in two (or more) journal files, and which shall all be
768 * suppressed but one. */
773 if (j->current_location.type == LOCATION_DISCRETE) {
776 k = compare_with_location(f, c, &j->current_location);
778 found = direction == DIRECTION_DOWN ? k > 0 : k < 0;
783 journal_file_save_location(f, direction, c, cp);
787 r = next_with_matches(j, f, direction, &c, &cp);
793 static int real_journal_next(sd_journal *j, direction_t direction) {
794 JournalFile *f, *new_file = NULL;
799 assert_return(j, -EINVAL);
800 assert_return(!journal_pid_changed(j), -ECHILD);
802 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
805 r = next_beyond_location(j, f, direction);
807 log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
808 remove_file_real(j, f);
811 f->location_type = LOCATION_TAIL;
820 k = journal_file_compare_locations(f, new_file);
822 found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
832 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
836 set_location(j, new_file, o);
841 _public_ int sd_journal_next(sd_journal *j) {
842 return real_journal_next(j, DIRECTION_DOWN);
845 _public_ int sd_journal_previous(sd_journal *j) {
846 return real_journal_next(j, DIRECTION_UP);
849 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
852 assert_return(j, -EINVAL);
853 assert_return(!journal_pid_changed(j), -ECHILD);
856 /* If this is not a discrete skip, then at least
857 * resolve the current location */
858 if (j->current_location.type != LOCATION_DISCRETE)
859 return real_journal_next(j, direction);
865 r = real_journal_next(j, direction);
879 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
880 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
883 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
884 return real_journal_next_skip(j, DIRECTION_UP, skip);
887 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
890 char bid[33], sid[33];
892 assert_return(j, -EINVAL);
893 assert_return(!journal_pid_changed(j), -ECHILD);
894 assert_return(cursor, -EINVAL);
896 if (!j->current_file || j->current_file->current_offset <= 0)
897 return -EADDRNOTAVAIL;
899 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
903 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
904 sd_id128_to_string(o->entry.boot_id, bid);
907 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
908 sid, le64toh(o->entry.seqnum),
909 bid, le64toh(o->entry.monotonic),
910 le64toh(o->entry.realtime),
911 le64toh(o->entry.xor_hash)) < 0)
917 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
918 const char *word, *state;
920 unsigned long long seqnum, monotonic, realtime, xor_hash;
922 seqnum_id_set = false,
925 monotonic_set = false,
926 realtime_set = false,
927 xor_hash_set = false;
928 sd_id128_t seqnum_id, boot_id;
930 assert_return(j, -EINVAL);
931 assert_return(!journal_pid_changed(j), -ECHILD);
932 assert_return(!isempty(cursor), -EINVAL);
934 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
938 if (l < 2 || word[1] != '=')
941 item = strndup(word, l);
948 seqnum_id_set = true;
949 k = sd_id128_from_string(item+2, &seqnum_id);
954 if (sscanf(item+2, "%llx", &seqnum) != 1)
960 k = sd_id128_from_string(item+2, &boot_id);
964 monotonic_set = true;
965 if (sscanf(item+2, "%llx", &monotonic) != 1)
971 if (sscanf(item+2, "%llx", &realtime) != 1)
977 if (sscanf(item+2, "%llx", &xor_hash) != 1)
988 if ((!seqnum_set || !seqnum_id_set) &&
989 (!monotonic_set || !boot_id_set) &&
995 j->current_location.type = LOCATION_SEEK;
998 j->current_location.realtime = (uint64_t) realtime;
999 j->current_location.realtime_set = true;
1002 if (seqnum_set && seqnum_id_set) {
1003 j->current_location.seqnum = (uint64_t) seqnum;
1004 j->current_location.seqnum_id = seqnum_id;
1005 j->current_location.seqnum_set = true;
1008 if (monotonic_set && boot_id_set) {
1009 j->current_location.monotonic = (uint64_t) monotonic;
1010 j->current_location.boot_id = boot_id;
1011 j->current_location.monotonic_set = true;
1015 j->current_location.xor_hash = (uint64_t) xor_hash;
1016 j->current_location.xor_hash_set = true;
1022 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1024 const char *word, *state;
1028 assert_return(j, -EINVAL);
1029 assert_return(!journal_pid_changed(j), -ECHILD);
1030 assert_return(!isempty(cursor), -EINVAL);
1032 if (!j->current_file || j->current_file->current_offset <= 0)
1033 return -EADDRNOTAVAIL;
1035 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1039 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
1040 _cleanup_free_ char *item = NULL;
1042 unsigned long long ll;
1045 if (l < 2 || word[1] != '=')
1048 item = strndup(word, l);
1055 k = sd_id128_from_string(item+2, &id);
1058 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1063 if (sscanf(item+2, "%llx", &ll) != 1)
1065 if (ll != le64toh(o->entry.seqnum))
1070 k = sd_id128_from_string(item+2, &id);
1073 if (!sd_id128_equal(id, o->entry.boot_id))
1078 if (sscanf(item+2, "%llx", &ll) != 1)
1080 if (ll != le64toh(o->entry.monotonic))
1085 if (sscanf(item+2, "%llx", &ll) != 1)
1087 if (ll != le64toh(o->entry.realtime))
1092 if (sscanf(item+2, "%llx", &ll) != 1)
1094 if (ll != le64toh(o->entry.xor_hash))
1104 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1105 assert_return(j, -EINVAL);
1106 assert_return(!journal_pid_changed(j), -ECHILD);
1109 j->current_location.type = LOCATION_SEEK;
1110 j->current_location.boot_id = boot_id;
1111 j->current_location.monotonic = usec;
1112 j->current_location.monotonic_set = true;
1117 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1118 assert_return(j, -EINVAL);
1119 assert_return(!journal_pid_changed(j), -ECHILD);
1122 j->current_location.type = LOCATION_SEEK;
1123 j->current_location.realtime = usec;
1124 j->current_location.realtime_set = true;
1129 _public_ int sd_journal_seek_head(sd_journal *j) {
1130 assert_return(j, -EINVAL);
1131 assert_return(!journal_pid_changed(j), -ECHILD);
1134 j->current_location.type = LOCATION_HEAD;
1139 _public_ int sd_journal_seek_tail(sd_journal *j) {
1140 assert_return(j, -EINVAL);
1141 assert_return(!journal_pid_changed(j), -ECHILD);
1144 j->current_location.type = LOCATION_TAIL;
1149 static void check_network(sd_journal *j, int fd) {
1157 if (fstatfs(fd, &sfs) < 0)
1161 F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1162 F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
1163 F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
1164 F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
1165 F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
1168 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1169 const char *full, *tilded, *atted;
1171 full = strappenda(prefix, ".journal");
1172 tilded = strappenda(full, "~");
1173 atted = strappenda(prefix, "@");
1175 return streq(filename, full) ||
1176 streq(filename, tilded) ||
1177 startswith(filename, atted);
1180 static bool file_type_wanted(int flags, const char *filename) {
1181 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1184 /* no flags set → every type is OK */
1185 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1188 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1191 if (flags & SD_JOURNAL_CURRENT_USER) {
1192 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1194 assert_se(snprintf(prefix, sizeof(prefix), "user-"UID_FMT, getuid())
1195 < (int) sizeof(prefix));
1197 if (file_has_type_prefix(prefix, filename))
1204 static int add_any_file(sd_journal *j, const char *path) {
1205 JournalFile *f = NULL;
1211 if (ordered_hashmap_get(j->files, path))
1214 if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1215 log_warning("Too many open journal files, not adding %s.", path);
1216 return set_put_error(j, -ETOOMANYREFS);
1219 r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
1223 /* journal_file_dump(f); */
1225 r = ordered_hashmap_put(j->files, f->path, f);
1227 journal_file_close(f);
1231 log_debug("File %s added.", f->path);
1233 check_network(j, f->fd);
1235 j->current_invalidate_counter ++;
1240 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1241 _cleanup_free_ char *path = NULL;
1248 if (j->no_new_files ||
1249 !file_type_wanted(j->flags, filename))
1252 path = strjoin(prefix, "/", filename, NULL);
1256 r = add_any_file(j, path);
1262 static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
1263 _cleanup_free_ char *path;
1270 path = strjoin(prefix, "/", filename, NULL);
1274 f = ordered_hashmap_get(j->files, path);
1278 remove_file_real(j, f);
1282 static void remove_file_real(sd_journal *j, JournalFile *f) {
1286 ordered_hashmap_remove(j->files, f->path);
1288 log_debug("File %s removed.", f->path);
1290 if (j->current_file == f) {
1291 j->current_file = NULL;
1292 j->current_field = 0;
1295 if (j->unique_file == f) {
1296 /* Jump to the next unique_file or NULL if that one was last */
1297 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
1298 j->unique_offset = 0;
1299 if (!j->unique_file)
1300 j->unique_file_lost = true;
1303 journal_file_close(f);
1305 j->current_invalidate_counter ++;
1308 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
1309 _cleanup_free_ char *path = NULL;
1311 _cleanup_closedir_ DIR *d = NULL;
1319 log_debug("Considering %s/%s.", prefix, dirname);
1321 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1322 (sd_id128_from_string(dirname, &id) < 0 ||
1323 sd_id128_get_machine(&mid) < 0 ||
1324 !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
1327 path = strjoin(prefix, "/", dirname, NULL);
1333 log_debug_errno(errno, "Failed to open %s: %m", path);
1334 if (errno == ENOENT)
1339 m = hashmap_get(j->directories_by_path, path);
1341 m = new0(Directory, 1);
1348 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1353 path = NULL; /* avoid freeing in cleanup */
1354 j->current_invalidate_counter ++;
1356 log_debug("Directory %s added.", m->path);
1358 } else if (m->is_root)
1361 if (m->wd <= 0 && j->inotify_fd >= 0) {
1363 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1364 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1365 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1368 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1369 inotify_rm_watch(j->inotify_fd, m->wd);
1377 if (!de && errno != 0) {
1379 log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
1385 if (dirent_is_file_with_suffix(de, ".journal") ||
1386 dirent_is_file_with_suffix(de, ".journal~")) {
1387 r = add_file(j, m->path, de->d_name);
1389 log_debug_errno(r, "Failed to add file %s/%s: %m",
1390 m->path, de->d_name);
1391 r = set_put_error(j, r);
1398 check_network(j, dirfd(d));
1403 static int add_root_directory(sd_journal *j, const char *p) {
1404 _cleanup_closedir_ DIR *d = NULL;
1411 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1412 !path_startswith(p, "/run"))
1416 p = strappenda(j->prefix, p);
1422 m = hashmap_get(j->directories_by_path, p);
1424 m = new0(Directory, 1);
1429 m->path = strdup(p);
1435 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1441 j->current_invalidate_counter ++;
1443 log_debug("Root directory %s added.", m->path);
1445 } else if (!m->is_root)
1448 if (m->wd <= 0 && j->inotify_fd >= 0) {
1450 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1451 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1454 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1455 inotify_rm_watch(j->inotify_fd, m->wd);
1458 if (j->no_new_files)
1467 if (!de && errno != 0) {
1469 log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
1475 if (dirent_is_file_with_suffix(de, ".journal") ||
1476 dirent_is_file_with_suffix(de, ".journal~")) {
1477 r = add_file(j, m->path, de->d_name);
1479 log_debug_errno(r, "Failed to add file %s/%s: %m",
1480 m->path, de->d_name);
1481 r = set_put_error(j, r);
1485 } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
1486 sd_id128_from_string(de->d_name, &id) >= 0) {
1488 r = add_directory(j, m->path, de->d_name);
1490 log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
1494 check_network(j, dirfd(d));
1499 static int remove_directory(sd_journal *j, Directory *d) {
1503 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1505 if (j->inotify_fd >= 0)
1506 inotify_rm_watch(j->inotify_fd, d->wd);
1509 hashmap_remove(j->directories_by_path, d->path);
1512 log_debug("Root directory %s removed.", d->path);
1514 log_debug("Directory %s removed.", d->path);
1522 static int add_search_paths(sd_journal *j) {
1524 const char search_paths[] =
1525 "/run/log/journal\0"
1526 "/var/log/journal\0";
1531 /* We ignore most errors here, since the idea is to only open
1532 * what's actually accessible, and ignore the rest. */
1534 NULSTR_FOREACH(p, search_paths) {
1535 r = add_root_directory(j, p);
1536 if (r < 0 && r != -ENOENT) {
1537 r = set_put_error(j, r);
1546 static int add_current_paths(sd_journal *j) {
1551 assert(j->no_new_files);
1553 /* Simply adds all directories for files we have open as
1554 * "root" directories. We don't expect errors here, so we
1555 * treat them as fatal. */
1557 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
1558 _cleanup_free_ char *dir;
1561 dir = dirname_malloc(f->path);
1565 r = add_root_directory(j, dir);
1567 set_put_error(j, r);
1576 static int allocate_inotify(sd_journal *j) {
1579 if (j->inotify_fd < 0) {
1580 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1581 if (j->inotify_fd < 0)
1585 if (!j->directories_by_wd) {
1586 j->directories_by_wd = hashmap_new(NULL);
1587 if (!j->directories_by_wd)
1594 static sd_journal *journal_new(int flags, const char *path) {
1597 j = new0(sd_journal, 1);
1601 j->original_pid = getpid();
1604 j->data_threshold = DEFAULT_DATA_THRESHOLD;
1607 j->path = strdup(path);
1612 j->files = ordered_hashmap_new(&string_hash_ops);
1613 j->directories_by_path = hashmap_new(&string_hash_ops);
1614 j->mmap = mmap_cache_new();
1615 if (!j->files || !j->directories_by_path || !j->mmap)
1621 sd_journal_close(j);
1625 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1629 assert_return(ret, -EINVAL);
1630 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL);
1632 j = journal_new(flags, NULL);
1636 r = add_search_paths(j);
1644 sd_journal_close(j);
1649 _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
1650 _cleanup_free_ char *root = NULL, *class = NULL;
1655 assert_return(machine, -EINVAL);
1656 assert_return(ret, -EINVAL);
1657 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
1658 assert_return(machine_name_is_valid(machine), -EINVAL);
1660 p = strappenda("/run/systemd/machines/", machine);
1661 r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL);
1669 if (!streq_ptr(class, "container"))
1672 j = journal_new(flags, NULL);
1679 r = add_search_paths(j);
1687 sd_journal_close(j);
1691 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1695 assert_return(ret, -EINVAL);
1696 assert_return(path, -EINVAL);
1697 assert_return(flags == 0, -EINVAL);
1699 j = journal_new(flags, path);
1703 r = add_root_directory(j, path);
1705 set_put_error(j, r);
1713 sd_journal_close(j);
1718 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1723 assert_return(ret, -EINVAL);
1724 assert_return(flags == 0, -EINVAL);
1726 j = journal_new(flags, NULL);
1730 STRV_FOREACH(path, paths) {
1731 r = add_any_file(j, *path);
1733 log_error_errno(r, "Failed to open %s: %m", *path);
1738 j->no_new_files = true;
1744 sd_journal_close(j);
1749 _public_ void sd_journal_close(sd_journal *j) {
1756 sd_journal_flush_matches(j);
1758 while ((f = ordered_hashmap_steal_first(j->files)))
1759 journal_file_close(f);
1761 ordered_hashmap_free(j->files);
1763 while ((d = hashmap_first(j->directories_by_path)))
1764 remove_directory(j, d);
1766 while ((d = hashmap_first(j->directories_by_wd)))
1767 remove_directory(j, d);
1769 hashmap_free(j->directories_by_path);
1770 hashmap_free(j->directories_by_wd);
1772 safe_close(j->inotify_fd);
1775 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
1776 mmap_cache_unref(j->mmap);
1781 free(j->unique_field);
1782 set_free(j->errors);
1786 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1791 assert_return(j, -EINVAL);
1792 assert_return(!journal_pid_changed(j), -ECHILD);
1793 assert_return(ret, -EINVAL);
1795 f = j->current_file;
1797 return -EADDRNOTAVAIL;
1799 if (f->current_offset <= 0)
1800 return -EADDRNOTAVAIL;
1802 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1806 *ret = le64toh(o->entry.realtime);
1810 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1816 assert_return(j, -EINVAL);
1817 assert_return(!journal_pid_changed(j), -ECHILD);
1819 f = j->current_file;
1821 return -EADDRNOTAVAIL;
1823 if (f->current_offset <= 0)
1824 return -EADDRNOTAVAIL;
1826 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1831 *ret_boot_id = o->entry.boot_id;
1833 r = sd_id128_get_boot(&id);
1837 if (!sd_id128_equal(id, o->entry.boot_id))
1842 *ret = le64toh(o->entry.monotonic);
1847 static bool field_is_valid(const char *field) {
1855 if (startswith(field, "__"))
1858 for (p = field; *p; p++) {
1863 if (*p >= 'A' && *p <= 'Z')
1866 if (*p >= '0' && *p <= '9')
1875 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1878 size_t field_length;
1882 assert_return(j, -EINVAL);
1883 assert_return(!journal_pid_changed(j), -ECHILD);
1884 assert_return(field, -EINVAL);
1885 assert_return(data, -EINVAL);
1886 assert_return(size, -EINVAL);
1887 assert_return(field_is_valid(field), -EINVAL);
1889 f = j->current_file;
1891 return -EADDRNOTAVAIL;
1893 if (f->current_offset <= 0)
1894 return -EADDRNOTAVAIL;
1896 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1900 field_length = strlen(field);
1902 n = journal_file_entry_n_items(o);
1903 for (i = 0; i < n; i++) {
1909 p = le64toh(o->entry.items[i].object_offset);
1910 le_hash = o->entry.items[i].hash;
1911 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1915 if (le_hash != o->data.hash)
1918 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1920 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
1922 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1923 if (decompress_startswith(compression,
1925 &f->compress_buffer, &f->compress_buffer_size,
1926 field, field_length, '=')) {
1930 r = decompress_blob(compression,
1932 &f->compress_buffer, &f->compress_buffer_size, &rsize,
1937 *data = f->compress_buffer;
1938 *size = (size_t) rsize;
1943 return -EPROTONOSUPPORT;
1945 } else if (l >= field_length+1 &&
1946 memcmp(o->data.payload, field, field_length) == 0 &&
1947 o->data.payload[field_length] == '=') {
1951 if ((uint64_t) t != l)
1954 *data = o->data.payload;
1960 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1968 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
1973 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1976 /* We can't read objects larger than 4G on a 32bit machine */
1977 if ((uint64_t) t != l)
1980 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
1982 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1986 r = decompress_blob(compression,
1987 o->data.payload, l, &f->compress_buffer,
1988 &f->compress_buffer_size, &rsize, j->data_threshold);
1992 *data = f->compress_buffer;
1993 *size = (size_t) rsize;
1995 return -EPROTONOSUPPORT;
1998 *data = o->data.payload;
2005 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2012 assert_return(j, -EINVAL);
2013 assert_return(!journal_pid_changed(j), -ECHILD);
2014 assert_return(data, -EINVAL);
2015 assert_return(size, -EINVAL);
2017 f = j->current_file;
2019 return -EADDRNOTAVAIL;
2021 if (f->current_offset <= 0)
2022 return -EADDRNOTAVAIL;
2024 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2028 n = journal_file_entry_n_items(o);
2029 if (j->current_field >= n)
2032 p = le64toh(o->entry.items[j->current_field].object_offset);
2033 le_hash = o->entry.items[j->current_field].hash;
2034 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2038 if (le_hash != o->data.hash)
2041 r = return_data(j, f, o, data, size);
2045 j->current_field ++;
2050 _public_ void sd_journal_restart_data(sd_journal *j) {
2054 j->current_field = 0;
2057 _public_ int sd_journal_get_fd(sd_journal *j) {
2060 assert_return(j, -EINVAL);
2061 assert_return(!journal_pid_changed(j), -ECHILD);
2063 if (j->inotify_fd >= 0)
2064 return j->inotify_fd;
2066 r = allocate_inotify(j);
2070 /* Iterate through all dirs again, to add them to the
2072 if (j->no_new_files)
2073 r = add_current_paths(j);
2075 r = add_root_directory(j, j->path);
2077 r = add_search_paths(j);
2081 return j->inotify_fd;
2084 _public_ int sd_journal_get_events(sd_journal *j) {
2087 assert_return(j, -EINVAL);
2088 assert_return(!journal_pid_changed(j), -ECHILD);
2090 fd = sd_journal_get_fd(j);
2097 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2100 assert_return(j, -EINVAL);
2101 assert_return(!journal_pid_changed(j), -ECHILD);
2102 assert_return(timeout_usec, -EINVAL);
2104 fd = sd_journal_get_fd(j);
2108 if (!j->on_network) {
2109 *timeout_usec = (uint64_t) -1;
2113 /* If we are on the network we need to regularly check for
2114 * changes manually */
2116 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2120 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2127 /* Is this a subdirectory we watch? */
2128 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2132 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2133 (endswith(e->name, ".journal") ||
2134 endswith(e->name, ".journal~"))) {
2136 /* Event for a journal file */
2138 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2139 r = add_file(j, d->path, e->name);
2141 log_debug_errno(r, "Failed to add file %s/%s: %m",
2143 set_put_error(j, r);
2146 } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
2148 r = remove_file(j, d->path, e->name);
2150 log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
2153 } else if (!d->is_root && e->len == 0) {
2155 /* Event for a subdirectory */
2157 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2158 r = remove_directory(j, d);
2160 log_debug_errno(r, "Failed to remove directory %s: %m", d->path);
2164 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2166 /* Event for root directory */
2168 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2169 r = add_directory(j, d->path, e->name);
2171 log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
2178 if (e->mask & IN_IGNORED)
2181 log_warning("Unknown inotify event.");
2184 static int determine_change(sd_journal *j) {
2189 b = j->current_invalidate_counter != j->last_invalidate_counter;
2190 j->last_invalidate_counter = j->current_invalidate_counter;
2192 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2195 _public_ int sd_journal_process(sd_journal *j) {
2196 bool got_something = false;
2198 assert_return(j, -EINVAL);
2199 assert_return(!journal_pid_changed(j), -ECHILD);
2201 j->last_process_usec = now(CLOCK_MONOTONIC);
2204 uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event);
2205 struct inotify_event *e;
2208 l = read(j->inotify_fd, buffer, sizeof(buffer));
2210 if (errno == EAGAIN || errno == EINTR)
2211 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2216 got_something = true;
2218 FOREACH_INOTIFY_EVENT(e, buffer, l)
2219 process_inotify_event(j, e);
2223 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2227 assert_return(j, -EINVAL);
2228 assert_return(!journal_pid_changed(j), -ECHILD);
2230 if (j->inotify_fd < 0) {
2232 /* This is the first invocation, hence create the
2234 r = sd_journal_get_fd(j);
2238 /* The journal might have changed since the context
2239 * object was created and we weren't watching before,
2240 * hence don't wait for anything, and return
2242 return determine_change(j);
2245 r = sd_journal_get_timeout(j, &t);
2249 if (t != (uint64_t) -1) {
2252 n = now(CLOCK_MONOTONIC);
2253 t = t > n ? t - n : 0;
2255 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2260 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2261 } while (r == -EINTR);
2266 return sd_journal_process(j);
2269 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2273 uint64_t fmin = 0, tmax = 0;
2276 assert_return(j, -EINVAL);
2277 assert_return(!journal_pid_changed(j), -ECHILD);
2278 assert_return(from || to, -EINVAL);
2279 assert_return(from != to, -EINVAL);
2281 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2284 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2297 fmin = MIN(fr, fmin);
2298 tmax = MAX(t, tmax);
2307 return first ? 0 : 1;
2310 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2316 assert_return(j, -EINVAL);
2317 assert_return(!journal_pid_changed(j), -ECHILD);
2318 assert_return(from || to, -EINVAL);
2319 assert_return(from != to, -EINVAL);
2321 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2324 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2334 *from = MIN(fr, *from);
2349 void journal_print_header(sd_journal *j) {
2352 bool newline = false;
2356 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2362 journal_file_print_header(f);
2366 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2371 assert_return(j, -EINVAL);
2372 assert_return(!journal_pid_changed(j), -ECHILD);
2373 assert_return(bytes, -EINVAL);
2375 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2378 if (fstat(f->fd, &st) < 0)
2381 sum += (uint64_t) st.st_blocks * 512ULL;
2388 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2391 assert_return(j, -EINVAL);
2392 assert_return(!journal_pid_changed(j), -ECHILD);
2393 assert_return(!isempty(field), -EINVAL);
2394 assert_return(field_is_valid(field), -EINVAL);
2400 free(j->unique_field);
2401 j->unique_field = f;
2402 j->unique_file = NULL;
2403 j->unique_offset = 0;
2404 j->unique_file_lost = false;
2409 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2412 assert_return(j, -EINVAL);
2413 assert_return(!journal_pid_changed(j), -ECHILD);
2414 assert_return(data, -EINVAL);
2415 assert_return(l, -EINVAL);
2416 assert_return(j->unique_field, -EINVAL);
2418 k = strlen(j->unique_field);
2420 if (!j->unique_file) {
2421 if (j->unique_file_lost)
2424 j->unique_file = ordered_hashmap_first(j->files);
2425 if (!j->unique_file)
2428 j->unique_offset = 0;
2440 /* Proceed to next data object in the field's linked list */
2441 if (j->unique_offset == 0) {
2442 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2446 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2448 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2452 j->unique_offset = le64toh(o->data.next_field_offset);
2455 /* We reached the end of the list? Then start again, with the next file */
2456 if (j->unique_offset == 0) {
2457 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
2458 if (!j->unique_file)
2464 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2465 * instead, so that we can look at this data object at the same
2466 * time as one on another file */
2467 r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
2471 /* Let's do the type check by hand, since we used 0 context above. */
2472 if (o->object.type != OBJECT_DATA) {
2473 log_debug("%s:offset " OFSfmt ": object has type %d, expected %d",
2474 j->unique_file->path, j->unique_offset,
2475 o->object.type, OBJECT_DATA);
2479 r = return_data(j, j->unique_file, o, &odata, &ol);
2483 /* Check if we have at least the field name and "=". */
2485 log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
2486 j->unique_file->path, j->unique_offset,
2491 if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') {
2492 log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"",
2493 j->unique_file->path, j->unique_offset,
2498 /* OK, now let's see if we already returned this data
2499 * object by checking if it exists in the earlier
2500 * traversed files. */
2502 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
2506 if (of == j->unique_file)
2509 /* Skip this file it didn't have any fields
2511 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2512 le64toh(of->header->n_fields) <= 0)
2515 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2526 r = return_data(j, j->unique_file, o, data, l);
2534 _public_ void sd_journal_restart_unique(sd_journal *j) {
2538 j->unique_file = NULL;
2539 j->unique_offset = 0;
2540 j->unique_file_lost = false;
2543 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2544 assert_return(j, -EINVAL);
2545 assert_return(!journal_pid_changed(j), -ECHILD);
2547 return !j->on_network;
2550 static char *lookup_field(const char *field, void *userdata) {
2551 sd_journal *j = userdata;
2559 r = sd_journal_get_data(j, field, &data, &size);
2561 size > REPLACE_VAR_MAX)
2562 return strdup(field);
2564 d = strlen(field) + 1;
2566 return strndup((const char*) data + d, size - d);
2569 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2573 _cleanup_free_ char *text = NULL, *cid = NULL;
2577 assert_return(j, -EINVAL);
2578 assert_return(!journal_pid_changed(j), -ECHILD);
2579 assert_return(ret, -EINVAL);
2581 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2585 cid = strndup((const char*) data + 11, size - 11);
2589 r = sd_id128_from_string(cid, &id);
2593 r = catalog_get(CATALOG_DATABASE, id, &text);
2597 t = replace_var(text, lookup_field, j);
2605 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2606 assert_return(ret, -EINVAL);
2608 return catalog_get(CATALOG_DATABASE, id, ret);
2611 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2612 assert_return(j, -EINVAL);
2613 assert_return(!journal_pid_changed(j), -ECHILD);
2615 j->data_threshold = sz;
2619 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2620 assert_return(j, -EINVAL);
2621 assert_return(!journal_pid_changed(j), -ECHILD);
2622 assert_return(sz, -EINVAL);
2624 *sz = j->data_threshold;