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"
45 #define JOURNAL_FILES_MAX 1024
47 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
49 #define REPLACE_VAR_MAX 256
51 #define DEFAULT_DATA_THRESHOLD (64*1024)
53 /* We return an error here only if we didn't manage to
54 memorize the real error. */
55 static int set_put_error(sd_journal *j, int r) {
61 k = set_ensure_allocated(&j->errors, trivial_hash_func, trivial_compare_func);
65 return set_put(j->errors, INT_TO_PTR(r));
68 static void detach_location(sd_journal *j) {
74 j->current_file = NULL;
77 HASHMAP_FOREACH(f, j->files, i)
78 f->current_offset = 0;
81 static void reset_location(sd_journal *j) {
85 zero(j->current_location);
88 static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
90 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
92 assert(o->object.type == OBJECT_ENTRY);
95 l->seqnum = le64toh(o->entry.seqnum);
96 l->seqnum_id = f->header->seqnum_id;
97 l->realtime = le64toh(o->entry.realtime);
98 l->monotonic = le64toh(o->entry.monotonic);
99 l->boot_id = o->entry.boot_id;
100 l->xor_hash = le64toh(o->entry.xor_hash);
102 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
105 static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o, uint64_t offset) {
107 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
111 init_location(&j->current_location, type, f, o);
114 j->current_file->current_offset = 0;
117 j->current_field = 0;
119 f->current_offset = offset;
122 static int match_is_valid(const void *data, size_t size) {
130 if (startswith(data, "__"))
134 for (p = b; p < b + size; p++) {
142 if (*p >= 'A' && *p <= 'Z')
145 if (*p >= '0' && *p <= '9')
154 static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
155 const uint8_t *a = _a, *b = _b;
158 for (j = 0; j < s && j < t; j++) {
170 static Match *match_new(Match *p, MatchType t) {
181 LIST_PREPEND(Match, matches, p->matches, m);
187 static void match_free(Match *m) {
191 match_free(m->matches);
194 LIST_REMOVE(Match, matches, m->parent->matches, m);
200 static void match_free_if_empty(Match *m) {
201 if (!m || m->matches)
207 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
208 Match *l3, *l4, *add_here = NULL, *m;
220 if (!match_is_valid(data, size))
227 * level 4: concrete matches */
230 j->level0 = match_new(NULL, MATCH_AND_TERM);
236 j->level1 = match_new(j->level0, MATCH_OR_TERM);
242 j->level2 = match_new(j->level1, MATCH_AND_TERM);
247 assert(j->level0->type == MATCH_AND_TERM);
248 assert(j->level1->type == MATCH_OR_TERM);
249 assert(j->level2->type == MATCH_AND_TERM);
251 le_hash = htole64(hash64(data, size));
253 LIST_FOREACH(matches, l3, j->level2->matches) {
254 assert(l3->type == MATCH_OR_TERM);
256 LIST_FOREACH(matches, l4, l3->matches) {
257 assert(l4->type == MATCH_DISCRETE);
259 /* Exactly the same match already? Then ignore
261 if (l4->le_hash == le_hash &&
263 memcmp(l4->data, data, size) == 0)
266 /* Same field? Then let's add this to this OR term */
267 if (same_field(data, size, l4->data, l4->size)) {
278 add_here = match_new(j->level2, MATCH_OR_TERM);
283 m = match_new(add_here, MATCH_DISCRETE);
287 m->le_hash = le_hash;
289 m->data = memdup(data, size);
298 match_free_if_empty(add_here);
299 match_free_if_empty(j->level2);
300 match_free_if_empty(j->level1);
301 match_free_if_empty(j->level0);
306 _public_ int sd_journal_add_conjunction(sd_journal *j) {
315 if (!j->level1->matches)
324 _public_ int sd_journal_add_disjunction(sd_journal *j) {
336 if (!j->level2->matches)
343 static char *match_make_string(Match *m) {
346 bool enclose = false;
351 if (m->type == MATCH_DISCRETE)
352 return strndup(m->data, m->size);
355 LIST_FOREACH(matches, i, m->matches) {
358 t = match_make_string(i);
365 k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t, NULL);
382 r = strjoin("(", p, ")", NULL);
390 char *journal_make_match_string(sd_journal *j) {
393 return match_make_string(j->level0);
396 _public_ void sd_journal_flush_matches(sd_journal *j) {
402 match_free(j->level0);
404 j->level0 = j->level1 = j->level2 = NULL;
409 static int compare_entry_order(JournalFile *af, Object *_ao,
410 JournalFile *bf, uint64_t bp) {
420 /* The mmap cache might invalidate the object from the first
421 * file if we look at the one from the second file. Hence
422 * temporarily copy the header of the first one, and look at
424 ao = alloca(offsetof(EntryObject, items));
425 memcpy(ao, _ao, offsetof(EntryObject, items));
427 r = journal_file_move_to_object(bf, OBJECT_ENTRY, bp, &bo);
429 return strcmp(af->path, bf->path);
431 /* We operate on two different files here, hence we can access
432 * two objects at the same time, which we normally can't.
434 * If contents and timestamps match, these entries are
435 * identical, even if the seqnum does not match */
437 if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) &&
438 ao->entry.monotonic == bo->entry.monotonic &&
439 ao->entry.realtime == bo->entry.realtime &&
440 ao->entry.xor_hash == bo->entry.xor_hash)
443 if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) {
445 /* If this is from the same seqnum source, compare
447 a = le64toh(ao->entry.seqnum);
448 b = le64toh(bo->entry.seqnum);
455 /* Wow! This is weird, different data but the same
456 * seqnums? Something is borked, but let's make the
457 * best of it and compare by time. */
460 if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) {
462 /* If the boot id matches compare monotonic time */
463 a = le64toh(ao->entry.monotonic);
464 b = le64toh(bo->entry.monotonic);
472 /* Otherwise compare UTC time */
473 a = le64toh(ao->entry.realtime);
474 b = le64toh(bo->entry.realtime);
481 /* Finally, compare by contents */
482 a = le64toh(ao->entry.xor_hash);
483 b = le64toh(bo->entry.xor_hash);
493 _pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) {
499 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
501 if (l->monotonic_set &&
502 sd_id128_equal(ao->entry.boot_id, l->boot_id) &&
504 le64toh(ao->entry.realtime) == l->realtime &&
506 le64toh(ao->entry.xor_hash) == l->xor_hash)
510 sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) {
512 a = le64toh(ao->entry.seqnum);
520 if (l->monotonic_set &&
521 sd_id128_equal(ao->entry.boot_id, l->boot_id)) {
523 a = le64toh(ao->entry.monotonic);
525 if (a < l->monotonic)
527 if (a > l->monotonic)
531 if (l->realtime_set) {
533 a = le64toh(ao->entry.realtime);
541 if (l->xor_hash_set) {
542 a = le64toh(ao->entry.xor_hash);
553 static int next_for_match(
557 uint64_t after_offset,
558 direction_t direction,
570 if (m->type == MATCH_DISCRETE) {
573 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
577 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
579 } else if (m->type == MATCH_OR_TERM) {
582 /* Find the earliest match beyond after_offset */
584 LIST_FOREACH(matches, i, m->matches) {
587 r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
591 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
596 } else if (m->type == MATCH_AND_TERM) {
597 Match *i, *last_moved;
599 /* Always jump to the next matching entry and repeat
600 * this until we find an offset that matches for all
606 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
610 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
611 last_moved = m->matches;
613 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
616 r = next_for_match(j, i, f, np, direction, NULL, &cp);
620 assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
621 if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
631 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
643 static int find_location_for_match(
647 direction_t direction,
657 if (m->type == MATCH_DISCRETE) {
660 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
664 /* FIXME: missing: find by monotonic */
666 if (j->current_location.type == LOCATION_HEAD)
667 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
668 if (j->current_location.type == LOCATION_TAIL)
669 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
670 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
671 return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
672 if (j->current_location.monotonic_set) {
673 r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
677 if (j->current_location.realtime_set)
678 return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
680 return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
682 } else if (m->type == MATCH_OR_TERM) {
687 /* Find the earliest match */
689 LIST_FOREACH(matches, i, m->matches) {
692 r = find_location_for_match(j, i, f, direction, NULL, &cp);
696 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
704 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
719 assert(m->type == MATCH_AND_TERM);
721 /* First jump to the last match, and then find the
722 * next one where all matches match */
727 LIST_FOREACH(matches, i, m->matches) {
730 r = find_location_for_match(j, i, f, direction, NULL, &cp);
734 if (np == 0 || (direction == DIRECTION_DOWN ? np < cp : np > cp))
738 return next_for_match(j, m, f, np, direction, ret, offset);
742 static int find_location_with_matches(
745 direction_t direction,
757 /* No matches is simple */
759 if (j->current_location.type == LOCATION_HEAD)
760 return journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, ret, offset);
761 if (j->current_location.type == LOCATION_TAIL)
762 return journal_file_next_entry(f, NULL, 0, DIRECTION_UP, ret, offset);
763 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
764 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
765 if (j->current_location.monotonic_set) {
766 r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
770 if (j->current_location.realtime_set)
771 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
773 return journal_file_next_entry(f, NULL, 0, direction, ret, offset);
775 return find_location_for_match(j, j->level0, f, direction, ret, offset);
778 static int next_with_matches(
781 direction_t direction,
796 /* No matches is easy. We simple advance the file
799 return journal_file_next_entry(f, c, cp, direction, ret, offset);
801 /* If we have a match then we look for the next matching entry
802 * with an offset at least one step larger */
803 return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset);
806 static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
814 if (f->current_offset > 0) {
815 cp = f->current_offset;
817 r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c);
821 r = next_with_matches(j, f, direction, &c, &cp);
825 r = find_location_with_matches(j, f, direction, &c, &cp);
830 /* OK, we found the spot, now let's advance until to an entry
831 * that is actually different from what we were previously
832 * looking at. This is necessary to handle entries which exist
833 * in two (or more) journal files, and which shall all be
834 * suppressed but one. */
839 if (j->current_location.type == LOCATION_DISCRETE) {
842 k = compare_with_location(f, c, &j->current_location);
843 if (direction == DIRECTION_DOWN)
858 r = next_with_matches(j, f, direction, &c, &cp);
864 static int real_journal_next(sd_journal *j, direction_t direction) {
865 JournalFile *f, *new_file = NULL;
866 uint64_t new_offset = 0;
875 HASHMAP_FOREACH(f, j->files, i) {
878 r = next_beyond_location(j, f, direction, &o, &p);
880 log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r));
890 k = compare_entry_order(f, o, new_file, new_offset);
892 if (direction == DIRECTION_DOWN)
907 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_offset, &o);
911 set_location(j, LOCATION_DISCRETE, new_file, o, new_offset);
916 _public_ int sd_journal_next(sd_journal *j) {
917 return real_journal_next(j, DIRECTION_DOWN);
920 _public_ int sd_journal_previous(sd_journal *j) {
921 return real_journal_next(j, DIRECTION_UP);
924 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
931 /* If this is not a discrete skip, then at least
932 * resolve the current location */
933 if (j->current_location.type != LOCATION_DISCRETE)
934 return real_journal_next(j, direction);
940 r = real_journal_next(j, direction);
954 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
955 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
958 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
959 return real_journal_next_skip(j, DIRECTION_UP, skip);
962 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
965 char bid[33], sid[33];
972 if (!j->current_file || j->current_file->current_offset <= 0)
973 return -EADDRNOTAVAIL;
975 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
979 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
980 sd_id128_to_string(o->entry.boot_id, bid);
983 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
984 sid, le64toh(o->entry.seqnum),
985 bid, le64toh(o->entry.monotonic),
986 le64toh(o->entry.realtime),
987 le64toh(o->entry.xor_hash)) < 0)
993 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
996 unsigned long long seqnum, monotonic, realtime, xor_hash;
998 seqnum_id_set = false,
1000 boot_id_set = false,
1001 monotonic_set = false,
1002 realtime_set = false,
1003 xor_hash_set = false;
1004 sd_id128_t seqnum_id, boot_id;
1008 if (isempty(cursor))
1011 FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
1015 if (l < 2 || w[1] != '=')
1018 item = strndup(w, l);
1025 seqnum_id_set = true;
1026 k = sd_id128_from_string(item+2, &seqnum_id);
1031 if (sscanf(item+2, "%llx", &seqnum) != 1)
1037 k = sd_id128_from_string(item+2, &boot_id);
1041 monotonic_set = true;
1042 if (sscanf(item+2, "%llx", &monotonic) != 1)
1047 realtime_set = true;
1048 if (sscanf(item+2, "%llx", &realtime) != 1)
1053 xor_hash_set = true;
1054 if (sscanf(item+2, "%llx", &xor_hash) != 1)
1065 if ((!seqnum_set || !seqnum_id_set) &&
1066 (!monotonic_set || !boot_id_set) &&
1072 j->current_location.type = LOCATION_SEEK;
1075 j->current_location.realtime = (uint64_t) realtime;
1076 j->current_location.realtime_set = true;
1079 if (seqnum_set && seqnum_id_set) {
1080 j->current_location.seqnum = (uint64_t) seqnum;
1081 j->current_location.seqnum_id = seqnum_id;
1082 j->current_location.seqnum_set = true;
1085 if (monotonic_set && boot_id_set) {
1086 j->current_location.monotonic = (uint64_t) monotonic;
1087 j->current_location.boot_id = boot_id;
1088 j->current_location.monotonic_set = true;
1092 j->current_location.xor_hash = (uint64_t) xor_hash;
1093 j->current_location.xor_hash_set = true;
1099 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1107 if (isempty(cursor))
1110 if (!j->current_file || j->current_file->current_offset <= 0)
1111 return -EADDRNOTAVAIL;
1113 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1117 FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
1118 _cleanup_free_ char *item = NULL;
1120 unsigned long long ll;
1123 if (l < 2 || w[1] != '=')
1126 item = strndup(w, l);
1133 k = sd_id128_from_string(item+2, &id);
1136 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1141 if (sscanf(item+2, "%llx", &ll) != 1)
1143 if (ll != le64toh(o->entry.seqnum))
1148 k = sd_id128_from_string(item+2, &id);
1151 if (!sd_id128_equal(id, o->entry.boot_id))
1156 if (sscanf(item+2, "%llx", &ll) != 1)
1158 if (ll != le64toh(o->entry.monotonic))
1163 if (sscanf(item+2, "%llx", &ll) != 1)
1165 if (ll != le64toh(o->entry.realtime))
1170 if (sscanf(item+2, "%llx", &ll) != 1)
1172 if (ll != le64toh(o->entry.xor_hash))
1182 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1187 j->current_location.type = LOCATION_SEEK;
1188 j->current_location.boot_id = boot_id;
1189 j->current_location.monotonic = usec;
1190 j->current_location.monotonic_set = true;
1195 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1200 j->current_location.type = LOCATION_SEEK;
1201 j->current_location.realtime = usec;
1202 j->current_location.realtime_set = true;
1207 _public_ int sd_journal_seek_head(sd_journal *j) {
1212 j->current_location.type = LOCATION_HEAD;
1217 _public_ int sd_journal_seek_tail(sd_journal *j) {
1222 j->current_location.type = LOCATION_TAIL;
1227 static void check_network(sd_journal *j, int fd) {
1235 if (fstatfs(fd, &sfs) < 0)
1239 F_TYPE_CMP(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1240 F_TYPE_CMP(sfs.f_type, CODA_SUPER_MAGIC) ||
1241 F_TYPE_CMP(sfs.f_type, NCP_SUPER_MAGIC) ||
1242 F_TYPE_CMP(sfs.f_type, NFS_SUPER_MAGIC) ||
1243 F_TYPE_CMP(sfs.f_type, SMB_SUPER_MAGIC);
1246 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1247 const char *full, *tilded, *atted;
1249 full = strappend(prefix, ".journal");
1250 tilded = strappenda(full, "~");
1251 atted = strappenda(prefix, "@");
1253 return streq(filename, full) ||
1254 streq(filename, tilded) ||
1255 startswith(filename, atted);
1258 static bool file_type_wanted(int flags, const char *filename) {
1259 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1262 /* no flags set → every type is OK */
1263 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1266 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1269 if (flags & SD_JOURNAL_CURRENT_USER) {
1270 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1272 assert_se(snprintf(prefix, sizeof(prefix), "user-%lu", (unsigned long) getuid())
1273 < (int) sizeof(prefix));
1275 if (file_has_type_prefix(prefix, filename))
1282 static int add_any_file(sd_journal *j, const char *path) {
1289 if (hashmap_get(j->files, path))
1292 if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1293 log_warning("Too many open journal files, not adding %s.", path);
1294 return set_put_error(j, -ETOOMANYREFS);
1297 r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
1301 /* journal_file_dump(f); */
1303 r = hashmap_put(j->files, f->path, f);
1305 journal_file_close(f);
1309 log_debug("File %s added.", f->path);
1311 check_network(j, f->fd);
1313 j->current_invalidate_counter ++;
1318 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1319 _cleanup_free_ char *path = NULL;
1326 if (j->no_new_files ||
1327 !file_type_wanted(j->flags, filename))
1330 path = strjoin(prefix, "/", filename, NULL);
1334 r = add_any_file(j, path);
1340 static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
1348 path = strjoin(prefix, "/", filename, NULL);
1352 f = hashmap_get(j->files, path);
1357 hashmap_remove(j->files, f->path);
1359 log_debug("File %s removed.", f->path);
1361 if (j->current_file == f) {
1362 j->current_file = NULL;
1363 j->current_field = 0;
1366 if (j->unique_file == f) {
1367 j->unique_file = NULL;
1368 j->unique_offset = 0;
1371 journal_file_close(f);
1373 j->current_invalidate_counter ++;
1378 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
1379 _cleanup_free_ char *path = NULL;
1381 _cleanup_closedir_ DIR *d = NULL;
1389 log_debug("Considering %s/%s.", prefix, dirname);
1391 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1392 (sd_id128_from_string(dirname, &id) < 0 ||
1393 sd_id128_get_machine(&mid) < 0 ||
1394 !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
1397 path = strjoin(prefix, "/", dirname, NULL);
1403 log_debug("Failed to open %s: %m", path);
1404 if (errno == ENOENT)
1409 m = hashmap_get(j->directories_by_path, path);
1411 m = new0(Directory, 1);
1418 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1423 path = NULL; /* avoid freeing in cleanup */
1424 j->current_invalidate_counter ++;
1426 log_debug("Directory %s added.", m->path);
1428 } else if (m->is_root)
1431 if (m->wd <= 0 && j->inotify_fd >= 0) {
1433 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1434 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1435 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1438 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1439 inotify_rm_watch(j->inotify_fd, m->wd);
1444 union dirent_storage buf;
1446 r = readdir_r(d, &buf.de, &de);
1450 if (dirent_is_file_with_suffix(de, ".journal") ||
1451 dirent_is_file_with_suffix(de, ".journal~")) {
1452 r = add_file(j, m->path, de->d_name);
1454 log_debug("Failed to add file %s/%s: %s",
1455 m->path, de->d_name, strerror(-r));
1456 r = set_put_error(j, r);
1463 check_network(j, dirfd(d));
1468 static int add_root_directory(sd_journal *j, const char *p) {
1469 _cleanup_closedir_ DIR *d = NULL;
1476 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1477 !path_startswith(p, "/run"))
1484 m = hashmap_get(j->directories_by_path, p);
1486 m = new0(Directory, 1);
1491 m->path = strdup(p);
1497 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1503 j->current_invalidate_counter ++;
1505 log_debug("Root directory %s added.", m->path);
1507 } else if (!m->is_root)
1510 if (m->wd <= 0 && j->inotify_fd >= 0) {
1512 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1513 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1516 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1517 inotify_rm_watch(j->inotify_fd, m->wd);
1520 if (j->no_new_files)
1525 union dirent_storage buf;
1528 r = readdir_r(d, &buf.de, &de);
1532 if (dirent_is_file_with_suffix(de, ".journal") ||
1533 dirent_is_file_with_suffix(de, ".journal~")) {
1534 r = add_file(j, m->path, de->d_name);
1536 log_debug("Failed to add file %s/%s: %s",
1537 m->path, de->d_name, strerror(-r));
1538 r = set_put_error(j, r);
1542 } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
1543 sd_id128_from_string(de->d_name, &id) >= 0) {
1545 r = add_directory(j, m->path, de->d_name);
1547 log_debug("Failed to add directory %s/%s: %s", m->path, de->d_name, strerror(-r));
1551 check_network(j, dirfd(d));
1556 static int remove_directory(sd_journal *j, Directory *d) {
1560 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1562 if (j->inotify_fd >= 0)
1563 inotify_rm_watch(j->inotify_fd, d->wd);
1566 hashmap_remove(j->directories_by_path, d->path);
1569 log_debug("Root directory %s removed.", d->path);
1571 log_debug("Directory %s removed.", d->path);
1579 static int add_search_paths(sd_journal *j) {
1581 const char search_paths[] =
1582 "/run/log/journal\0"
1583 "/var/log/journal\0";
1588 /* We ignore most errors here, since the idea is to only open
1589 * what's actually accessible, and ignore the rest. */
1591 NULSTR_FOREACH(p, search_paths) {
1592 r = add_root_directory(j, p);
1593 if (r < 0 && r != -ENOENT) {
1594 r = set_put_error(j, r);
1603 static int add_current_paths(sd_journal *j) {
1608 assert(j->no_new_files);
1610 /* Simply adds all directories for files we have open as
1611 * "root" directories. We don't expect errors here, so we
1612 * treat them as fatal. */
1614 HASHMAP_FOREACH(f, j->files, i) {
1616 _cleanup_free_ char *dir;
1618 dir = dirname_malloc(f->path);
1622 r = add_root_directory(j, dir);
1624 set_put_error(j, r);
1633 static int allocate_inotify(sd_journal *j) {
1636 if (j->inotify_fd < 0) {
1637 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1638 if (j->inotify_fd < 0)
1642 if (!j->directories_by_wd) {
1643 j->directories_by_wd = hashmap_new(trivial_hash_func, trivial_compare_func);
1644 if (!j->directories_by_wd)
1651 static sd_journal *journal_new(int flags, const char *path) {
1654 j = new0(sd_journal, 1);
1660 j->data_threshold = DEFAULT_DATA_THRESHOLD;
1663 j->path = strdup(path);
1668 j->files = hashmap_new(string_hash_func, string_compare_func);
1669 j->directories_by_path = hashmap_new(string_hash_func, string_compare_func);
1670 j->mmap = mmap_cache_new();
1671 if (!j->files || !j->directories_by_path || !j->mmap)
1677 sd_journal_close(j);
1681 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1688 if (flags & ~(SD_JOURNAL_LOCAL_ONLY|
1689 SD_JOURNAL_RUNTIME_ONLY|
1691 SD_JOURNAL_CURRENT_USER))
1694 j = journal_new(flags, NULL);
1698 r = add_search_paths(j);
1706 sd_journal_close(j);
1711 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1724 j = journal_new(flags, path);
1728 r = add_root_directory(j, path);
1730 set_put_error(j, r);
1738 sd_journal_close(j);
1743 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1754 j = journal_new(flags, NULL);
1758 STRV_FOREACH(path, paths) {
1759 r = add_any_file(j, *path);
1761 log_error("Failed to open %s: %s", *path, strerror(-r));
1766 j->no_new_files = true;
1772 sd_journal_close(j);
1777 _public_ void sd_journal_close(sd_journal *j) {
1784 sd_journal_flush_matches(j);
1786 while ((f = hashmap_steal_first(j->files)))
1787 journal_file_close(f);
1789 hashmap_free(j->files);
1791 while ((d = hashmap_first(j->directories_by_path)))
1792 remove_directory(j, d);
1794 while ((d = hashmap_first(j->directories_by_wd)))
1795 remove_directory(j, d);
1797 hashmap_free(j->directories_by_path);
1798 hashmap_free(j->directories_by_wd);
1800 if (j->inotify_fd >= 0)
1801 close_nointr_nofail(j->inotify_fd);
1804 mmap_cache_unref(j->mmap);
1807 free(j->unique_field);
1808 set_free(j->errors);
1812 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1822 f = j->current_file;
1824 return -EADDRNOTAVAIL;
1826 if (f->current_offset <= 0)
1827 return -EADDRNOTAVAIL;
1829 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1833 *ret = le64toh(o->entry.realtime);
1837 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1846 f = j->current_file;
1848 return -EADDRNOTAVAIL;
1850 if (f->current_offset <= 0)
1851 return -EADDRNOTAVAIL;
1853 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1858 *ret_boot_id = o->entry.boot_id;
1860 r = sd_id128_get_boot(&id);
1864 if (!sd_id128_equal(id, o->entry.boot_id))
1869 *ret = le64toh(o->entry.monotonic);
1874 static bool field_is_valid(const char *field) {
1882 if (startswith(field, "__"))
1885 for (p = field; *p; p++) {
1890 if (*p >= 'A' && *p <= 'Z')
1893 if (*p >= '0' && *p <= '9')
1902 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1905 size_t field_length;
1918 if (!field_is_valid(field))
1921 f = j->current_file;
1923 return -EADDRNOTAVAIL;
1925 if (f->current_offset <= 0)
1926 return -EADDRNOTAVAIL;
1928 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1932 field_length = strlen(field);
1934 n = journal_file_entry_n_items(o);
1935 for (i = 0; i < n; i++) {
1940 p = le64toh(o->entry.items[i].object_offset);
1941 le_hash = o->entry.items[i].hash;
1942 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1946 if (le_hash != o->data.hash)
1949 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1951 if (o->object.flags & OBJECT_COMPRESSED) {
1954 if (uncompress_startswith(o->data.payload, l,
1955 &f->compress_buffer, &f->compress_buffer_size,
1956 field, field_length, '=')) {
1960 if (!uncompress_blob(o->data.payload, l,
1961 &f->compress_buffer, &f->compress_buffer_size, &rsize,
1965 *data = f->compress_buffer;
1966 *size = (size_t) rsize;
1971 return -EPROTONOSUPPORT;
1974 } else if (l >= field_length+1 &&
1975 memcmp(o->data.payload, field, field_length) == 0 &&
1976 o->data.payload[field_length] == '=') {
1980 if ((uint64_t) t != l)
1983 *data = o->data.payload;
1989 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1997 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
2001 l = le64toh(o->object.size) - offsetof(Object, data.payload);
2004 /* We can't read objects larger than 4G on a 32bit machine */
2005 if ((uint64_t) t != l)
2008 if (o->object.flags & OBJECT_COMPRESSED) {
2012 if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold))
2015 *data = f->compress_buffer;
2016 *size = (size_t) rsize;
2018 return -EPROTONOSUPPORT;
2021 *data = o->data.payload;
2028 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2042 f = j->current_file;
2044 return -EADDRNOTAVAIL;
2046 if (f->current_offset <= 0)
2047 return -EADDRNOTAVAIL;
2049 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2053 n = journal_file_entry_n_items(o);
2054 if (j->current_field >= n)
2057 p = le64toh(o->entry.items[j->current_field].object_offset);
2058 le_hash = o->entry.items[j->current_field].hash;
2059 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2063 if (le_hash != o->data.hash)
2066 r = return_data(j, f, o, data, size);
2070 j->current_field ++;
2075 _public_ void sd_journal_restart_data(sd_journal *j) {
2079 j->current_field = 0;
2082 _public_ int sd_journal_get_fd(sd_journal *j) {
2088 if (j->inotify_fd >= 0)
2089 return j->inotify_fd;
2091 r = allocate_inotify(j);
2095 /* Iterate through all dirs again, to add them to the
2097 if (j->no_new_files)
2098 r = add_current_paths(j);
2100 r = add_root_directory(j, j->path);
2102 r = add_search_paths(j);
2106 return j->inotify_fd;
2109 _public_ int sd_journal_get_events(sd_journal *j) {
2115 fd = sd_journal_get_fd(j);
2122 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2130 fd = sd_journal_get_fd(j);
2134 if (!j->on_network) {
2135 *timeout_usec = (uint64_t) -1;
2139 /* If we are on the network we need to regularly check for
2140 * changes manually */
2142 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2146 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2153 /* Is this a subdirectory we watch? */
2154 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2158 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2159 (endswith(e->name, ".journal") ||
2160 endswith(e->name, ".journal~"))) {
2162 /* Event for a journal file */
2164 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2165 r = add_file(j, d->path, e->name);
2167 log_debug("Failed to add file %s/%s: %s",
2168 d->path, e->name, strerror(-r));
2169 set_put_error(j, r);
2172 } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
2174 r = remove_file(j, d->path, e->name);
2176 log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r));
2179 } else if (!d->is_root && e->len == 0) {
2181 /* Event for a subdirectory */
2183 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2184 r = remove_directory(j, d);
2186 log_debug("Failed to remove directory %s: %s", d->path, strerror(-r));
2190 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2192 /* Event for root directory */
2194 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2195 r = add_directory(j, d->path, e->name);
2197 log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r));
2204 if (e->mask & IN_IGNORED)
2207 log_warning("Unknown inotify event.");
2210 static int determine_change(sd_journal *j) {
2215 b = j->current_invalidate_counter != j->last_invalidate_counter;
2216 j->last_invalidate_counter = j->current_invalidate_counter;
2218 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2221 _public_ int sd_journal_process(sd_journal *j) {
2222 uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event);
2223 bool got_something = false;
2228 j->last_process_usec = now(CLOCK_MONOTONIC);
2231 struct inotify_event *e;
2234 l = read(j->inotify_fd, buffer, sizeof(buffer));
2236 if (errno == EAGAIN || errno == EINTR)
2237 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2242 got_something = true;
2244 e = (struct inotify_event*) buffer;
2248 process_inotify_event(j, e);
2250 step = sizeof(struct inotify_event) + e->len;
2251 assert(step <= (size_t) l);
2253 e = (struct inotify_event*) ((uint8_t*) e + step);
2258 return determine_change(j);
2261 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2267 if (j->inotify_fd < 0) {
2269 /* This is the first invocation, hence create the
2271 r = sd_journal_get_fd(j);
2275 /* The journal might have changed since the context
2276 * object was created and we weren't watching before,
2277 * hence don't wait for anything, and return
2279 return determine_change(j);
2282 r = sd_journal_get_timeout(j, &t);
2286 if (t != (uint64_t) -1) {
2289 n = now(CLOCK_MONOTONIC);
2290 t = t > n ? t - n : 0;
2292 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2297 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2298 } while (r == -EINTR);
2303 return sd_journal_process(j);
2306 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2319 HASHMAP_FOREACH(f, j->files, i) {
2322 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2338 *from = MIN(fr, *from);
2344 return first ? 0 : 1;
2347 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2360 HASHMAP_FOREACH(f, j->files, i) {
2363 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2379 *from = MIN(fr, *from);
2385 return first ? 0 : 1;
2388 void journal_print_header(sd_journal *j) {
2391 bool newline = false;
2395 HASHMAP_FOREACH(f, j->files, i) {
2401 journal_file_print_header(f);
2405 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2415 HASHMAP_FOREACH(f, j->files, i) {
2418 if (fstat(f->fd, &st) < 0)
2421 sum += (uint64_t) st.st_blocks * 512ULL;
2428 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2435 if (!field_is_valid(field))
2442 free(j->unique_field);
2443 j->unique_field = f;
2444 j->unique_file = NULL;
2445 j->unique_offset = 0;
2450 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2461 if (!j->unique_field)
2464 k = strlen(j->unique_field);
2466 if (!j->unique_file) {
2467 j->unique_file = hashmap_first(j->files);
2468 if (!j->unique_file)
2470 j->unique_offset = 0;
2480 /* Proceed to next data object in the field's linked list */
2481 if (j->unique_offset == 0) {
2482 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2486 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2488 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2492 j->unique_offset = le64toh(o->data.next_field_offset);
2495 /* We reached the end of the list? Then start again, with the next file */
2496 if (j->unique_offset == 0) {
2499 n = hashmap_next(j->files, j->unique_file->path);
2507 /* We do not use the type context here, but 0 instead,
2508 * so that we can look at this data object at the same
2509 * time as one on another file */
2510 r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o);
2514 /* Let's do the type check by hand, since we used 0 context above. */
2515 if (o->object.type != OBJECT_DATA)
2518 r = return_data(j, j->unique_file, o, &odata, &ol);
2522 /* OK, now let's see if we already returned this data
2523 * object by checking if it exists in the earlier
2524 * traversed files. */
2526 HASHMAP_FOREACH(of, j->files, i) {
2530 if (of == j->unique_file)
2533 /* Skip this file it didn't have any fields
2535 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2536 le64toh(of->header->n_fields) <= 0)
2539 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2550 r = return_data(j, j->unique_file, o, data, l);
2558 _public_ void sd_journal_restart_unique(sd_journal *j) {
2562 j->unique_file = NULL;
2563 j->unique_offset = 0;
2566 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2570 return !j->on_network;
2573 static char *lookup_field(const char *field, void *userdata) {
2574 sd_journal *j = userdata;
2582 r = sd_journal_get_data(j, field, &data, &size);
2584 size > REPLACE_VAR_MAX)
2585 return strdup(field);
2587 d = strlen(field) + 1;
2589 return strndup((const char*) data + d, size - d);
2592 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2596 _cleanup_free_ char *text = NULL, *cid = NULL;
2605 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2609 cid = strndup((const char*) data + 11, size - 11);
2613 r = sd_id128_from_string(cid, &id);
2617 r = catalog_get(CATALOG_DATABASE, id, &text);
2621 t = replace_var(text, lookup_field, j);
2629 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2633 return catalog_get(CATALOG_DATABASE, id, ret);
2636 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2640 j->data_threshold = sz;
2644 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2650 *sz = j->data_threshold;