80 #if defined(_DB_185_H_) && defined(USE_FCNTL_LOCK)
81 #error "Error: this system must not use the db 1.85 compatibility interface"
84 #ifndef DB_VERSION_MAJOR
85 #define DB_VERSION_MAJOR 1
86 #define DICT_DB_GET(db, key, val, flag) db->get(db, key, val, flag)
87 #define DICT_DB_PUT(db, key, val, flag) db->put(db, key, val, flag)
88 #define DICT_DB_DEL(db, key, flag) db->del(db, key, flag)
89 #define DICT_DB_SYNC(db, flag) db->sync(db, flag)
90 #define DICT_DB_CLOSE(db) db->close(db)
91 #define DONT_CLOBBER R_NOOVERWRITE
94 #if DB_VERSION_MAJOR > 1
95 #define DICT_DB_GET(db, key, val, flag) sanitize(db->get(db, 0, key, val, flag))
96 #define DICT_DB_PUT(db, key, val, flag) sanitize(db->put(db, 0, key, val, flag))
97 #define DICT_DB_DEL(db, key, flag) sanitize(db->del(db, 0, key, flag))
98 #define DICT_DB_SYNC(db, flag) ((errno = db->sync(db, flag)) ? -1 : 0)
99 #define DICT_DB_CLOSE(db) ((errno = db->close(db, 0)) ? -1 : 0)
100 #define DONT_CLOBBER DB_NOOVERWRITE
103 #if (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6)
104 #define DICT_DB_CURSOR(db, curs) (db)->cursor((db), NULL, (curs))
106 #define DICT_DB_CURSOR(db, curs) (db)->cursor((db), NULL, (curs), 0)
109 #ifndef DB_FCNTL_LOCKING
110 #define DB_FCNTL_LOCKING 0
130 #if DB_VERSION_MAJOR > 2
133 #if DB_VERSION_MAJOR > 1
140 #define SCOPY(buf, data, size) \
141 vstring_str(vstring_strncpy(buf ? buf : (buf = vstring_alloc(10)), data, size))
143 #define DICT_DB_NELM 4096
145 #if DB_VERSION_MAJOR > 1
149 static int sanitize(
int status)
179 static const char *dict_db_lookup(
DICT *dict,
const char *name)
181 DICT_DB *dict_db = (DICT_DB *) dict;
182 DB *db = dict_db->db;
186 const char *result = 0;
194 msg_panic(
"dict_db_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
196 memset(&db_key, 0,
sizeof(db_key));
197 memset(&db_value, 0,
sizeof(db_value));
214 msg_fatal(
"%s: lock dictionary: %m", dict_db->dict.name);
221 db_key.data = (
void *) name;
222 db_key.size = strlen(name) + 1;
223 if ((status = DICT_DB_GET(db, &db_key, &db_value, 0)) < 0)
224 msg_fatal(
"error reading %s: %m", dict_db->dict.name);
227 result = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
236 db_key.data = (
void *) name;
237 db_key.size = strlen(name);
238 if ((status = DICT_DB_GET(db, &db_key, &db_value, 0)) < 0)
239 msg_fatal(
"error reading %s: %m", dict_db->dict.name);
242 result = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
251 msg_fatal(
"%s: unlock dictionary: %m", dict_db->dict.name);
258 static int dict_db_update(
DICT *dict,
const char *name,
const char *value)
260 DICT_DB *dict_db = (DICT_DB *) dict;
261 DB *db = dict_db->db;
272 msg_panic(
"dict_db_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
283 memset(&db_key, 0,
sizeof(db_key));
284 memset(&db_value, 0,
sizeof(db_value));
285 db_key.data = (
void *) name;
286 db_value.data = (
void *) value;
287 db_key.size = strlen(name);
288 db_value.size = strlen(value);
296 #ifdef DB_NO_TRAILING_NULL
316 msg_fatal(
"%s: lock dictionary: %m", dict_db->dict.name);
321 if ((status = DICT_DB_PUT(db, &db_key, &db_value,
323 msg_fatal(
"error writing %s: %m", dict_db->dict.name);
328 msg_warn(
"%s: duplicate entry: \"%s\"", dict_db->dict.name, name);
330 msg_fatal(
"%s: duplicate entry: \"%s\"", dict_db->dict.name, name);
333 if (DICT_DB_SYNC(db, 0) < 0)
334 msg_fatal(
"%s: flush dictionary: %m", dict_db->dict.name);
341 msg_fatal(
"%s: unlock dictionary: %m", dict_db->dict.name);
348 static int dict_db_delete(
DICT *dict,
const char *name)
350 DICT_DB *dict_db = (DICT_DB *) dict;
351 DB *db = dict_db->db;
362 msg_panic(
"dict_db_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
373 memset(&db_key, 0,
sizeof(db_key));
380 msg_fatal(
"%s: lock dictionary: %m", dict_db->dict.name);
387 db_key.data = (
void *) name;
388 db_key.size = strlen(name) + 1;
389 if ((status = DICT_DB_DEL(db, &db_key, flags)) < 0)
390 msg_fatal(
"error deleting from %s: %m", dict_db->dict.name);
400 db_key.data = (
void *) name;
401 db_key.size = strlen(name);
402 if ((status = DICT_DB_DEL(db, &db_key, flags)) < 0)
403 msg_fatal(
"error deleting from %s: %m", dict_db->dict.name);
408 if (DICT_DB_SYNC(db, 0) < 0)
409 msg_fatal(
"%s: flush dictionary: %m", dict_db->dict.name);
416 msg_fatal(
"%s: unlock dictionary: %m", dict_db->dict.name);
423 static int dict_db_sequence(
DICT *dict,
int function,
424 const char **key,
const char **value)
426 const char *myname =
"dict_db_sequence";
427 DICT_DB *dict_db = (DICT_DB *) dict;
428 DB *db = dict_db->db;
436 #if DB_VERSION_MAJOR > 1
441 memset(&db_key, 0,
sizeof(db_key));
442 memset(&db_value, 0,
sizeof(db_value));
449 if (dict_db->cursor == 0)
450 DICT_DB_CURSOR(db, &(dict_db->cursor));
451 db_function = DB_FIRST;
454 if (dict_db->cursor == 0)
456 db_function = DB_NEXT;
459 msg_panic(
"%s: invalid function %d", myname,
function);
467 msg_fatal(
"%s: lock dictionary: %m", dict_db->dict.name);
473 dict_db->cursor->c_get(dict_db->cursor, &db_key, &db_value, db_function);
474 if (status != 0 && status != DB_NOTFOUND)
475 msg_fatal(
"error [%d] seeking %s: %m", status, dict_db->dict.name);
482 msg_fatal(
"%s: unlock dictionary: %m", dict_db->dict.name);
489 *key = SCOPY(dict_db->key_buf, db_key.data, db_key.size);
490 *value = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
500 db_function = R_FIRST;
503 db_function = R_NEXT;
506 msg_panic(
"%s: invalid function %d", myname,
function);
514 msg_fatal(
"%s: lock dictionary: %m", dict_db->dict.name);
516 if ((status = db->seq(db, &db_key, &db_value, db_function)) < 0)
517 msg_fatal(
"error seeking %s: %m", dict_db->dict.name);
524 msg_fatal(
"%s: unlock dictionary: %m", dict_db->dict.name);
531 *key = SCOPY(dict_db->key_buf, db_key.data, db_key.size);
532 *value = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
540 static void dict_db_close(
DICT *dict)
542 DICT_DB *dict_db = (DICT_DB *) dict;
544 #if DB_VERSION_MAJOR > 1
546 dict_db->cursor->c_close(dict_db->cursor);
548 if (DICT_DB_SYNC(dict_db->db, 0) < 0)
549 msg_fatal(
"flush database %s: %m", dict_db->dict.name);
561 if (DICT_DB_CLOSE(dict_db->db) < 0)
562 msg_info(
"close database %s: %m (possible Berkeley DB bug)",
564 #if DB_VERSION_MAJOR > 2
565 dict_db->dbenv->close(dict_db->dbenv, 0);
567 if (dict_db->key_buf)
569 if (dict_db->val_buf)
576 #if DB_VERSION_MAJOR > 2
580 static DB_ENV *dict_db_new_env(
const char *db_path)
584 u_int32_t cache_size_gbytes;
585 u_int32_t cache_size_bytes;
588 if ((errno = db_env_create(&dbenv, 0)) != 0)
590 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 7)
591 if ((errno = dbenv->get_cachesize(dbenv, &cache_size_gbytes,
592 &cache_size_bytes, &ncache)) != 0)
595 if ((errno = dbenv->set_cache_max(dbenv, cache_size_gbytes,
598 if ((errno = dbenv->set_cachesize(dbenv, cache_size_gbytes,
605 if ((errno = dbenv->open(dbenv,
sane_dirname(db_home_buf, db_path),
606 DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0)) != 0)
616 static DICT *dict_db_open(
const char *
class,
const char *path,
int open_flags,
617 int type,
void *tweak,
int dict_flags)
627 #if DB_VERSION_MAJOR > 1
631 #if DB_VERSION_MAJOR > 2
640 #if DB_VERSION_MAJOR > 1
645 (void) db_version(&major_version, &minor_version, &patch_version);
646 if (major_version != DB_VERSION_MAJOR || minor_version != DB_VERSION_MINOR)
648 "incorrect version of Berkeley DB: "
649 "compiled against %d.%d.%d, run-time linked against %d.%d.%d",
650 DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
651 major_version, minor_version, patch_version));
653 msg_info(
"Compiled against Berkeley DB: %d.%d.%d\n",
654 DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH);
655 msg_info(
"Run-time linked against Berkeley DB: %d.%d.%d\n",
656 major_version, minor_version, patch_version);
660 msg_info(
"Compiled against Berkeley DB version 1");
676 #define LOCK_OPEN_FLAGS(f) ((f) & ~(O_CREAT|O_TRUNC))
677 #define FREE_RETURN(e) do { \
678 DICT *_dict = (e); if (db) DICT_DB_CLOSE(db); \
679 if (lock_fd >= 0) (void) close(lock_fd); \
680 if (db_base_buf) vstring_free(db_base_buf); \
681 if (db_path) myfree(db_path); return (_dict); \
685 if ((lock_fd = open(db_path, LOCK_OPEN_FLAGS(open_flags), 0644)) < 0) {
688 "open database %s: %m", db_path));
691 msg_fatal(
"shared-lock database %s for open: %m", db_path);
701 #if DB_VERSION_MAJOR < 2
702 if ((db = dbopen(db_path, open_flags, 0644, type, tweak)) == 0)
704 "open database %s: %m", db_path));
711 #if DB_VERSION_MAJOR == 2
712 db_flags = DB_FCNTL_LOCKING;
713 if (open_flags == O_RDONLY)
714 db_flags |= DB_RDONLY;
715 if (open_flags & O_CREAT)
716 db_flags |= DB_CREATE;
717 if (open_flags & O_TRUNC)
718 db_flags |= DB_TRUNCATE;
719 if ((errno = db_open(db_path, type, db_flags, 0644, 0, tweak, &db)) != 0)
721 "open database %s: %m", db_path));
724 if ((errno = db->fd(db, &dbfd)) != 0)
725 msg_fatal(
"get database file descriptor: %m");
731 #if DB_VERSION_MAJOR > 2
732 db_flags = DB_FCNTL_LOCKING;
733 if (open_flags == O_RDONLY)
734 db_flags |= DB_RDONLY;
735 if (open_flags & O_CREAT)
736 db_flags |= DB_CREATE;
737 if (open_flags & O_TRUNC)
738 db_flags |= DB_TRUNCATE;
739 if ((errno = db_create(&db, dbenv = dict_db_new_env(db_path), 0)) != 0)
743 if (type == DB_HASH && db->set_h_nelem(db, DICT_DB_NELM) != 0)
744 msg_fatal(
"set DB hash element count %d: %m", DICT_DB_NELM);
746 #if DB_VERSION_MAJOR == 6 || DB_VERSION_MAJOR == 5 || \
747 (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0)
748 if ((errno = db->open(db, 0,
sane_basename(db_base_buf, db_path),
749 0, type, db_flags, 0644)) != 0)
751 "open database %s: %m", db_path));
752 #elif (DB_VERSION_MAJOR == 3 || DB_VERSION_MAJOR == 4)
753 if ((errno = db->open(db,
sane_basename(db_base_buf, db_path), 0,
754 type, db_flags, 0644)) != 0)
756 "open database %s: %m", db_path));
758 #error "Unsupported Berkeley DB version"
761 if ((errno = db->fd(db, &dbfd)) != 0)
762 msg_fatal(
"get database file descriptor: %m");
764 if ((dict_flags & DICT_FLAG_LOCK) && lock_fd >= 0) {
766 msg_fatal(
"unlock database %s for open: %m", db_path);
767 if (close(lock_fd) < 0)
768 msg_fatal(
"close database %s: %m", db_path);
771 dict_db = (DICT_DB *)
dict_alloc(
class, db_path,
sizeof(*dict_db));
772 dict_db->dict.
lookup = dict_db_lookup;
773 dict_db->dict.update = dict_db_update;
774 dict_db->dict.delete = dict_db_delete;
775 dict_db->dict.sequence = dict_db_sequence;
776 dict_db->dict.close = dict_db_close;
777 dict_db->dict.lock_fd = dbfd;
778 dict_db->dict.stat_fd = dbfd;
779 if (
fstat(dict_db->dict.stat_fd, &st) < 0)
781 dict_db->dict.mtime = st.st_mtime;
782 dict_db->dict.owner.uid = st.st_uid;
783 dict_db->dict.owner.status = (st.st_uid != 0);
789 if ((dict_flags & DICT_FLAG_LOCK) != 0
790 &&
stat(path, &st) == 0
791 && st.st_mtime > dict_db->dict.mtime
792 && st.st_mtime < time((time_t *) 0) - 100)
793 msg_warn(
"database %s is older than source file %s", db_path, path);
803 #if DB_VERSION_MAJOR > 2
804 dict_db->dbenv = dbenv;
806 #if DB_VERSION_MAJOR > 1
809 dict_db->key_buf = 0;
810 dict_db->val_buf = 0;
820 #if DB_VERSION_MAJOR < 2
823 memset((
void *) &tweak, 0,
sizeof(tweak));
824 tweak.nelem = DICT_DB_NELM;
827 #if DB_VERSION_MAJOR == 2
830 memset((
void *) &tweak, 0,
sizeof(tweak));
831 tweak.h_nelem = DICT_DB_NELM;
834 #if DB_VERSION_MAJOR > 2
840 (
void *) &tweak, dict_flags));
847 #if DB_VERSION_MAJOR < 2
850 memset((
void *) &tweak, 0,
sizeof(tweak));
853 #if DB_VERSION_MAJOR == 2
856 memset((
void *) &tweak, 0,
sizeof(tweak));
859 #if DB_VERSION_MAJOR > 2
866 (
void *) &tweak, dict_flags));
#define DICT_FLAG_DUP_IGNORE
#define MYFLOCK_OP_SHARED
#define DICT_SEQ_FUN_FIRST
NORETURN msg_panic(const char *fmt,...)
#define DICT_SEQ_FUN_NEXT
#define MYFLOCK_OP_EXCLUSIVE
#define DICT_FLAG_FOLD_FIX
char * sane_dirname(VSTRING *bp, const char *path)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
#define DICT_FLAG_DUP_REPLACE
#define DICT_FLAG_TRY1NULL
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
int myflock(int fd, int lock_style, int operation)
char * lowercase(char *string)
const char *(* lookup)(struct DICT *, const char *)
#define DICT_FLAG_DUP_WARN
NORETURN msg_fatal(const char *fmt,...)
char * concatenate(const char *arg0,...)
DICT * dict_btree_open(const char *, int, int)
char * sane_basename(VSTRING *bp, const char *path)
VSTRING * vstring_free(VSTRING *vp)
#define DICT_FLAG_SYNC_UPDATE
DICT * dict_alloc(const char *, const char *, ssize_t)
#define DICT_FLAG_TRY0NULL
int close_on_exec(int fd, int on)
DICT * dict_hash_open(const char *, int, int)
DICT * dict_surrogate(const char *dict_type, const char *dict_name, int open_flags, int dict_flags, const char *fmt,...)
void msg_info(const char *fmt,...)