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 7168
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 *f, Location *l) {
418 assert(f->location_type == LOCATION_SEEK);
419 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
421 if (l->monotonic_set &&
422 sd_id128_equal(f->current_boot_id, l->boot_id) &&
424 f->current_realtime == l->realtime &&
426 f->current_xor_hash == l->xor_hash)
430 sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) {
432 if (f->current_seqnum < l->seqnum)
434 if (f->current_seqnum > l->seqnum)
438 if (l->monotonic_set &&
439 sd_id128_equal(f->current_boot_id, l->boot_id)) {
441 if (f->current_monotonic < l->monotonic)
443 if (f->current_monotonic > l->monotonic)
447 if (l->realtime_set) {
449 if (f->current_realtime < l->realtime)
451 if (f->current_realtime > l->realtime)
455 if (l->xor_hash_set) {
457 if (f->current_xor_hash < l->xor_hash)
459 if (f->current_xor_hash > l->xor_hash)
466 static int next_for_match(
470 uint64_t after_offset,
471 direction_t direction,
483 if (m->type == MATCH_DISCRETE) {
486 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
490 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
492 } else if (m->type == MATCH_OR_TERM) {
495 /* Find the earliest match beyond after_offset */
497 LIST_FOREACH(matches, i, m->matches) {
500 r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
504 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
512 } else if (m->type == MATCH_AND_TERM) {
513 Match *i, *last_moved;
515 /* Always jump to the next matching entry and repeat
516 * this until we find an offset that matches for all
522 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
526 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
527 last_moved = m->matches;
529 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
532 r = next_for_match(j, i, f, np, direction, NULL, &cp);
536 assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
537 if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
546 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
558 static int find_location_for_match(
562 direction_t direction,
572 if (m->type == MATCH_DISCRETE) {
575 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
579 /* FIXME: missing: find by monotonic */
581 if (j->current_location.type == LOCATION_HEAD)
582 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
583 if (j->current_location.type == LOCATION_TAIL)
584 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
585 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
586 return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
587 if (j->current_location.monotonic_set) {
588 r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
592 if (j->current_location.realtime_set)
593 return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
595 return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
597 } else if (m->type == MATCH_OR_TERM) {
602 /* Find the earliest match */
604 LIST_FOREACH(matches, i, m->matches) {
607 r = find_location_for_match(j, i, f, direction, NULL, &cp);
611 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
619 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
634 assert(m->type == MATCH_AND_TERM);
636 /* First jump to the last match, and then find the
637 * next one where all matches match */
642 LIST_FOREACH(matches, i, m->matches) {
645 r = find_location_for_match(j, i, f, direction, NULL, &cp);
649 if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
653 return next_for_match(j, m, f, np, direction, ret, offset);
657 static int find_location_with_matches(
660 direction_t direction,
672 /* No matches is simple */
674 if (j->current_location.type == LOCATION_HEAD)
675 return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
676 if (j->current_location.type == LOCATION_TAIL)
677 return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
678 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
679 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
680 if (j->current_location.monotonic_set) {
681 r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
685 if (j->current_location.realtime_set)
686 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
688 return journal_file_next_entry(f, 0, direction, ret, offset);
690 return find_location_for_match(j, j->level0, f, direction, ret, offset);
693 static int next_with_matches(
696 direction_t direction,
705 /* No matches is easy. We simple advance the file
708 return journal_file_next_entry(f, f->current_offset, direction, ret, offset);
710 /* If we have a match then we look for the next matching entry
711 * with an offset at least one step larger */
712 return next_for_match(j, j->level0, f,
713 direction == DIRECTION_DOWN ? f->current_offset + 1
714 : f->current_offset - 1,
715 direction, ret, offset);
718 static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) {
720 uint64_t cp, n_entries;
726 if (f->last_direction == direction && f->current_offset > 0) {
727 /* If we hit EOF before, recheck if any new entries arrived. */
728 n_entries = le64toh(f->header->n_entries);
729 if (f->location_type == LOCATION_TAIL && n_entries == f->last_n_entries)
731 f->last_n_entries = n_entries;
733 /* LOCATION_SEEK here means we did the work in a previous
734 * iteration and the current location already points to a
735 * candidate entry. */
736 if (f->location_type != LOCATION_SEEK) {
737 r = next_with_matches(j, f, direction, &c, &cp);
741 journal_file_save_location(f, direction, c, cp);
744 r = find_location_with_matches(j, f, direction, &c, &cp);
748 journal_file_save_location(f, direction, c, cp);
751 /* OK, we found the spot, now let's advance until an entry
752 * that is actually different from what we were previously
753 * looking at. This is necessary to handle entries which exist
754 * in two (or more) journal files, and which shall all be
755 * suppressed but one. */
760 if (j->current_location.type == LOCATION_DISCRETE) {
763 k = compare_with_location(f, &j->current_location);
765 found = direction == DIRECTION_DOWN ? k > 0 : k < 0;
772 r = next_with_matches(j, f, direction, &c, &cp);
776 journal_file_save_location(f, direction, c, cp);
780 static int real_journal_next(sd_journal *j, direction_t direction) {
781 JournalFile *f, *new_file = NULL;
786 assert_return(j, -EINVAL);
787 assert_return(!journal_pid_changed(j), -ECHILD);
789 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
792 r = next_beyond_location(j, f, direction);
794 log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
795 remove_file_real(j, f);
798 f->location_type = LOCATION_TAIL;
807 k = journal_file_compare_locations(f, new_file);
809 found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
819 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
823 set_location(j, new_file, o);
828 _public_ int sd_journal_next(sd_journal *j) {
829 return real_journal_next(j, DIRECTION_DOWN);
832 _public_ int sd_journal_previous(sd_journal *j) {
833 return real_journal_next(j, DIRECTION_UP);
836 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
839 assert_return(j, -EINVAL);
840 assert_return(!journal_pid_changed(j), -ECHILD);
843 /* If this is not a discrete skip, then at least
844 * resolve the current location */
845 if (j->current_location.type != LOCATION_DISCRETE)
846 return real_journal_next(j, direction);
852 r = real_journal_next(j, direction);
866 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
867 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
870 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
871 return real_journal_next_skip(j, DIRECTION_UP, skip);
874 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
877 char bid[33], sid[33];
879 assert_return(j, -EINVAL);
880 assert_return(!journal_pid_changed(j), -ECHILD);
881 assert_return(cursor, -EINVAL);
883 if (!j->current_file || j->current_file->current_offset <= 0)
884 return -EADDRNOTAVAIL;
886 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
890 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
891 sd_id128_to_string(o->entry.boot_id, bid);
894 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
895 sid, le64toh(o->entry.seqnum),
896 bid, le64toh(o->entry.monotonic),
897 le64toh(o->entry.realtime),
898 le64toh(o->entry.xor_hash)) < 0)
904 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
905 const char *word, *state;
907 unsigned long long seqnum, monotonic, realtime, xor_hash;
909 seqnum_id_set = false,
912 monotonic_set = false,
913 realtime_set = false,
914 xor_hash_set = false;
915 sd_id128_t seqnum_id, boot_id;
917 assert_return(j, -EINVAL);
918 assert_return(!journal_pid_changed(j), -ECHILD);
919 assert_return(!isempty(cursor), -EINVAL);
921 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
925 if (l < 2 || word[1] != '=')
928 item = strndup(word, l);
935 seqnum_id_set = true;
936 k = sd_id128_from_string(item+2, &seqnum_id);
941 if (sscanf(item+2, "%llx", &seqnum) != 1)
947 k = sd_id128_from_string(item+2, &boot_id);
951 monotonic_set = true;
952 if (sscanf(item+2, "%llx", &monotonic) != 1)
958 if (sscanf(item+2, "%llx", &realtime) != 1)
964 if (sscanf(item+2, "%llx", &xor_hash) != 1)
975 if ((!seqnum_set || !seqnum_id_set) &&
976 (!monotonic_set || !boot_id_set) &&
982 j->current_location.type = LOCATION_SEEK;
985 j->current_location.realtime = (uint64_t) realtime;
986 j->current_location.realtime_set = true;
989 if (seqnum_set && seqnum_id_set) {
990 j->current_location.seqnum = (uint64_t) seqnum;
991 j->current_location.seqnum_id = seqnum_id;
992 j->current_location.seqnum_set = true;
995 if (monotonic_set && boot_id_set) {
996 j->current_location.monotonic = (uint64_t) monotonic;
997 j->current_location.boot_id = boot_id;
998 j->current_location.monotonic_set = true;
1002 j->current_location.xor_hash = (uint64_t) xor_hash;
1003 j->current_location.xor_hash_set = true;
1009 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1011 const char *word, *state;
1015 assert_return(j, -EINVAL);
1016 assert_return(!journal_pid_changed(j), -ECHILD);
1017 assert_return(!isempty(cursor), -EINVAL);
1019 if (!j->current_file || j->current_file->current_offset <= 0)
1020 return -EADDRNOTAVAIL;
1022 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1026 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
1027 _cleanup_free_ char *item = NULL;
1029 unsigned long long ll;
1032 if (l < 2 || word[1] != '=')
1035 item = strndup(word, l);
1042 k = sd_id128_from_string(item+2, &id);
1045 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1050 if (sscanf(item+2, "%llx", &ll) != 1)
1052 if (ll != le64toh(o->entry.seqnum))
1057 k = sd_id128_from_string(item+2, &id);
1060 if (!sd_id128_equal(id, o->entry.boot_id))
1065 if (sscanf(item+2, "%llx", &ll) != 1)
1067 if (ll != le64toh(o->entry.monotonic))
1072 if (sscanf(item+2, "%llx", &ll) != 1)
1074 if (ll != le64toh(o->entry.realtime))
1079 if (sscanf(item+2, "%llx", &ll) != 1)
1081 if (ll != le64toh(o->entry.xor_hash))
1091 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1092 assert_return(j, -EINVAL);
1093 assert_return(!journal_pid_changed(j), -ECHILD);
1096 j->current_location.type = LOCATION_SEEK;
1097 j->current_location.boot_id = boot_id;
1098 j->current_location.monotonic = usec;
1099 j->current_location.monotonic_set = true;
1104 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, 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.realtime = usec;
1111 j->current_location.realtime_set = true;
1116 _public_ int sd_journal_seek_head(sd_journal *j) {
1117 assert_return(j, -EINVAL);
1118 assert_return(!journal_pid_changed(j), -ECHILD);
1121 j->current_location.type = LOCATION_HEAD;
1126 _public_ int sd_journal_seek_tail(sd_journal *j) {
1127 assert_return(j, -EINVAL);
1128 assert_return(!journal_pid_changed(j), -ECHILD);
1131 j->current_location.type = LOCATION_TAIL;
1136 static void check_network(sd_journal *j, int fd) {
1144 if (fstatfs(fd, &sfs) < 0)
1148 F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1149 F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
1150 F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
1151 F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
1152 F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
1155 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1156 const char *full, *tilded, *atted;
1158 full = strjoina(prefix, ".journal");
1159 tilded = strjoina(full, "~");
1160 atted = strjoina(prefix, "@");
1162 return streq(filename, full) ||
1163 streq(filename, tilded) ||
1164 startswith(filename, atted);
1167 static bool file_type_wanted(int flags, const char *filename) {
1168 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1171 /* no flags set → every type is OK */
1172 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1175 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1178 if (flags & SD_JOURNAL_CURRENT_USER) {
1179 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1181 xsprintf(prefix, "user-"UID_FMT, getuid());
1183 if (file_has_type_prefix(prefix, filename))
1190 static int add_any_file(sd_journal *j, const char *path) {
1191 JournalFile *f = NULL;
1197 if (ordered_hashmap_get(j->files, path))
1200 if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1201 log_warning("Too many open journal files, not adding %s.", path);
1202 return set_put_error(j, -ETOOMANYREFS);
1205 r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
1209 /* journal_file_dump(f); */
1211 r = ordered_hashmap_put(j->files, f->path, f);
1213 journal_file_close(f);
1217 log_debug("File %s added.", f->path);
1219 check_network(j, f->fd);
1221 j->current_invalidate_counter ++;
1226 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1227 _cleanup_free_ char *path = NULL;
1234 if (j->no_new_files ||
1235 !file_type_wanted(j->flags, filename))
1238 path = strjoin(prefix, "/", filename, NULL);
1242 r = add_any_file(j, path);
1248 static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
1249 _cleanup_free_ char *path;
1256 path = strjoin(prefix, "/", filename, NULL);
1260 f = ordered_hashmap_get(j->files, path);
1264 remove_file_real(j, f);
1268 static void remove_file_real(sd_journal *j, JournalFile *f) {
1272 ordered_hashmap_remove(j->files, f->path);
1274 log_debug("File %s removed.", f->path);
1276 if (j->current_file == f) {
1277 j->current_file = NULL;
1278 j->current_field = 0;
1281 if (j->unique_file == f) {
1282 /* Jump to the next unique_file or NULL if that one was last */
1283 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
1284 j->unique_offset = 0;
1285 if (!j->unique_file)
1286 j->unique_file_lost = true;
1289 journal_file_close(f);
1291 j->current_invalidate_counter ++;
1294 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
1295 _cleanup_free_ char *path = NULL;
1297 _cleanup_closedir_ DIR *d = NULL;
1305 log_debug("Considering %s/%s.", prefix, dirname);
1307 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1308 (sd_id128_from_string(dirname, &id) < 0 ||
1309 sd_id128_get_machine(&mid) < 0 ||
1310 !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
1313 path = strjoin(prefix, "/", dirname, NULL);
1319 log_debug_errno(errno, "Failed to open %s: %m", path);
1320 if (errno == ENOENT)
1325 m = hashmap_get(j->directories_by_path, path);
1327 m = new0(Directory, 1);
1334 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1339 path = NULL; /* avoid freeing in cleanup */
1340 j->current_invalidate_counter ++;
1342 log_debug("Directory %s added.", m->path);
1344 } else if (m->is_root)
1347 if (m->wd <= 0 && j->inotify_fd >= 0) {
1349 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1350 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1351 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1354 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1355 inotify_rm_watch(j->inotify_fd, m->wd);
1363 if (!de && errno != 0) {
1365 log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
1371 if (dirent_is_file_with_suffix(de, ".journal") ||
1372 dirent_is_file_with_suffix(de, ".journal~")) {
1373 r = add_file(j, m->path, de->d_name);
1375 log_debug_errno(r, "Failed to add file %s/%s: %m",
1376 m->path, de->d_name);
1377 r = set_put_error(j, r);
1384 check_network(j, dirfd(d));
1389 static int add_root_directory(sd_journal *j, const char *p) {
1390 _cleanup_closedir_ DIR *d = NULL;
1397 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1398 !path_startswith(p, "/run"))
1402 p = strjoina(j->prefix, p);
1408 m = hashmap_get(j->directories_by_path, p);
1410 m = new0(Directory, 1);
1415 m->path = strdup(p);
1421 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1427 j->current_invalidate_counter ++;
1429 log_debug("Root directory %s added.", m->path);
1431 } else if (!m->is_root)
1434 if (m->wd <= 0 && j->inotify_fd >= 0) {
1436 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1437 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1440 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1441 inotify_rm_watch(j->inotify_fd, m->wd);
1444 if (j->no_new_files)
1453 if (!de && errno != 0) {
1455 log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
1461 if (dirent_is_file_with_suffix(de, ".journal") ||
1462 dirent_is_file_with_suffix(de, ".journal~")) {
1463 r = add_file(j, m->path, de->d_name);
1465 log_debug_errno(r, "Failed to add file %s/%s: %m",
1466 m->path, de->d_name);
1467 r = set_put_error(j, r);
1471 } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
1472 sd_id128_from_string(de->d_name, &id) >= 0) {
1474 r = add_directory(j, m->path, de->d_name);
1476 log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
1480 check_network(j, dirfd(d));
1485 static int remove_directory(sd_journal *j, Directory *d) {
1489 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1491 if (j->inotify_fd >= 0)
1492 inotify_rm_watch(j->inotify_fd, d->wd);
1495 hashmap_remove(j->directories_by_path, d->path);
1498 log_debug("Root directory %s removed.", d->path);
1500 log_debug("Directory %s removed.", d->path);
1508 static int add_search_paths(sd_journal *j) {
1510 const char search_paths[] =
1511 "/run/log/journal\0"
1512 "/var/log/journal\0";
1517 /* We ignore most errors here, since the idea is to only open
1518 * what's actually accessible, and ignore the rest. */
1520 NULSTR_FOREACH(p, search_paths) {
1521 r = add_root_directory(j, p);
1522 if (r < 0 && r != -ENOENT) {
1523 r = set_put_error(j, r);
1532 static int add_current_paths(sd_journal *j) {
1537 assert(j->no_new_files);
1539 /* Simply adds all directories for files we have open as
1540 * "root" directories. We don't expect errors here, so we
1541 * treat them as fatal. */
1543 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
1544 _cleanup_free_ char *dir;
1547 dir = dirname_malloc(f->path);
1551 r = add_root_directory(j, dir);
1553 set_put_error(j, r);
1562 static int allocate_inotify(sd_journal *j) {
1565 if (j->inotify_fd < 0) {
1566 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1567 if (j->inotify_fd < 0)
1571 if (!j->directories_by_wd) {
1572 j->directories_by_wd = hashmap_new(NULL);
1573 if (!j->directories_by_wd)
1580 static sd_journal *journal_new(int flags, const char *path) {
1583 j = new0(sd_journal, 1);
1587 j->original_pid = getpid();
1590 j->data_threshold = DEFAULT_DATA_THRESHOLD;
1593 j->path = strdup(path);
1598 j->files = ordered_hashmap_new(&string_hash_ops);
1599 j->directories_by_path = hashmap_new(&string_hash_ops);
1600 j->mmap = mmap_cache_new();
1601 if (!j->files || !j->directories_by_path || !j->mmap)
1607 sd_journal_close(j);
1611 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1615 assert_return(ret, -EINVAL);
1616 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL);
1618 j = journal_new(flags, NULL);
1622 r = add_search_paths(j);
1630 sd_journal_close(j);
1635 _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
1636 _cleanup_free_ char *root = NULL, *class = NULL;
1641 assert_return(machine, -EINVAL);
1642 assert_return(ret, -EINVAL);
1643 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
1644 assert_return(machine_name_is_valid(machine), -EINVAL);
1646 p = strjoina("/run/systemd/machines/", machine);
1647 r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL);
1655 if (!streq_ptr(class, "container"))
1658 j = journal_new(flags, NULL);
1665 r = add_search_paths(j);
1673 sd_journal_close(j);
1677 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1681 assert_return(ret, -EINVAL);
1682 assert_return(path, -EINVAL);
1683 assert_return(flags == 0, -EINVAL);
1685 j = journal_new(flags, path);
1689 r = add_root_directory(j, path);
1691 set_put_error(j, r);
1699 sd_journal_close(j);
1704 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1709 assert_return(ret, -EINVAL);
1710 assert_return(flags == 0, -EINVAL);
1712 j = journal_new(flags, NULL);
1716 STRV_FOREACH(path, paths) {
1717 r = add_any_file(j, *path);
1719 log_error_errno(r, "Failed to open %s: %m", *path);
1724 j->no_new_files = true;
1730 sd_journal_close(j);
1735 _public_ void sd_journal_close(sd_journal *j) {
1742 sd_journal_flush_matches(j);
1744 while ((f = ordered_hashmap_steal_first(j->files)))
1745 journal_file_close(f);
1747 ordered_hashmap_free(j->files);
1749 while ((d = hashmap_first(j->directories_by_path)))
1750 remove_directory(j, d);
1752 while ((d = hashmap_first(j->directories_by_wd)))
1753 remove_directory(j, d);
1755 hashmap_free(j->directories_by_path);
1756 hashmap_free(j->directories_by_wd);
1758 safe_close(j->inotify_fd);
1761 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
1762 mmap_cache_unref(j->mmap);
1767 free(j->unique_field);
1768 set_free(j->errors);
1772 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1777 assert_return(j, -EINVAL);
1778 assert_return(!journal_pid_changed(j), -ECHILD);
1779 assert_return(ret, -EINVAL);
1781 f = j->current_file;
1783 return -EADDRNOTAVAIL;
1785 if (f->current_offset <= 0)
1786 return -EADDRNOTAVAIL;
1788 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1792 *ret = le64toh(o->entry.realtime);
1796 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1802 assert_return(j, -EINVAL);
1803 assert_return(!journal_pid_changed(j), -ECHILD);
1805 f = j->current_file;
1807 return -EADDRNOTAVAIL;
1809 if (f->current_offset <= 0)
1810 return -EADDRNOTAVAIL;
1812 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1817 *ret_boot_id = o->entry.boot_id;
1819 r = sd_id128_get_boot(&id);
1823 if (!sd_id128_equal(id, o->entry.boot_id))
1828 *ret = le64toh(o->entry.monotonic);
1833 static bool field_is_valid(const char *field) {
1841 if (startswith(field, "__"))
1844 for (p = field; *p; p++) {
1849 if (*p >= 'A' && *p <= 'Z')
1852 if (*p >= '0' && *p <= '9')
1861 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1864 size_t field_length;
1868 assert_return(j, -EINVAL);
1869 assert_return(!journal_pid_changed(j), -ECHILD);
1870 assert_return(field, -EINVAL);
1871 assert_return(data, -EINVAL);
1872 assert_return(size, -EINVAL);
1873 assert_return(field_is_valid(field), -EINVAL);
1875 f = j->current_file;
1877 return -EADDRNOTAVAIL;
1879 if (f->current_offset <= 0)
1880 return -EADDRNOTAVAIL;
1882 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1886 field_length = strlen(field);
1888 n = journal_file_entry_n_items(o);
1889 for (i = 0; i < n; i++) {
1895 p = le64toh(o->entry.items[i].object_offset);
1896 le_hash = o->entry.items[i].hash;
1897 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1901 if (le_hash != o->data.hash)
1904 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1906 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
1908 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1909 if (decompress_startswith(compression,
1911 &f->compress_buffer, &f->compress_buffer_size,
1912 field, field_length, '=')) {
1916 r = decompress_blob(compression,
1918 &f->compress_buffer, &f->compress_buffer_size, &rsize,
1923 *data = f->compress_buffer;
1924 *size = (size_t) rsize;
1929 return -EPROTONOSUPPORT;
1931 } else if (l >= field_length+1 &&
1932 memcmp(o->data.payload, field, field_length) == 0 &&
1933 o->data.payload[field_length] == '=') {
1937 if ((uint64_t) t != l)
1940 *data = o->data.payload;
1946 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1954 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
1959 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1962 /* We can't read objects larger than 4G on a 32bit machine */
1963 if ((uint64_t) t != l)
1966 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
1968 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1972 r = decompress_blob(compression,
1973 o->data.payload, l, &f->compress_buffer,
1974 &f->compress_buffer_size, &rsize, j->data_threshold);
1978 *data = f->compress_buffer;
1979 *size = (size_t) rsize;
1981 return -EPROTONOSUPPORT;
1984 *data = o->data.payload;
1991 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
1998 assert_return(j, -EINVAL);
1999 assert_return(!journal_pid_changed(j), -ECHILD);
2000 assert_return(data, -EINVAL);
2001 assert_return(size, -EINVAL);
2003 f = j->current_file;
2005 return -EADDRNOTAVAIL;
2007 if (f->current_offset <= 0)
2008 return -EADDRNOTAVAIL;
2010 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2014 n = journal_file_entry_n_items(o);
2015 if (j->current_field >= n)
2018 p = le64toh(o->entry.items[j->current_field].object_offset);
2019 le_hash = o->entry.items[j->current_field].hash;
2020 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2024 if (le_hash != o->data.hash)
2027 r = return_data(j, f, o, data, size);
2031 j->current_field ++;
2036 _public_ void sd_journal_restart_data(sd_journal *j) {
2040 j->current_field = 0;
2043 _public_ int sd_journal_get_fd(sd_journal *j) {
2046 assert_return(j, -EINVAL);
2047 assert_return(!journal_pid_changed(j), -ECHILD);
2049 if (j->inotify_fd >= 0)
2050 return j->inotify_fd;
2052 r = allocate_inotify(j);
2056 /* Iterate through all dirs again, to add them to the
2058 if (j->no_new_files)
2059 r = add_current_paths(j);
2061 r = add_root_directory(j, j->path);
2063 r = add_search_paths(j);
2067 return j->inotify_fd;
2070 _public_ int sd_journal_get_events(sd_journal *j) {
2073 assert_return(j, -EINVAL);
2074 assert_return(!journal_pid_changed(j), -ECHILD);
2076 fd = sd_journal_get_fd(j);
2083 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2086 assert_return(j, -EINVAL);
2087 assert_return(!journal_pid_changed(j), -ECHILD);
2088 assert_return(timeout_usec, -EINVAL);
2090 fd = sd_journal_get_fd(j);
2094 if (!j->on_network) {
2095 *timeout_usec = (uint64_t) -1;
2099 /* If we are on the network we need to regularly check for
2100 * changes manually */
2102 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2106 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2113 /* Is this a subdirectory we watch? */
2114 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2118 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2119 (endswith(e->name, ".journal") ||
2120 endswith(e->name, ".journal~"))) {
2122 /* Event for a journal file */
2124 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2125 r = add_file(j, d->path, e->name);
2127 log_debug_errno(r, "Failed to add file %s/%s: %m",
2129 set_put_error(j, r);
2132 } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
2134 r = remove_file(j, d->path, e->name);
2136 log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
2139 } else if (!d->is_root && e->len == 0) {
2141 /* Event for a subdirectory */
2143 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2144 r = remove_directory(j, d);
2146 log_debug_errno(r, "Failed to remove directory %s: %m", d->path);
2150 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2152 /* Event for root directory */
2154 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2155 r = add_directory(j, d->path, e->name);
2157 log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
2164 if (e->mask & IN_IGNORED)
2167 log_warning("Unknown inotify event.");
2170 static int determine_change(sd_journal *j) {
2175 b = j->current_invalidate_counter != j->last_invalidate_counter;
2176 j->last_invalidate_counter = j->current_invalidate_counter;
2178 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2181 _public_ int sd_journal_process(sd_journal *j) {
2182 bool got_something = false;
2184 assert_return(j, -EINVAL);
2185 assert_return(!journal_pid_changed(j), -ECHILD);
2187 j->last_process_usec = now(CLOCK_MONOTONIC);
2190 union inotify_event_buffer buffer;
2191 struct inotify_event *e;
2194 l = read(j->inotify_fd, &buffer, sizeof(buffer));
2196 if (errno == EAGAIN || errno == EINTR)
2197 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2202 got_something = true;
2204 FOREACH_INOTIFY_EVENT(e, buffer, l)
2205 process_inotify_event(j, e);
2209 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2213 assert_return(j, -EINVAL);
2214 assert_return(!journal_pid_changed(j), -ECHILD);
2216 if (j->inotify_fd < 0) {
2218 /* This is the first invocation, hence create the
2220 r = sd_journal_get_fd(j);
2224 /* The journal might have changed since the context
2225 * object was created and we weren't watching before,
2226 * hence don't wait for anything, and return
2228 return determine_change(j);
2231 r = sd_journal_get_timeout(j, &t);
2235 if (t != (uint64_t) -1) {
2238 n = now(CLOCK_MONOTONIC);
2239 t = t > n ? t - n : 0;
2241 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2246 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2247 } while (r == -EINTR);
2252 return sd_journal_process(j);
2255 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2259 uint64_t fmin = 0, tmax = 0;
2262 assert_return(j, -EINVAL);
2263 assert_return(!journal_pid_changed(j), -ECHILD);
2264 assert_return(from || to, -EINVAL);
2265 assert_return(from != to, -EINVAL);
2267 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2270 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2283 fmin = MIN(fr, fmin);
2284 tmax = MAX(t, tmax);
2293 return first ? 0 : 1;
2296 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2302 assert_return(j, -EINVAL);
2303 assert_return(!journal_pid_changed(j), -ECHILD);
2304 assert_return(from || to, -EINVAL);
2305 assert_return(from != to, -EINVAL);
2307 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2310 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2320 *from = MIN(fr, *from);
2335 void journal_print_header(sd_journal *j) {
2338 bool newline = false;
2342 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2348 journal_file_print_header(f);
2352 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2357 assert_return(j, -EINVAL);
2358 assert_return(!journal_pid_changed(j), -ECHILD);
2359 assert_return(bytes, -EINVAL);
2361 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2364 if (fstat(f->fd, &st) < 0)
2367 sum += (uint64_t) st.st_blocks * 512ULL;
2374 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2377 assert_return(j, -EINVAL);
2378 assert_return(!journal_pid_changed(j), -ECHILD);
2379 assert_return(!isempty(field), -EINVAL);
2380 assert_return(field_is_valid(field), -EINVAL);
2386 free(j->unique_field);
2387 j->unique_field = f;
2388 j->unique_file = NULL;
2389 j->unique_offset = 0;
2390 j->unique_file_lost = false;
2395 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2398 assert_return(j, -EINVAL);
2399 assert_return(!journal_pid_changed(j), -ECHILD);
2400 assert_return(data, -EINVAL);
2401 assert_return(l, -EINVAL);
2402 assert_return(j->unique_field, -EINVAL);
2404 k = strlen(j->unique_field);
2406 if (!j->unique_file) {
2407 if (j->unique_file_lost)
2410 j->unique_file = ordered_hashmap_first(j->files);
2411 if (!j->unique_file)
2414 j->unique_offset = 0;
2426 /* Proceed to next data object in the field's linked list */
2427 if (j->unique_offset == 0) {
2428 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2432 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2434 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2438 j->unique_offset = le64toh(o->data.next_field_offset);
2441 /* We reached the end of the list? Then start again, with the next file */
2442 if (j->unique_offset == 0) {
2443 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
2444 if (!j->unique_file)
2450 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2451 * instead, so that we can look at this data object at the same
2452 * time as one on another file */
2453 r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
2457 /* Let's do the type check by hand, since we used 0 context above. */
2458 if (o->object.type != OBJECT_DATA) {
2459 log_debug("%s:offset " OFSfmt ": object has type %d, expected %d",
2460 j->unique_file->path, j->unique_offset,
2461 o->object.type, OBJECT_DATA);
2465 r = return_data(j, j->unique_file, o, &odata, &ol);
2469 /* Check if we have at least the field name and "=". */
2471 log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
2472 j->unique_file->path, j->unique_offset,
2477 if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') {
2478 log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"",
2479 j->unique_file->path, j->unique_offset,
2484 /* OK, now let's see if we already returned this data
2485 * object by checking if it exists in the earlier
2486 * traversed files. */
2488 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
2492 if (of == j->unique_file)
2495 /* Skip this file it didn't have any fields
2497 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2498 le64toh(of->header->n_fields) <= 0)
2501 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2512 r = return_data(j, j->unique_file, o, data, l);
2520 _public_ void sd_journal_restart_unique(sd_journal *j) {
2524 j->unique_file = NULL;
2525 j->unique_offset = 0;
2526 j->unique_file_lost = false;
2529 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2530 assert_return(j, -EINVAL);
2531 assert_return(!journal_pid_changed(j), -ECHILD);
2533 return !j->on_network;
2536 static char *lookup_field(const char *field, void *userdata) {
2537 sd_journal *j = userdata;
2545 r = sd_journal_get_data(j, field, &data, &size);
2547 size > REPLACE_VAR_MAX)
2548 return strdup(field);
2550 d = strlen(field) + 1;
2552 return strndup((const char*) data + d, size - d);
2555 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2559 _cleanup_free_ char *text = NULL, *cid = NULL;
2563 assert_return(j, -EINVAL);
2564 assert_return(!journal_pid_changed(j), -ECHILD);
2565 assert_return(ret, -EINVAL);
2567 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2571 cid = strndup((const char*) data + 11, size - 11);
2575 r = sd_id128_from_string(cid, &id);
2579 r = catalog_get(CATALOG_DATABASE, id, &text);
2583 t = replace_var(text, lookup_field, j);
2591 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2592 assert_return(ret, -EINVAL);
2594 return catalog_get(CATALOG_DATABASE, id, ret);
2597 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2598 assert_return(j, -EINVAL);
2599 assert_return(!journal_pid_changed(j), -ECHILD);
2601 j->data_threshold = sz;
2605 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2606 assert_return(j, -EINVAL);
2607 assert_return(!journal_pid_changed(j), -ECHILD);
2608 assert_return(sz, -EINVAL);
2610 *sz = j->data_threshold;