* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
For convenience, the definitions of the structures used in the various hints
databases are also kept in this file, which is used by the maintenance
-utilities as well as the main Exim binary. */
+utilities as well as the main Exim binary.
+
+A key/value store is supported (only). Keys are strings; values arbitrary
+binary blobs.
+
+The API is:
+ Functions:
+ exim_lockfile_needed API semantics predicate
+ exim_dbopen
+ exim_dbclose
+ exim_dbget
+ exim_dbput
+ exim_dbputb non-overwriting put
+ exim_dbdel
+ exim_dbcreate_cursor
+ exim_dbscan get, and bump cursor
+ exim_dbdelete_cursor
+ exim_datum_init
+ exim_datum_size_get/set
+ exim_datum_data_get/set
+ exim_datum_free
+ Defines:
+ EXIM_DB access handle
+ EXIM_CURSOR datatype for cursor
+ EXIM_DATUM datatype for "value"
+ EXIM_DBTYPE text for logging & debuug
+
+Selection of the shim layer implementation, and backend, is by #defines.
+
+The users of this API are:
+ hintsdb interface dbfn.c
+ hintsdb utilities exim_dbutil.c and exim_dbmvuild.c
+ dbmdb lookup lookups/dbmdb,c
+ autoreply transport transports/autoreply.c
+
+Note that the dbmdb lookup use, bypassing the dbfn.c layer,
+means that no file-locking is done.
+XXX This feels like a layering violation; I don't see it commented on
+anywhere.
+
+Future: consider re-architecting to support caching of the open-handle
+for hintsdb uses (the dbmdb use gets that already). This would need APIs
+for transaction locks. Perhaps merge the implementation with the lookups
+layer, in some way, for the open-handle caching (since that manages closes
+required by Exim's process transitions)?
+*/
#ifndef HINTSDB_H
#define HINTSDB_H
-#if defined(USE_TDB)
+#ifdef USE_SQLITE
+# if defined(USE_DB) || defined(USE_GDBM) || defined(USE_TDB)
+# error USE_SQLITE conflict with alternate definition
+# endif
+# include "hintsdb/hints_sqlite.h"
-# if defined(USE_DB) || defined(USE_GDBM)
+#elif defined(USE_TDB)
+# if defined(USE_DB) || defined(USE_GDBM) || defined(USE_SQLITE)
# error USE_TDB conflict with alternate definition
# endif
-
-/* ************************* tdb interface ************************ */
-/*XXX https://manpages.org/tdb/3 mentions concurrent writes.
-Could we lose the file lock? */
-
-# include <tdb.h>
-
-/* Basic DB type */
-# define EXIM_DB TDB_CONTEXT
-
-/* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
-tdb_traverse to be called) */
-# define EXIM_CURSOR TDB_DATA
-
-/* The datum type used for queries */
-# define EXIM_DATUM TDB_DATA
-
-/* Some text for messages */
-# define EXIM_DBTYPE "tdb"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
-static inline EXIM_DB *
-exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
- unsigned mode)
-{
-return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
-}
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-static inline BOOL
-exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
-{
-*res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
-return res->dptr != NULL;
-}
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-static inline int
-exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return tdb_store(dbp, *key, *data, TDB_REPLACE); }
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-static inline int
-exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return tdb_store(dbp, *key, *data, TDB_INSERT); }
-
-/* Returns from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP (-1)
-
-/* EXIM_DBDEL */
-static inline int
-exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
-{ return tdb_delete(dbp, *key); }
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-static inline EXIM_CURSOR *
-exim_dbcreate_cursor(EXIM_DB * dbp)
-{
-EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
-c->dptr = NULL;
-return c;
-}
-
-/* EXIM_DBSCAN - This is complicated because we have to free the last datum
-free() must not die when passed NULL */
-
-static inline BOOL
-exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
- EXIM_CURSOR * cursor)
-{
-*key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
-free(cursor->dptr);
-*cursor = *key;
-return key->dptr != NULL;
-}
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
-static inline void
-exim_dbdelete_cursor(EXIM_CURSOR * cursor)
-{ store_free(cursor); }
-
-/* EXIM_DBCLOSE */
-static inline void
-exim_dbclose__(EXIM_DB * db)
-{ tdb_close(db); }
-
-/* Datum access */
-
-static inline uschar *
-exim_datum_data_get(EXIM_DATUM * dp)
-{ return US dp->dptr; }
-static inline void
-exim_datum_data_set(EXIM_DATUM * dp, void * s)
-{ dp->dptr = s; }
-
-static inline unsigned
-exim_datum_size_get(EXIM_DATUM * dp)
-{ return dp->dsize; }
-static inline void
-exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
-{ dp->dsize = n; }
-
-/* No initialization is needed. */
-
-static inline void
-exim_datum_init(EXIM_DATUM * d)
-{ }
-
-/* Free the stuff inside the datum. */
-
-static inline void
-exim_datum_free(EXIM_DATUM * d)
-{
-free(d->dptr);
-d->dptr = NULL;
-}
-
-/* size limit */
-
-# define EXIM_DB_RLIMIT 150
-
-
-
-
-
-
-/********************* Berkeley db native definitions **********************/
+# include "hintsdb/hints_tdb.h"
#elif defined USE_DB
-
-# if defined(USE_TDB) || defined(USE_GDBM)
+# if defined(USE_TDB) || defined(USE_GDBM) || defined(USE_SQLITE)
# error USE_DB conflict with alternate definition
# endif
-
-# include <db.h>
-
-/* 1.x did no locking
- 2.x had facilities, but exim does it's own
- 3.x+ unknown
-*/
-
-/* We can distinguish between versions 1.x and 2.x/3.x by looking for a
-definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
-
-# ifdef DB_VERSION_STRING
-
-# if DB_VERSION_MAJOR >= 6
-# error Version 6 and later BDB API is not supported
-# endif
-
-/* The API changed (again!) between the 2.x and 3.x versions */
-
-# if DB_VERSION_MAJOR >= 3
-
-/***************** Berkeley db 3.x/4.x native definitions ******************/
-
-/* Basic DB type */
-# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
-# define EXIM_DB DB_ENV
-/* Cursor type, for scanning */
-# define EXIM_CURSOR DBC
-
-/* The datum type used for queries */
-# define EXIM_DATUM DBT
-
-/* Some text for messages */
-# define EXIM_DBTYPE "db (v4.1+)"
-
-/* Only more-recent versions. 5+ ? */
-# ifndef DB_FORCESYNC
-# define DB_FORCESYNC 0
-# endif
-
-/* Error callback */
-/* For Berkeley DB >= 2, we can define a function to be called in case of DB
-errors. This should help with debugging strange DB problems, e.g. getting "File
-exists" when you try to open a db file. The API for this function was changed
-at DB release 4.3. */
-
-static inline void
-dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
-{
-#ifndef MACRO_PREDEF
-log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
-#endif
-}
-
-
-
-/* Access functions */
-
-/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
-/* The API changed for DB 4.1. - and we also starting using the "env" with a
-specified working dir, to avoid the DBCONFIG file trap. */
-
-# define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
-
-static inline EXIM_DB *
-exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
- unsigned mode)
-{
-EXIM_DB * dbp;
-DB * b;
-if ( db_env_create(&dbp, 0) != 0
- || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
- || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
- )
- return NULL;
-if (db_create(&b, dbp, 0) == 0)
- {
- dbp->app_private = b;
- if (b->open(b, NULL, CS name, NULL,
- flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
- flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
- mode) == 0
- )
- return dbp;
-
- b->close(b, 0);
- }
-dbp->close(dbp, 0);
-return NULL;
-}
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-static inline BOOL
-exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
-{
-DB * b = ENV_TO_DB(dbp);
-return b->get(b, NULL, key, res, 0) == 0;
-}
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-static inline int
-exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{
-DB * b = ENV_TO_DB(dbp);
-return b->put(b, NULL, key, data, 0);
-}
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-static inline int
-exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{
-DB * b = ENV_TO_DB(dbp);
-return b->put(b, NULL, key, data, DB_NOOVERWRITE);
-}
-
-/* Return values from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP DB_KEYEXIST
-
-/* EXIM_DBDEL */
-static inline int
-exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
-{
-DB * b = ENV_TO_DB(dbp);
-return b->del(b, NULL, key, 0);
-}
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-
-static inline EXIM_CURSOR *
-exim_dbcreate_cursor(EXIM_DB * dbp)
-{
-DB * b = ENV_TO_DB(dbp);
-EXIM_CURSOR * c;
-b->cursor(b, NULL, &c, 0);
-return c;
-}
-
-/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-static inline BOOL
-exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
- EXIM_CURSOR * cursor)
-{
-return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
-}
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
-static inline void
-exim_dbdelete_cursor(EXIM_CURSOR * cursor)
-{ cursor->c_close(cursor); }
-
-/* EXIM_DBCLOSE */
-static inline void
-exim_dbclose__(EXIM_DB * dbp_o)
-{
-DB_ENV * dbp = dbp_o;
-DB * b = ENV_TO_DB(dbp);
-b->close(b, 0);
-dbp->close(dbp, DB_FORCESYNC);
-}
-
-/* Datum access */
-
-static inline uschar *
-exim_datum_data_get(EXIM_DATUM * dp)
-{ return dp->data; }
-static inline void
-exim_datum_data_set(EXIM_DATUM * dp, void * s)
-{ dp->data = s; }
-
-static inline unsigned
-exim_datum_size_get(EXIM_DATUM * dp)
-{ return dp->size; }
-static inline void
-exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
-{ dp->size = n; }
-
-/* The whole datum structure contains other fields that must be cleared
-before use, but we don't have to free anything after reading data. */
-
-static inline void
-exim_datum_init(EXIM_DATUM * d)
-{ memset(d, 0, sizeof(*d)); }
-
-static inline void
-exim_datum_free(EXIM_DATUM * d)
-{ }
-
-# else /* pre- 4.1 */
-
-# define EXIM_DB DB
-
-/* Cursor type, for scanning */
-# define EXIM_CURSOR DBC
-
-/* The datum type used for queries */
-# define EXIM_DATUM DBT
-
-/* Some text for messages */
-# define EXIM_DBTYPE "db (v3/4)"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
-static inline EXIM_DB *
-exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
- unsigned mode)
-{
-EXIM_DB * dbp;
-return db_create(&dbp, NULL, 0) == 0
- && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
- dbp->open(dbp, CS name, NULL,
- flags == O_RDONLY ? DB_UNKNOWN : DB_HASH,
- flags == O_RDONLY ? DB_RDONLY : DB_CREATE,
- mode)
- ) == 0
- ? dbp : NULL;
-}
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-static inline BOOL
-exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
-{ return dbp->get(dbp, NULL, key, res, 0) == 0; }
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-static inline int
-exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return dbp->put(dbp, NULL, key, data, 0); }
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-static inline int
-exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
-
-/* Return values from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP DB_KEYEXIST
-
-/* EXIM_DBDEL */
-static inline int
-exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
-{ return dbp->del(dbp, NULL, key, 0); }
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
-
-static inline EXIM_CURSOR *
-exim_dbcreate_cursor(EXIM_DB * dbp)
-{
-EXIM_CURSOR * c;
-dbp->cursor(dbp, NULL, &c, 0);
-return c;
-}
-
-/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-static inline BOOL
-exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
- EXIM_CURSOR * cursor)
-{
-return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
-}
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
-static inline void
-exim_dbdelete_cursor(EXIM_CURSOR * cursor)
-{ cursor->c_close(cursor); }
-
-/* EXIM_DBCLOSE */
-static inline void
-exim_dbclose__(EXIM_DB * dbp)
-{ dbp->close(dbp, 0); }
-
-/* Datum access */
-
-static inline uschar *
-exim_datum_data_get(EXIM_DATUM * dp)
-{ return US dp->dptr; }
-static inline void
-exim_datum_data_set(EXIM_DATUM * dp, void * s)
-{ dp->dptr = s; }
-
-static inline uschar *
-exim_datum_size_get(EXIM_DATUM * dp)
-{ return US dp->size; }
-static inline void
-exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
-{ dp->size = CS s; }
-
-/* The whole datum structure contains other fields that must be cleared
-before use, but we don't have to free anything after reading data. */
-
-static inline void
-exim_datum_init(EXIM_DATUM * d)
-{ memset(d, 0, sizeof(*d)); }
-
-static inline void
-exim_datum_free(EXIM_DATUM * d)
-{ }
-
-# endif
-
-
-# else /* DB_VERSION_MAJOR >= 3 */
-# error Berkeley DB versions earlier than 3 are not supported */
-# endif /* DB_VERSION_MAJOR */
-# else
-# error Berkeley DB version 1 is no longer supported
-# endif /* DB_VERSION_STRING */
-
-
-/* all BDB versions */
-/* size limit */
-
-# define EXIM_DB_RLIMIT 150
-
-
-
-
-
-
-/********************* gdbm interface definitions **********************/
+# include "hintsdb/hints_bdb.h"
#elif defined USE_GDBM
-/*XXX TODO: exim's locfile not needed */
-
-# if defined(USE_TDB) || defined(USE_DB)
+# if defined(USE_TDB) || defined(USE_DB) || defined(USE_SQLITE)
# error USE_GDBM conflict with alternate definition
# endif
+# include "hintsdb/hints_gdbm.h"
-# include <gdbm.h>
-
-/* Basic DB type */
-typedef struct {
- GDBM_FILE gdbm; /* Database */
- datum lkey; /* Last key, for scans */
-} EXIM_DB;
-
-/* Cursor type, not used with gdbm: just set up a dummy */
-# define EXIM_CURSOR int
-
-/* The datum type used for queries */
-# define EXIM_DATUM datum
-
-/* Some text for messages */
+#else
-# define EXIM_DBTYPE "gdbm"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
-static inline EXIM_DB *
-exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
- unsigned mode)
-{
-EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
-if (dbp)
- {
- dbp->lkey.dptr = NULL;
- dbp->gdbm = gdbm_open(CS name, 0,
- flags & O_CREAT ? GDBM_WRCREAT
- : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
- : GDBM_READER,
- mode, 0);
- if (dbp->gdbm) return dbp;
- free(dbp);
- }
-return NULL;
-}
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-static inline BOOL
-exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
-{
-*res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
-return res->dptr != NULL;
-}
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-static inline int
-exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-static inline int
-exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
-
-/* Returns from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP 1
-
-/* EXIM_DBDEL */
-static inline int
-exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
-{ return gdbm_delete(dbp->gdbm, *key); }
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
-static inline EXIM_CURSOR *
-exim_dbcreate_cursor(EXIM_DB * dbp)
-{ return NULL; }
-
-/* EXIM_DBSCAN */
-static inline BOOL
-exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
- EXIM_CURSOR * cursor)
-{
-char * s;
-*key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
-if ((s = dbp->lkey.dptr)) free(s);
-dbp->lkey = *key;
-return key->dptr != NULL;
-}
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
-static inline void
-exim_dbdelete_cursor(EXIM_CURSOR * cursor)
-{ }
-
-/* EXIM_DBCLOSE */
-static inline void
-exim_dbclose__(EXIM_DB * dbp)
-{
-char * s;
-gdbm_close(dbp->gdbm);
-if ((s = dbp->lkey.dptr)) free(s);
-free(dbp);
-}
-
-/* Datum access types */
-
-static inline uschar *
-exim_datum_data_get(EXIM_DATUM * dp)
-{ return US dp->dptr; }
-static inline void
-exim_datum_data_set(EXIM_DATUM * dp, void * s)
-{ dp->dptr = s; }
-
-static inline unsigned
-exim_datum_size_get(EXIM_DATUM * dp)
-{ return dp->dsize; }
-static inline void
-exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
-{ dp->dsize = n; }
-
-/* There's no clearing required before use, but we have to free the dptr
-after reading data. */
-
-static inline void
-exim_datum_init(EXIM_DATUM * d)
-{ }
-
-static inline void
-exim_datum_free(EXIM_DATUM * d)
-{ free(d->dptr); }
-
-/* size limit. GDBM is int-max limited, but we want to be less silly */
-
-# define EXIM_DB_RLIMIT 150
-
-#else /* USE_GDBM */
-
-
-
-
-
-
-/* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
-interface (which seems to be a wrapper for GDBM) */
-
-
-/********************* ndbm interface definitions **********************/
-
-# include <ndbm.h>
-
-/* Basic DB type */
-# define EXIM_DB DBM
-
-/* Cursor type, not used with ndbm: just set up a dummy */
-# define EXIM_CURSOR int
-
-/* The datum type used for queries */
-# define EXIM_DATUM datum
-
-/* Some text for messages */
-
-# define EXIM_DBTYPE "ndbm"
-
-/* Access functions */
-
-/* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-/* Check that the name given is not present. This catches
-a directory name; otherwise we would create the name.pag and
-name.dir files in the directory's parent. */
-
-static inline EXIM_DB *
-exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
- unsigned mode)
-{
-struct stat st;
-if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
- return dbm_open(CS name, flags, mode);
-#ifndef COMPILE_UTILITY
-debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
-#endif
-errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
-return NULL;
-}
-
-/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-static inline BOOL
-exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
-{
-*res = dbm_fetch(dbp, *key); /* A struct arg & return! */
-return res->dptr != NULL;
-}
-
-/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-static inline int
-exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return dbm_store(dbp, *key, *data, DBM_REPLACE); }
-
-/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-static inline int
-exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
-{ return dbm_store(dbp, *key, *data, DBM_INSERT); }
-
-/* Returns from EXIM_DBPUTB */
-
-# define EXIM_DBPUTB_OK 0
-# define EXIM_DBPUTB_DUP 1
-
-/* EXIM_DBDEL */
-static inline int
-exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
-{ return dbm_delete(dbp, *key); }
-
-/* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
-static inline EXIM_CURSOR *
-exim_dbcreate_cursor(EXIM_DB * dbp)
-{ return NULL; }
-
-/* EXIM_DBSCAN */
-static inline BOOL
-exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
- EXIM_CURSOR * cursor)
-{
-*key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
-return key->dptr != NULL;
-}
-
-/* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
-static inline void
-exim_dbdelete_cursor(EXIM_CURSOR * cursor)
-{ }
-
-/* EXIM_DBCLOSE */
-static inline void
-exim_dbclose__(EXIM_DB * dbp)
-{ dbm_close(dbp); }
-
-/* Datum access types */
-
-static inline uschar *
-exim_datum_data_get(EXIM_DATUM * dp)
-{ return US dp->dptr; }
-static inline void
-exim_datum_data_set(EXIM_DATUM * dp, void * s)
-{ dp->dptr = s; }
-
-static inline unsigned
-exim_datum_size_get(EXIM_DATUM * dp)
-{ return dp->dsize; }
-static inline void
-exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
-{ dp->dsize = n; }
-
-/* There's no clearing required before use, and we don't have to free anything
-after reading data. */
-
-static inline void
-exim_datum_init(EXIM_DATUM * d)
-{ }
-
-static inline void
-exim_datum_free(EXIM_DATUM * d)
-{ }
-
-/* size limit */
-
-# define EXIM_DB_RLIMIT 150
+/* If none of USE_{DB,GDBM,SQLITE,TDB} are set
+the default is the NDBM interface (which seems to be a wrapper for GDBM) */
+# include "hintsdb/hints_ndbm.h"
#endif /* !USE_GDBM */
exim_dbclose__(dbp);
}
-# endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
+#endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
/********************* End of dbm library definitions **********************/
-
#endif /* whole file */
/* End of hintsdb.h */
+/* vi: aw ai sw=2
+*/