-
-int journal_file_prev_entry(JournalFile *f, Object *o, Object **ret, uint64_t *offset) {
- uint64_t np;
- int r;
-
- assert(f);
-
- if (!o)
- np = le64toh(f->header->tail_entry_offset);
- else {
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EINVAL;
-
- np = le64toh(o->entry.prev_entry_offset);
- }
-
- if (np == 0)
- return 0;
-
- r = journal_file_move_to_object(f, np, &o);
- if (r < 0)
- return r;
-
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EBADMSG;
-
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = np;
-
- return 1;
-}
-
-int journal_file_find_first_entry(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset) {
- uint64_t p, osize, hash, h;
- int r;
-
- assert(f);
- assert(data || size == 0);
-
- osize = offsetof(Object, data.payload) + size;
-
- hash = hash64(data, size);
- h = hash % (le64toh(f->header->hash_table_size) / sizeof(HashItem));
- p = le64toh(f->hash_table[h].head_hash_offset);
-
- while (p != 0) {
- Object *o;
-
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- if (le64toh(o->object.type) != OBJECT_DATA)
- return -EBADMSG;
-
- if (le64toh(o->object.size) == osize &&
- memcmp(o->data.payload, data, size) == 0) {
-
- if (le64toh(o->data.hash) != hash)
- return -EBADMSG;
-
- if (o->data.head_entry_offset == 0)
- return 0;
-
- p = le64toh(o->data.head_entry_offset);
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EBADMSG;
-
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = p;
-
- return 1;
- }
-
- p = le64toh(o->data.next_hash_offset);
- }
-
- return 0;
-}
-
-int journal_file_find_last_entry(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset) {
- uint64_t p, osize, hash, h;
- int r;
-
- assert(f);
- assert(data || size == 0);
-
- osize = offsetof(Object, data.payload) + size;
-
- hash = hash64(data, size);
- h = hash % (le64toh(f->header->hash_table_size) / sizeof(HashItem));
- p = le64toh(f->hash_table[h].tail_hash_offset);
-
- while (p != 0) {
- Object *o;
-
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- if (le64toh(o->object.type) != OBJECT_DATA)
- return -EBADMSG;
-
- if (le64toh(o->object.size) == osize &&
- memcmp(o->data.payload, data, size) == 0) {
-
- if (le64toh(o->data.hash) != hash)
- return -EBADMSG;
-
- if (o->data.tail_entry_offset == 0)
- return 0;
-
- p = le64toh(o->data.tail_entry_offset);
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EBADMSG;
-
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = p;
-
- return 1;
- }
-
- p = le64toh(o->data.prev_hash_offset);
- }
-
- return 0;
-}
-
-void journal_file_dump(JournalFile *f) {
- char a[33], b[33], c[33];
- Object *o;
- int r;
- uint64_t p;
-
- assert(f);
-
- printf("File ID: %s\n"
- "Machine ID: %s\n"
- "Boot ID: %s\n"
- "Arena size: %llu\n",
- sd_id128_to_string(f->header->file_id, a),
- sd_id128_to_string(f->header->machine_id, b),
- sd_id128_to_string(f->header->boot_id, c),
- (unsigned long long) le64toh(f->header->arena_size));
-
- p = le64toh(f->header->head_object_offset);
- while (p != 0) {
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- goto fail;
-
- switch (o->object.type) {
-
- case OBJECT_UNUSED:
- printf("Type: OBJECT_UNUSED\n");
- break;
-
- case OBJECT_DATA:
- printf("Type: OBJECT_DATA\n");
- break;
-
- case OBJECT_ENTRY:
- printf("Type: OBJECT_ENTRY %llu\n", (unsigned long long) le64toh(o->entry.seqnum));
- break;
-
- case OBJECT_HASH_TABLE:
- printf("Type: OBJECT_HASH_TABLE\n");
- break;
-
- case OBJECT_BISECT_TABLE:
- printf("Type: OBJECT_BISECT_TABLE\n");
- break;
- }
-
- if (p == le64toh(f->header->tail_object_offset))
- p = 0;
- else
- p = p + ALIGN64(le64toh(o->object.size));
- }
-
- return;
-fail:
- log_error("File corrupt");
-}
-
-int journal_file_open(
- const char *fname,
- int flags,
- mode_t mode,
- JournalFile **ret) {
-
- JournalFile *f;
- int r;
- bool newly_created = false;
-
- assert(fname);
-
- if ((flags & O_ACCMODE) != O_RDONLY &&
- (flags & O_ACCMODE) != O_RDWR)
- return -EINVAL;
-
- f = new0(JournalFile, 1);
- if (!f)
- return -ENOMEM;
-
- f->writable = (flags & O_ACCMODE) != O_RDONLY;
- f->prot = prot_from_flags(flags);
-
- f->fd = open(fname, flags|O_CLOEXEC, mode);
- if (f->fd < 0) {
- r = -errno;
- goto fail;
- }
-
- f->path = strdup(fname);
- if (!f->path) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (fstat(f->fd, &f->last_stat) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (f->last_stat.st_size == 0 && f->writable) {
- newly_created = true;
-
- r = journal_file_init_header(f);
- if (r < 0)
- goto fail;
-
- if (fstat(f->fd, &f->last_stat) < 0) {
- r = -errno;
- goto fail;
- }
- }
-
- if (f->last_stat.st_size < (off_t) sizeof(Header)) {
- r = -EIO;
- goto fail;
- }
-
- f->header = mmap(NULL, PAGE_ALIGN(sizeof(Header)), prot_from_flags(flags), MAP_SHARED, f->fd, 0);
- if (f->header == MAP_FAILED) {
- f->header = NULL;
- r = -errno;
- goto fail;
- }
-
- if (!newly_created) {
- r = journal_file_verify_header(f);
- if (r < 0)
- goto fail;
- }
-
- if (f->writable) {
- r = journal_file_refresh_header(f);
- if (r < 0)
- goto fail;
- }
-
- if (newly_created) {
-
- r = journal_file_setup_hash_table(f);
- if (r < 0)
- goto fail;
-
- r = journal_file_setup_bisect_table(f);
- if (r < 0)
- goto fail;
- }
-
- r = journal_file_map_hash_table(f);
- if (r < 0)
- goto fail;
-
- r = journal_file_map_bisect_table(f);
- if (r < 0)
- goto fail;
-
- if (ret)
- *ret = f;
-
- return 0;
-
-fail:
- journal_file_close(f);
-
- return r;
-}
-
-int sd_journal_open(sd_journal **ret) {
- sd_journal *j;
- char *fn;
- const char *p;
- int r = 0;
- const char search_paths[] =
- "/run/log/journal\0"
- "/var/log/journal\0";
-
- assert(ret);
-
- j = new0(sd_journal, 1);
- if (!j)
- return -ENOMEM;
-
- j->files = hashmap_new(string_hash_func, string_compare_func);
- if (!j->files)
- goto fail;
-
- NULSTR_FOREACH(p, search_paths) {
- DIR *d;
-
- d = opendir(p);
- if (!d) {
- if (errno != ENOENT && r == 0)
- r = -errno;
-
- continue;
- }
-
- for (;;) {
- struct dirent buf, *de;
- int k;
- JournalFile *f;
-
- k = readdir_r(d, &buf, &de);
- if (k != 0) {
- if (r == 0)
- r = -k;
-
- break;
- }
-
- if (!de)
- break;
-
- if (!dirent_is_file_with_suffix(de, ".journal"))
- continue;
-
- fn = join(p, "/", de->d_name, NULL);
- if (!fn) {
- r = -ENOMEM;
- closedir(d);
- goto fail;
- }
-
- k = journal_file_open(fn, O_RDONLY, 0, &f);
- free(fn);
-
- if (k < 0) {
-
- if (r == 0)
- r = -k;
- } else {
- k = hashmap_put(j->files, f->path, f);
- if (k < 0) {
- journal_file_close(f);
- closedir(d);
-
- r = k;
- goto fail;
- }
- }
- }
- }
-
- *ret = j;
- return 0;
-
-fail:
- sd_journal_close(j);
-
- return r;
-};
-
-void sd_journal_close(sd_journal *j) {
- assert(j);
-
- if (j->files) {
- JournalFile *f;
-
- while ((f = hashmap_steal_first(j->files)))
- journal_file_close(f);
-
- hashmap_free(j->files);
- }
-
- free(j);
-}