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 static bool journal_pid_changed(sd_journal *j) {
56 /* We don't support people creating a journal object and
57 * keeping it around over a fork(). Let's complain. */
59 return j->original_pid != getpid();
62 /* We return an error here only if we didn't manage to
63 memorize the real error. */
64 static int set_put_error(sd_journal *j, int r) {
70 k = set_ensure_allocated(&j->errors, trivial_hash_func, trivial_compare_func);
74 return set_put(j->errors, INT_TO_PTR(r));
77 static void detach_location(sd_journal *j) {
83 j->current_file = NULL;
86 HASHMAP_FOREACH(f, j->files, i)
87 f->current_offset = 0;
90 static void reset_location(sd_journal *j) {
94 zero(j->current_location);
97 static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
99 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
101 assert(o->object.type == OBJECT_ENTRY);
104 l->seqnum = le64toh(o->entry.seqnum);
105 l->seqnum_id = f->header->seqnum_id;
106 l->realtime = le64toh(o->entry.realtime);
107 l->monotonic = le64toh(o->entry.monotonic);
108 l->boot_id = o->entry.boot_id;
109 l->xor_hash = le64toh(o->entry.xor_hash);
111 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
114 static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o,
115 direction_t direction, uint64_t offset) {
117 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
121 init_location(&j->current_location, type, f, o);
124 j->current_field = 0;
126 f->last_direction = direction;
127 f->current_offset = offset;
130 static int match_is_valid(const void *data, size_t size) {
138 if (startswith(data, "__"))
142 for (p = b; p < b + size; p++) {
150 if (*p >= 'A' && *p <= 'Z')
153 if (*p >= '0' && *p <= '9')
162 static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
163 const uint8_t *a = _a, *b = _b;
166 for (j = 0; j < s && j < t; j++) {
175 assert_not_reached("\"=\" not found");
178 static Match *match_new(Match *p, MatchType t) {
189 LIST_PREPEND(Match, matches, p->matches, m);
195 static void match_free(Match *m) {
199 match_free(m->matches);
202 LIST_REMOVE(Match, matches, m->parent->matches, m);
208 static void match_free_if_empty(Match *m) {
209 if (!m || m->matches)
215 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
216 Match *l3, *l4, *add_here = NULL, *m;
221 if (journal_pid_changed(j))
230 if (!match_is_valid(data, size))
237 * level 4: concrete matches */
240 j->level0 = match_new(NULL, MATCH_AND_TERM);
246 j->level1 = match_new(j->level0, MATCH_OR_TERM);
252 j->level2 = match_new(j->level1, MATCH_AND_TERM);
257 assert(j->level0->type == MATCH_AND_TERM);
258 assert(j->level1->type == MATCH_OR_TERM);
259 assert(j->level2->type == MATCH_AND_TERM);
261 le_hash = htole64(hash64(data, size));
263 LIST_FOREACH(matches, l3, j->level2->matches) {
264 assert(l3->type == MATCH_OR_TERM);
266 LIST_FOREACH(matches, l4, l3->matches) {
267 assert(l4->type == MATCH_DISCRETE);
269 /* Exactly the same match already? Then ignore
271 if (l4->le_hash == le_hash &&
273 memcmp(l4->data, data, size) == 0)
276 /* Same field? Then let's add this to this OR term */
277 if (same_field(data, size, l4->data, l4->size)) {
288 add_here = match_new(j->level2, MATCH_OR_TERM);
293 m = match_new(add_here, MATCH_DISCRETE);
297 m->le_hash = le_hash;
299 m->data = memdup(data, size);
308 match_free_if_empty(add_here);
309 match_free_if_empty(j->level2);
310 match_free_if_empty(j->level1);
311 match_free_if_empty(j->level0);
316 _public_ int sd_journal_add_conjunction(sd_journal *j) {
319 if (journal_pid_changed(j))
328 if (!j->level1->matches)
337 _public_ int sd_journal_add_disjunction(sd_journal *j) {
340 if (journal_pid_changed(j))
352 if (!j->level2->matches)
359 static char *match_make_string(Match *m) {
362 bool enclose = false;
365 return strdup("none");
367 if (m->type == MATCH_DISCRETE)
368 return strndup(m->data, m->size);
371 LIST_FOREACH(matches, i, m->matches) {
374 t = match_make_string(i);
381 k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t, NULL);
396 r = strjoin("(", p, ")", NULL);
404 char *journal_make_match_string(sd_journal *j) {
407 return match_make_string(j->level0);
410 _public_ void sd_journal_flush_matches(sd_journal *j) {
415 match_free(j->level0);
417 j->level0 = j->level1 = j->level2 = NULL;
422 static int compare_entry_order(JournalFile *af, Object *_ao,
423 JournalFile *bf, uint64_t bp) {
433 /* The mmap cache might invalidate the object from the first
434 * file if we look at the one from the second file. Hence
435 * temporarily copy the header of the first one, and look at
437 ao = alloca(offsetof(EntryObject, items));
438 memcpy(ao, _ao, offsetof(EntryObject, items));
440 r = journal_file_move_to_object(bf, OBJECT_ENTRY, bp, &bo);
442 return strcmp(af->path, bf->path);
444 /* We operate on two different files here, hence we can access
445 * two objects at the same time, which we normally can't.
447 * If contents and timestamps match, these entries are
448 * identical, even if the seqnum does not match */
450 if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) &&
451 ao->entry.monotonic == bo->entry.monotonic &&
452 ao->entry.realtime == bo->entry.realtime &&
453 ao->entry.xor_hash == bo->entry.xor_hash)
456 if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) {
458 /* If this is from the same seqnum source, compare
460 a = le64toh(ao->entry.seqnum);
461 b = le64toh(bo->entry.seqnum);
468 /* Wow! This is weird, different data but the same
469 * seqnums? Something is borked, but let's make the
470 * best of it and compare by time. */
473 if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) {
475 /* If the boot id matches compare monotonic time */
476 a = le64toh(ao->entry.monotonic);
477 b = le64toh(bo->entry.monotonic);
485 /* Otherwise compare UTC time */
486 a = le64toh(ao->entry.realtime);
487 b = le64toh(bo->entry.realtime);
494 /* Finally, compare by contents */
495 a = le64toh(ao->entry.xor_hash);
496 b = le64toh(bo->entry.xor_hash);
506 _pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) {
512 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
514 if (l->monotonic_set &&
515 sd_id128_equal(ao->entry.boot_id, l->boot_id) &&
517 le64toh(ao->entry.realtime) == l->realtime &&
519 le64toh(ao->entry.xor_hash) == l->xor_hash)
523 sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) {
525 a = le64toh(ao->entry.seqnum);
533 if (l->monotonic_set &&
534 sd_id128_equal(ao->entry.boot_id, l->boot_id)) {
536 a = le64toh(ao->entry.monotonic);
538 if (a < l->monotonic)
540 if (a > l->monotonic)
544 if (l->realtime_set) {
546 a = le64toh(ao->entry.realtime);
554 if (l->xor_hash_set) {
555 a = le64toh(ao->entry.xor_hash);
566 static int next_for_match(
570 uint64_t after_offset,
571 direction_t direction,
583 if (m->type == MATCH_DISCRETE) {
586 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
590 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
592 } else if (m->type == MATCH_OR_TERM) {
595 /* Find the earliest match beyond after_offset */
597 LIST_FOREACH(matches, i, m->matches) {
600 r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
604 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
612 } else if (m->type == MATCH_AND_TERM) {
613 Match *i, *last_moved;
615 /* Always jump to the next matching entry and repeat
616 * this until we find an offset that matches for all
622 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
626 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
627 last_moved = m->matches;
629 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
632 r = next_for_match(j, i, f, np, direction, NULL, &cp);
636 assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
637 if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
646 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
658 static int find_location_for_match(
662 direction_t direction,
672 if (m->type == MATCH_DISCRETE) {
675 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
679 /* FIXME: missing: find by monotonic */
681 if (j->current_location.type == LOCATION_HEAD)
682 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
683 if (j->current_location.type == LOCATION_TAIL)
684 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
685 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
686 return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
687 if (j->current_location.monotonic_set) {
688 r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
692 if (j->current_location.realtime_set)
693 return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
695 return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
697 } else if (m->type == MATCH_OR_TERM) {
702 /* Find the earliest match */
704 LIST_FOREACH(matches, i, m->matches) {
707 r = find_location_for_match(j, i, f, direction, NULL, &cp);
711 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
719 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
734 assert(m->type == MATCH_AND_TERM);
736 /* First jump to the last match, and then find the
737 * next one where all matches match */
742 LIST_FOREACH(matches, i, m->matches) {
745 r = find_location_for_match(j, i, f, direction, NULL, &cp);
749 if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
753 return next_for_match(j, m, f, np, direction, ret, offset);
757 static int find_location_with_matches(
760 direction_t direction,
772 /* No matches is simple */
774 if (j->current_location.type == LOCATION_HEAD)
775 return journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, ret, offset);
776 if (j->current_location.type == LOCATION_TAIL)
777 return journal_file_next_entry(f, NULL, 0, DIRECTION_UP, ret, offset);
778 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
779 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
780 if (j->current_location.monotonic_set) {
781 r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
785 if (j->current_location.realtime_set)
786 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
788 return journal_file_next_entry(f, NULL, 0, direction, ret, offset);
790 return find_location_for_match(j, j->level0, f, direction, ret, offset);
793 static int next_with_matches(
796 direction_t direction,
811 /* No matches is easy. We simple advance the file
814 return journal_file_next_entry(f, c, cp, direction, ret, offset);
816 /* If we have a match then we look for the next matching entry
817 * with an offset at least one step larger */
818 return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset);
821 static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) {
829 if (f->last_direction == direction && f->current_offset > 0) {
830 cp = f->current_offset;
832 r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c);
836 r = next_with_matches(j, f, direction, &c, &cp);
840 r = find_location_with_matches(j, f, direction, &c, &cp);
845 /* OK, we found the spot, now let's advance until an entry
846 * that is actually different from what we were previously
847 * looking at. This is necessary to handle entries which exist
848 * in two (or more) journal files, and which shall all be
849 * suppressed but one. */
854 if (j->current_location.type == LOCATION_DISCRETE) {
857 k = compare_with_location(f, c, &j->current_location);
858 if (direction == DIRECTION_DOWN)
873 r = next_with_matches(j, f, direction, &c, &cp);
879 static int real_journal_next(sd_journal *j, direction_t direction) {
880 JournalFile *f, *new_file = NULL;
881 uint64_t new_offset = 0;
889 if (journal_pid_changed(j))
892 HASHMAP_FOREACH(f, j->files, i) {
895 r = next_beyond_location(j, f, direction, &o, &p);
897 log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r));
907 k = compare_entry_order(f, o, new_file, new_offset);
909 found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
921 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_offset, &o);
925 set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset);
930 _public_ int sd_journal_next(sd_journal *j) {
931 return real_journal_next(j, DIRECTION_DOWN);
934 _public_ int sd_journal_previous(sd_journal *j) {
935 return real_journal_next(j, DIRECTION_UP);
938 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
943 if (journal_pid_changed(j))
947 /* If this is not a discrete skip, then at least
948 * resolve the current location */
949 if (j->current_location.type != LOCATION_DISCRETE)
950 return real_journal_next(j, direction);
956 r = real_journal_next(j, direction);
970 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
971 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
974 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
975 return real_journal_next_skip(j, DIRECTION_UP, skip);
978 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
981 char bid[33], sid[33];
985 if (journal_pid_changed(j))
990 if (!j->current_file || j->current_file->current_offset <= 0)
991 return -EADDRNOTAVAIL;
993 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
997 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
998 sd_id128_to_string(o->entry.boot_id, bid);
1000 if (asprintf(cursor,
1001 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
1002 sid, le64toh(o->entry.seqnum),
1003 bid, le64toh(o->entry.monotonic),
1004 le64toh(o->entry.realtime),
1005 le64toh(o->entry.xor_hash)) < 0)
1011 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
1014 unsigned long long seqnum, monotonic, realtime, xor_hash;
1016 seqnum_id_set = false,
1018 boot_id_set = false,
1019 monotonic_set = false,
1020 realtime_set = false,
1021 xor_hash_set = false;
1022 sd_id128_t seqnum_id, boot_id;
1026 if (journal_pid_changed(j))
1028 if (isempty(cursor))
1031 FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
1035 if (l < 2 || w[1] != '=')
1038 item = strndup(w, l);
1045 seqnum_id_set = true;
1046 k = sd_id128_from_string(item+2, &seqnum_id);
1051 if (sscanf(item+2, "%llx", &seqnum) != 1)
1057 k = sd_id128_from_string(item+2, &boot_id);
1061 monotonic_set = true;
1062 if (sscanf(item+2, "%llx", &monotonic) != 1)
1067 realtime_set = true;
1068 if (sscanf(item+2, "%llx", &realtime) != 1)
1073 xor_hash_set = true;
1074 if (sscanf(item+2, "%llx", &xor_hash) != 1)
1085 if ((!seqnum_set || !seqnum_id_set) &&
1086 (!monotonic_set || !boot_id_set) &&
1092 j->current_location.type = LOCATION_SEEK;
1095 j->current_location.realtime = (uint64_t) realtime;
1096 j->current_location.realtime_set = true;
1099 if (seqnum_set && seqnum_id_set) {
1100 j->current_location.seqnum = (uint64_t) seqnum;
1101 j->current_location.seqnum_id = seqnum_id;
1102 j->current_location.seqnum_set = true;
1105 if (monotonic_set && boot_id_set) {
1106 j->current_location.monotonic = (uint64_t) monotonic;
1107 j->current_location.boot_id = boot_id;
1108 j->current_location.monotonic_set = true;
1112 j->current_location.xor_hash = (uint64_t) xor_hash;
1113 j->current_location.xor_hash_set = true;
1119 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1127 if (journal_pid_changed(j))
1129 if (isempty(cursor))
1132 if (!j->current_file || j->current_file->current_offset <= 0)
1133 return -EADDRNOTAVAIL;
1135 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1139 FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
1140 _cleanup_free_ char *item = NULL;
1142 unsigned long long ll;
1145 if (l < 2 || w[1] != '=')
1148 item = strndup(w, l);
1155 k = sd_id128_from_string(item+2, &id);
1158 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1163 if (sscanf(item+2, "%llx", &ll) != 1)
1165 if (ll != le64toh(o->entry.seqnum))
1170 k = sd_id128_from_string(item+2, &id);
1173 if (!sd_id128_equal(id, o->entry.boot_id))
1178 if (sscanf(item+2, "%llx", &ll) != 1)
1180 if (ll != le64toh(o->entry.monotonic))
1185 if (sscanf(item+2, "%llx", &ll) != 1)
1187 if (ll != le64toh(o->entry.realtime))
1192 if (sscanf(item+2, "%llx", &ll) != 1)
1194 if (ll != le64toh(o->entry.xor_hash))
1204 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1207 if (journal_pid_changed(j))
1211 j->current_location.type = LOCATION_SEEK;
1212 j->current_location.boot_id = boot_id;
1213 j->current_location.monotonic = usec;
1214 j->current_location.monotonic_set = true;
1219 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1222 if (journal_pid_changed(j))
1226 j->current_location.type = LOCATION_SEEK;
1227 j->current_location.realtime = usec;
1228 j->current_location.realtime_set = true;
1233 _public_ int sd_journal_seek_head(sd_journal *j) {
1236 if (journal_pid_changed(j))
1240 j->current_location.type = LOCATION_HEAD;
1245 _public_ int sd_journal_seek_tail(sd_journal *j) {
1248 if (journal_pid_changed(j))
1252 j->current_location.type = LOCATION_TAIL;
1257 static void check_network(sd_journal *j, int fd) {
1265 if (fstatfs(fd, &sfs) < 0)
1269 F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1270 F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
1271 F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
1272 F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
1273 F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
1276 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1277 const char *full, *tilded, *atted;
1279 full = strappend(prefix, ".journal");
1280 tilded = strappenda(full, "~");
1281 atted = strappenda(prefix, "@");
1283 return streq(filename, full) ||
1284 streq(filename, tilded) ||
1285 startswith(filename, atted);
1288 static bool file_type_wanted(int flags, const char *filename) {
1289 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1292 /* no flags set → every type is OK */
1293 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1296 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1299 if (flags & SD_JOURNAL_CURRENT_USER) {
1300 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1302 assert_se(snprintf(prefix, sizeof(prefix), "user-%lu", (unsigned long) getuid())
1303 < (int) sizeof(prefix));
1305 if (file_has_type_prefix(prefix, filename))
1312 static int add_any_file(sd_journal *j, const char *path) {
1319 if (hashmap_get(j->files, path))
1322 if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1323 log_warning("Too many open journal files, not adding %s.", path);
1324 return set_put_error(j, -ETOOMANYREFS);
1327 r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
1331 /* journal_file_dump(f); */
1333 r = hashmap_put(j->files, f->path, f);
1335 journal_file_close(f);
1339 log_debug("File %s added.", f->path);
1341 check_network(j, f->fd);
1343 j->current_invalidate_counter ++;
1348 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1349 _cleanup_free_ char *path = NULL;
1356 if (j->no_new_files ||
1357 !file_type_wanted(j->flags, filename))
1360 path = strjoin(prefix, "/", filename, NULL);
1364 r = add_any_file(j, path);
1370 static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
1378 path = strjoin(prefix, "/", filename, NULL);
1382 f = hashmap_get(j->files, path);
1387 hashmap_remove(j->files, f->path);
1389 log_debug("File %s removed.", f->path);
1391 if (j->current_file == f) {
1392 j->current_file = NULL;
1393 j->current_field = 0;
1396 if (j->unique_file == f) {
1397 j->unique_file = NULL;
1398 j->unique_offset = 0;
1401 journal_file_close(f);
1403 j->current_invalidate_counter ++;
1408 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
1409 _cleanup_free_ char *path = NULL;
1411 _cleanup_closedir_ DIR *d = NULL;
1419 log_debug("Considering %s/%s.", prefix, dirname);
1421 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1422 (sd_id128_from_string(dirname, &id) < 0 ||
1423 sd_id128_get_machine(&mid) < 0 ||
1424 !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
1427 path = strjoin(prefix, "/", dirname, NULL);
1433 log_debug("Failed to open %s: %m", path);
1434 if (errno == ENOENT)
1439 m = hashmap_get(j->directories_by_path, path);
1441 m = new0(Directory, 1);
1448 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1453 path = NULL; /* avoid freeing in cleanup */
1454 j->current_invalidate_counter ++;
1456 log_debug("Directory %s added.", m->path);
1458 } else if (m->is_root)
1461 if (m->wd <= 0 && j->inotify_fd >= 0) {
1463 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1464 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1465 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1468 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1469 inotify_rm_watch(j->inotify_fd, m->wd);
1474 union dirent_storage buf;
1476 r = readdir_r(d, &buf.de, &de);
1480 if (dirent_is_file_with_suffix(de, ".journal") ||
1481 dirent_is_file_with_suffix(de, ".journal~")) {
1482 r = add_file(j, m->path, de->d_name);
1484 log_debug("Failed to add file %s/%s: %s",
1485 m->path, de->d_name, strerror(-r));
1486 r = set_put_error(j, r);
1493 check_network(j, dirfd(d));
1498 static int add_root_directory(sd_journal *j, const char *p) {
1499 _cleanup_closedir_ DIR *d = NULL;
1506 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1507 !path_startswith(p, "/run"))
1514 m = hashmap_get(j->directories_by_path, p);
1516 m = new0(Directory, 1);
1521 m->path = strdup(p);
1527 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1533 j->current_invalidate_counter ++;
1535 log_debug("Root directory %s added.", m->path);
1537 } else if (!m->is_root)
1540 if (m->wd <= 0 && j->inotify_fd >= 0) {
1542 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1543 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1546 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1547 inotify_rm_watch(j->inotify_fd, m->wd);
1550 if (j->no_new_files)
1555 union dirent_storage buf;
1558 r = readdir_r(d, &buf.de, &de);
1562 if (dirent_is_file_with_suffix(de, ".journal") ||
1563 dirent_is_file_with_suffix(de, ".journal~")) {
1564 r = add_file(j, m->path, de->d_name);
1566 log_debug("Failed to add file %s/%s: %s",
1567 m->path, de->d_name, strerror(-r));
1568 r = set_put_error(j, r);
1572 } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
1573 sd_id128_from_string(de->d_name, &id) >= 0) {
1575 r = add_directory(j, m->path, de->d_name);
1577 log_debug("Failed to add directory %s/%s: %s", m->path, de->d_name, strerror(-r));
1581 check_network(j, dirfd(d));
1586 static int remove_directory(sd_journal *j, Directory *d) {
1590 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1592 if (j->inotify_fd >= 0)
1593 inotify_rm_watch(j->inotify_fd, d->wd);
1596 hashmap_remove(j->directories_by_path, d->path);
1599 log_debug("Root directory %s removed.", d->path);
1601 log_debug("Directory %s removed.", d->path);
1609 static int add_search_paths(sd_journal *j) {
1611 const char search_paths[] =
1612 "/run/log/journal\0"
1613 "/var/log/journal\0";
1618 /* We ignore most errors here, since the idea is to only open
1619 * what's actually accessible, and ignore the rest. */
1621 NULSTR_FOREACH(p, search_paths) {
1622 r = add_root_directory(j, p);
1623 if (r < 0 && r != -ENOENT) {
1624 r = set_put_error(j, r);
1633 static int add_current_paths(sd_journal *j) {
1638 assert(j->no_new_files);
1640 /* Simply adds all directories for files we have open as
1641 * "root" directories. We don't expect errors here, so we
1642 * treat them as fatal. */
1644 HASHMAP_FOREACH(f, j->files, i) {
1646 _cleanup_free_ char *dir;
1648 dir = dirname_malloc(f->path);
1652 r = add_root_directory(j, dir);
1654 set_put_error(j, r);
1663 static int allocate_inotify(sd_journal *j) {
1666 if (j->inotify_fd < 0) {
1667 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1668 if (j->inotify_fd < 0)
1672 if (!j->directories_by_wd) {
1673 j->directories_by_wd = hashmap_new(trivial_hash_func, trivial_compare_func);
1674 if (!j->directories_by_wd)
1681 static sd_journal *journal_new(int flags, const char *path) {
1684 j = new0(sd_journal, 1);
1688 j->original_pid = getpid();
1691 j->data_threshold = DEFAULT_DATA_THRESHOLD;
1694 j->path = strdup(path);
1699 j->files = hashmap_new(string_hash_func, string_compare_func);
1700 j->directories_by_path = hashmap_new(string_hash_func, string_compare_func);
1701 j->mmap = mmap_cache_new();
1702 if (!j->files || !j->directories_by_path || !j->mmap)
1708 sd_journal_close(j);
1712 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1719 if (flags & ~(SD_JOURNAL_LOCAL_ONLY|
1720 SD_JOURNAL_RUNTIME_ONLY|
1722 SD_JOURNAL_CURRENT_USER))
1725 j = journal_new(flags, NULL);
1729 r = add_search_paths(j);
1737 sd_journal_close(j);
1742 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1755 j = journal_new(flags, path);
1759 r = add_root_directory(j, path);
1761 set_put_error(j, r);
1769 sd_journal_close(j);
1774 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1785 j = journal_new(flags, NULL);
1789 STRV_FOREACH(path, paths) {
1790 r = add_any_file(j, *path);
1792 log_error("Failed to open %s: %s", *path, strerror(-r));
1797 j->no_new_files = true;
1803 sd_journal_close(j);
1808 _public_ void sd_journal_close(sd_journal *j) {
1815 sd_journal_flush_matches(j);
1817 while ((f = hashmap_steal_first(j->files)))
1818 journal_file_close(f);
1820 hashmap_free(j->files);
1822 while ((d = hashmap_first(j->directories_by_path)))
1823 remove_directory(j, d);
1825 while ((d = hashmap_first(j->directories_by_wd)))
1826 remove_directory(j, d);
1828 hashmap_free(j->directories_by_path);
1829 hashmap_free(j->directories_by_wd);
1831 if (j->inotify_fd >= 0)
1832 close_nointr_nofail(j->inotify_fd);
1835 mmap_cache_unref(j->mmap);
1838 free(j->unique_field);
1839 set_free(j->errors);
1843 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1850 if (journal_pid_changed(j))
1855 f = j->current_file;
1857 return -EADDRNOTAVAIL;
1859 if (f->current_offset <= 0)
1860 return -EADDRNOTAVAIL;
1862 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1866 *ret = le64toh(o->entry.realtime);
1870 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1878 if (journal_pid_changed(j))
1881 f = j->current_file;
1883 return -EADDRNOTAVAIL;
1885 if (f->current_offset <= 0)
1886 return -EADDRNOTAVAIL;
1888 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1893 *ret_boot_id = o->entry.boot_id;
1895 r = sd_id128_get_boot(&id);
1899 if (!sd_id128_equal(id, o->entry.boot_id))
1904 *ret = le64toh(o->entry.monotonic);
1909 static bool field_is_valid(const char *field) {
1917 if (startswith(field, "__"))
1920 for (p = field; *p; p++) {
1925 if (*p >= 'A' && *p <= 'Z')
1928 if (*p >= '0' && *p <= '9')
1937 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1940 size_t field_length;
1946 if (journal_pid_changed(j))
1955 if (!field_is_valid(field))
1958 f = j->current_file;
1960 return -EADDRNOTAVAIL;
1962 if (f->current_offset <= 0)
1963 return -EADDRNOTAVAIL;
1965 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1969 field_length = strlen(field);
1971 n = journal_file_entry_n_items(o);
1972 for (i = 0; i < n; i++) {
1977 p = le64toh(o->entry.items[i].object_offset);
1978 le_hash = o->entry.items[i].hash;
1979 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1983 if (le_hash != o->data.hash)
1986 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1988 if (o->object.flags & OBJECT_COMPRESSED) {
1991 if (uncompress_startswith(o->data.payload, l,
1992 &f->compress_buffer, &f->compress_buffer_size,
1993 field, field_length, '=')) {
1997 if (!uncompress_blob(o->data.payload, l,
1998 &f->compress_buffer, &f->compress_buffer_size, &rsize,
2002 *data = f->compress_buffer;
2003 *size = (size_t) rsize;
2008 return -EPROTONOSUPPORT;
2011 } else if (l >= field_length+1 &&
2012 memcmp(o->data.payload, field, field_length) == 0 &&
2013 o->data.payload[field_length] == '=') {
2017 if ((uint64_t) t != l)
2020 *data = o->data.payload;
2026 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2034 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
2038 l = le64toh(o->object.size) - offsetof(Object, data.payload);
2041 /* We can't read objects larger than 4G on a 32bit machine */
2042 if ((uint64_t) t != l)
2045 if (o->object.flags & OBJECT_COMPRESSED) {
2049 if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold))
2052 *data = f->compress_buffer;
2053 *size = (size_t) rsize;
2055 return -EPROTONOSUPPORT;
2058 *data = o->data.payload;
2065 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2074 if (journal_pid_changed(j))
2081 f = j->current_file;
2083 return -EADDRNOTAVAIL;
2085 if (f->current_offset <= 0)
2086 return -EADDRNOTAVAIL;
2088 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2092 n = journal_file_entry_n_items(o);
2093 if (j->current_field >= n)
2096 p = le64toh(o->entry.items[j->current_field].object_offset);
2097 le_hash = o->entry.items[j->current_field].hash;
2098 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2102 if (le_hash != o->data.hash)
2105 r = return_data(j, f, o, data, size);
2109 j->current_field ++;
2114 _public_ void sd_journal_restart_data(sd_journal *j) {
2118 j->current_field = 0;
2121 _public_ int sd_journal_get_fd(sd_journal *j) {
2126 if (journal_pid_changed(j))
2129 if (j->inotify_fd >= 0)
2130 return j->inotify_fd;
2132 r = allocate_inotify(j);
2136 /* Iterate through all dirs again, to add them to the
2138 if (j->no_new_files)
2139 r = add_current_paths(j);
2141 r = add_root_directory(j, j->path);
2143 r = add_search_paths(j);
2147 return j->inotify_fd;
2150 _public_ int sd_journal_get_events(sd_journal *j) {
2155 if (journal_pid_changed(j))
2158 fd = sd_journal_get_fd(j);
2165 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2170 if (journal_pid_changed(j))
2175 fd = sd_journal_get_fd(j);
2179 if (!j->on_network) {
2180 *timeout_usec = (uint64_t) -1;
2184 /* If we are on the network we need to regularly check for
2185 * changes manually */
2187 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2191 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2198 /* Is this a subdirectory we watch? */
2199 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2203 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2204 (endswith(e->name, ".journal") ||
2205 endswith(e->name, ".journal~"))) {
2207 /* Event for a journal file */
2209 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2210 r = add_file(j, d->path, e->name);
2212 log_debug("Failed to add file %s/%s: %s",
2213 d->path, e->name, strerror(-r));
2214 set_put_error(j, r);
2217 } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
2219 r = remove_file(j, d->path, e->name);
2221 log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r));
2224 } else if (!d->is_root && e->len == 0) {
2226 /* Event for a subdirectory */
2228 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2229 r = remove_directory(j, d);
2231 log_debug("Failed to remove directory %s: %s", d->path, strerror(-r));
2235 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2237 /* Event for root directory */
2239 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2240 r = add_directory(j, d->path, e->name);
2242 log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r));
2249 if (e->mask & IN_IGNORED)
2252 log_warning("Unknown inotify event.");
2255 static int determine_change(sd_journal *j) {
2260 b = j->current_invalidate_counter != j->last_invalidate_counter;
2261 j->last_invalidate_counter = j->current_invalidate_counter;
2263 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2266 _public_ int sd_journal_process(sd_journal *j) {
2267 uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event);
2268 bool got_something = false;
2272 if (journal_pid_changed(j))
2275 j->last_process_usec = now(CLOCK_MONOTONIC);
2278 struct inotify_event *e;
2281 l = read(j->inotify_fd, buffer, sizeof(buffer));
2283 if (errno == EAGAIN || errno == EINTR)
2284 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2289 got_something = true;
2291 e = (struct inotify_event*) buffer;
2295 process_inotify_event(j, e);
2297 step = sizeof(struct inotify_event) + e->len;
2298 assert(step <= (size_t) l);
2300 e = (struct inotify_event*) ((uint8_t*) e + step);
2305 return determine_change(j);
2308 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2314 if (journal_pid_changed(j))
2317 if (j->inotify_fd < 0) {
2319 /* This is the first invocation, hence create the
2321 r = sd_journal_get_fd(j);
2325 /* The journal might have changed since the context
2326 * object was created and we weren't watching before,
2327 * hence don't wait for anything, and return
2329 return determine_change(j);
2332 r = sd_journal_get_timeout(j, &t);
2336 if (t != (uint64_t) -1) {
2339 n = now(CLOCK_MONOTONIC);
2340 t = t > n ? t - n : 0;
2342 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2347 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2348 } while (r == -EINTR);
2353 return sd_journal_process(j);
2356 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2364 if (journal_pid_changed(j))
2371 HASHMAP_FOREACH(f, j->files, i) {
2374 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2390 *from = MIN(fr, *from);
2396 return first ? 0 : 1;
2399 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2407 if (journal_pid_changed(j))
2414 HASHMAP_FOREACH(f, j->files, i) {
2417 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2433 *from = MIN(fr, *from);
2439 return first ? 0 : 1;
2442 void journal_print_header(sd_journal *j) {
2445 bool newline = false;
2449 HASHMAP_FOREACH(f, j->files, i) {
2455 journal_file_print_header(f);
2459 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2466 if (journal_pid_changed(j))
2471 HASHMAP_FOREACH(f, j->files, i) {
2474 if (fstat(f->fd, &st) < 0)
2477 sum += (uint64_t) st.st_blocks * 512ULL;
2484 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2489 if (journal_pid_changed(j))
2493 if (!field_is_valid(field))
2500 free(j->unique_field);
2501 j->unique_field = f;
2502 j->unique_file = NULL;
2503 j->unique_offset = 0;
2508 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2515 if (journal_pid_changed(j))
2521 if (!j->unique_field)
2524 k = strlen(j->unique_field);
2526 if (!j->unique_file) {
2527 j->unique_file = hashmap_first(j->files);
2528 if (!j->unique_file)
2530 j->unique_offset = 0;
2540 /* Proceed to next data object in the field's linked list */
2541 if (j->unique_offset == 0) {
2542 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2546 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2548 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2552 j->unique_offset = le64toh(o->data.next_field_offset);
2555 /* We reached the end of the list? Then start again, with the next file */
2556 if (j->unique_offset == 0) {
2559 n = hashmap_next(j->files, j->unique_file->path);
2567 /* We do not use the type context here, but 0 instead,
2568 * so that we can look at this data object at the same
2569 * time as one on another file */
2570 r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o);
2574 /* Let's do the type check by hand, since we used 0 context above. */
2575 if (o->object.type != OBJECT_DATA)
2578 r = return_data(j, j->unique_file, o, &odata, &ol);
2582 /* OK, now let's see if we already returned this data
2583 * object by checking if it exists in the earlier
2584 * traversed files. */
2586 HASHMAP_FOREACH(of, j->files, i) {
2590 if (of == j->unique_file)
2593 /* Skip this file it didn't have any fields
2595 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2596 le64toh(of->header->n_fields) <= 0)
2599 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2610 r = return_data(j, j->unique_file, o, data, l);
2618 _public_ void sd_journal_restart_unique(sd_journal *j) {
2622 j->unique_file = NULL;
2623 j->unique_offset = 0;
2626 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2629 if (journal_pid_changed(j))
2632 return !j->on_network;
2635 static char *lookup_field(const char *field, void *userdata) {
2636 sd_journal *j = userdata;
2644 r = sd_journal_get_data(j, field, &data, &size);
2646 size > REPLACE_VAR_MAX)
2647 return strdup(field);
2649 d = strlen(field) + 1;
2651 return strndup((const char*) data + d, size - d);
2654 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2658 _cleanup_free_ char *text = NULL, *cid = NULL;
2664 if (journal_pid_changed(j))
2669 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2673 cid = strndup((const char*) data + 11, size - 11);
2677 r = sd_id128_from_string(cid, &id);
2681 r = catalog_get(CATALOG_DATABASE, id, &text);
2685 t = replace_var(text, lookup_field, j);
2693 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2697 return catalog_get(CATALOG_DATABASE, id, ret);
2700 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2703 if (journal_pid_changed(j))
2706 j->data_threshold = sz;
2710 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2713 if (journal_pid_changed(j))
2718 *sz = j->data_threshold;