1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
10 /* This header file contains macro definitions so that a variety of DBM
11 libraries can be used by Exim. Nigel Metheringham provided the original set for
12 Berkeley DB 1.x in native mode and ndbm. Subsequently, versions for Berkeley DB
13 2.x and 3.x were added. Later still, support for tdb was added, courtesy of
14 James Antill. Most recently, support for native mode gdbm was added, with code
15 from Pierre A. Humblet, so Exim could be made to work with Cygwin.
17 For convenience, the definitions of the structures used in the various hints
18 databases are also kept in this file, which is used by the maintenance
19 utilities as well as the main Exim binary.
21 A key/value store is supported (only). Keys are strings; values arbitrary
26 exim_lockfile_needed API semantics predicate
31 exim_dbputb non-overwriting put
34 exim_dbscan get, and bump cursor
37 exim_datum_size_get/set
38 exim_datum_data_get/set
42 EXIM_CURSOR datatype for cursor
43 EXIM_DATUM datatype for "value"
44 EXIM_DBTYPE text for logging & debuug
46 Selection of the shim layer implementation, and backend, is by #defines.
48 The users of this API are:
49 hintsdb interface dbfn.c
50 hintsdb utilities exim_dbutil.c and exim_dbmvuild.c
51 dbmdb lookup lookups/dbmdb,c
52 autoreply transport transports/autoreply.c
54 Note that the dbmdb lookup use, bypassing the dbfn.c layer,
55 means that no file-locking is done.
56 XXX This feels like a layering violation; I don't see it commented on
59 Future: consider re-architecting to support caching of the open-handle
60 for hintsdb uses (the dbmdb use gets that already). This would need APIs
61 for transaction locks. Perhaps merge the implementation with the lookups
62 layer, in some way, for the open-handle caching (since that manages closes
63 required by Exim's process transisitions)?
71 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_TDB)
72 # error USE_SQLITE conflict with alternate definition
75 /* ********************* sqlite3 interface ************************ */
80 # define EXIM_DB sqlite3
82 # define EXIM_CURSOR int
84 # /* The datum type used for queries */
85 # define EXIM_DATUM blob
87 /* Some text for messages */
88 # define EXIM_DBTYPE "sqlite3"
90 # /* Access functions */
93 exim_lockfile_needed(void)
95 return FALSE; /* We do transaction; no extra locking needed */
98 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
99 static inline EXIM_DB *
100 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
104 int ret, sflags = flags & O_RDWR ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
105 if (flags & O_CREAT) sflags |= SQLITE_OPEN_CREATE;
106 if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK)
108 sqlite3_busy_timeout(dbp, 5000);
109 ret = sqlite3_exec(dbp, "BEGIN TRANSACTION;", NULL, NULL, NULL);
110 if (ret == SQLITE_OK && flags & O_CREAT)
111 ret = sqlite3_exec(dbp,
112 "CREATE TABLE IF NOT EXISTS tbl (ky TEXT PRIMARY KEY, dat BLOB);",
114 if (ret != SQLITE_OK)
118 // fprintf(stderr, "sqlite3_open_v2: %s\n", sqlite3_errmsg(dbp));
119 return ret == SQLITE_OK ? dbp : NULL;
122 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
123 /* note we alloc'n'copy - the caller need not do so */
124 /* result has a NUL appended, but the length is as per the DB */
127 exim_dbget__(EXIM_DB * dbp, const uschar * s, EXIM_DATUM * res)
129 sqlite3_stmt * statement;
132 res->len = (size_t) -1;
133 /* fprintf(stderr, "exim_dbget__(%s)\n", s); */
134 if ((ret = sqlite3_prepare_v2(dbp, CCS s, -1, &statement, NULL)) != SQLITE_OK)
136 /* fprintf(stderr, "prepare fail: %s\n", sqlite3_errmsg(dbp)); */
139 if (sqlite3_step(statement) != SQLITE_ROW)
141 /* fprintf(stderr, "step fail: %s\n", sqlite3_errmsg(dbp)); */
142 sqlite3_finalize(statement);
146 res->len = sqlite3_column_bytes(statement, 0);
147 # ifdef COMPILE_UTILITY
148 res->data = malloc(res->len);
150 res->data = store_get(res->len, GET_TAINTED);
152 memcpy(res->data, sqlite3_column_blob(statement, 0), res->len);
153 res->data[res->len] = '\0';
154 /* fprintf(stderr, "res %d bytes: '%.*s'\n", (int)res->len, (int)res->len, res->data); */
155 sqlite3_finalize(statement);
160 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
162 # define FMT "SELECT dat FROM tbl WHERE ky = '%.*s';"
167 # ifdef COMPILE_UTILITY
168 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
169 qry = malloc(i = snprintf(NULL, 0, FMT, (int) key->len, key->data));
170 snprintf(CS qry, i, FMT, (int) key->len, key->data);
171 ret = exim_dbget__(dbp, qry, res);
174 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
175 qry = string_sprintf(FMT, (int) key->len, key->data);
176 ret = exim_dbget__(dbp, qry, res);
184 # define EXIM_DBPUTB_OK 0
185 # define EXIM_DBPUTB_DUP (-1)
188 exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const uschar * alt)
190 int hlen = data->len * 2, off = 0, res;
191 # define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%.*s', X'%.*s');"
192 # ifdef COMPILE_UTILITY
193 uschar * hex = malloc(hlen+1);
195 uschar * hex = store_get(hlen+1, data->data);
199 for (const uschar * s = data->data, * t = s + data->len; s < t; s++, off += 2)
200 sprintf(CS hex + off, "%02X", *s);
202 # ifdef COMPILE_UTILITY
203 res = snprintf(CS hex, 0, FMT, alt, (int) key->len, key->data, hlen, hex);
205 snprintf(CS qry, res, FMT, alt, (int) key->len, key->data, hlen, hex);
206 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
207 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
211 qry = string_sprintf(FMT, alt, (int) key->len, key->data, hlen, hex);
212 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
213 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
214 /* fprintf(stderr, "exim_s_dbp res %d\n", res); */
217 if (res != SQLITE_OK)
218 fprintf(stderr, "sqlite3_exec: %s\n", sqlite3_errmsg(dbp));
220 return res == SQLITE_OK ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP;
224 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
227 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
229 /* fprintf(stderr, "exim_dbput()\n"); */
230 (void) exim_s_dbp(dbp, key, data, US"REPLACE");
234 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
236 /* Returns from EXIM_DBPUTB */
239 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
241 return exim_s_dbp(dbp, key, data, US"ABORT");
246 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
248 # define FMT "DELETE FROM tbl WHERE ky = '%.*s';"
252 # ifdef COMPILE_UTILITY
253 res = snprintf(NULL, 0, FMT, (int) key->len, key->data); /* res excludes nul */
255 snprintf(CS qry, res, FMT, (int) key->len, key->data);
256 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
259 qry = string_sprintf(FMT, (int) key->len, key->data);
260 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
268 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
269 /* Cursors are inefficiently emulated by repeating searches */
271 static inline EXIM_CURSOR *
272 exim_dbcreate_cursor(EXIM_DB * dbp)
274 # ifdef COMPILE_UTILITY
275 EXIM_CURSOR * c = malloc(sizeof(int));
277 EXIM_CURSOR * c = store_malloc(sizeof(int));
284 /* Note that we return the (next) key, not the record value */
286 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
287 EXIM_CURSOR * cursor)
289 # define FMT "SELECT ky FROM tbl ORDER BY ky LIMIT 1 OFFSET %d;"
294 # ifdef COMPILE_UTILITY
295 qry = malloc((i = snprintf(NULL, 0, FMT, *cursor)));
296 snprintf(CS qry, i-1, FMT, *cursor);
297 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
298 ret = exim_dbget__(dbp, qry, key);
300 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
302 qry = string_sprintf(FMT, *cursor);
303 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
304 ret = exim_dbget__(dbp, qry, key);
305 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
307 if (ret) *cursor = *cursor + 1;
312 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
314 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
316 # ifdef COMPILE_UTILITY
326 exim_dbclose__(EXIM_DB * dbp)
328 (void) sqlite3_exec(dbp, "COMMIT TRANSACTION;", NULL, NULL, NULL);
336 exim_datum_data_get(EXIM_DATUM * dp)
337 { return US dp->data; }
339 exim_datum_data_set(EXIM_DATUM * dp, void * s)
343 exim_datum_size_get(EXIM_DATUM * dp)
346 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
352 exim_datum_init(EXIM_DATUM * dp)
353 { dp->data = NULL; } /* compiler quietening */
355 /* No free needed for a datum */
358 exim_datum_free(EXIM_DATUM * dp)
363 # define EXIM_DB_RLIMIT 150
370 #elif defined(USE_TDB)
372 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_SQLITE)
373 # error USE_TDB conflict with alternate definition
376 /* ************************* tdb interface ************************ */
377 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
378 Could we lose the file lock? */
383 # define EXIM_DB TDB_CONTEXT
385 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
386 tdb_traverse to be called) */
387 # define EXIM_CURSOR TDB_DATA
389 /* The datum type used for queries */
390 # define EXIM_DATUM TDB_DATA
392 /* Some text for messages */
393 # define EXIM_DBTYPE "tdb"
395 /* Access functions */
398 exim_lockfile_needed(void)
403 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
404 static inline EXIM_DB *
405 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
408 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
411 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
413 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
415 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
416 return res->dptr != NULL;
419 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
421 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
422 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
424 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
426 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
427 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
429 /* Returns from EXIM_DBPUTB */
431 # define EXIM_DBPUTB_OK 0
432 # define EXIM_DBPUTB_DUP (-1)
436 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
437 { return tdb_delete(dbp, *key); }
439 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
440 static inline EXIM_CURSOR *
441 exim_dbcreate_cursor(EXIM_DB * dbp)
443 # ifdef COMPILE_UTILITY
444 EXIM_CURSOR * c = malloc(sizeof(TDB_DATA));
446 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
452 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
453 free() must not die when passed NULL */
456 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
457 EXIM_CURSOR * cursor)
459 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
462 return key->dptr != NULL;
465 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
467 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
468 { store_free(cursor); }
472 exim_dbclose__(EXIM_DB * db)
477 static inline uschar *
478 exim_datum_data_get(EXIM_DATUM * dp)
479 { return US dp->dptr; }
481 exim_datum_data_set(EXIM_DATUM * dp, void * s)
484 static inline unsigned
485 exim_datum_size_get(EXIM_DATUM * dp)
486 { return dp->dsize; }
488 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
491 /* No initialization is needed. */
494 exim_datum_init(EXIM_DATUM * d)
497 /* Free the stuff inside the datum. */
500 exim_datum_free(EXIM_DATUM * d)
508 # define EXIM_DB_RLIMIT 150
515 /********************* Berkeley db native definitions **********************/
519 # if defined(USE_TDB) || defined(USE_GDBM) || defined(USE_SQLITE)
520 # error USE_DB conflict with alternate definition
525 /* 1.x did no locking
526 2.x had facilities, but exim does it's own
530 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
531 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
533 # ifdef DB_VERSION_STRING
535 # if DB_VERSION_MAJOR >= 6
536 # error Version 6 and later BDB API is not supported
539 /* The API changed (again!) between the 2.x and 3.x versions */
541 # if DB_VERSION_MAJOR >= 3
543 /***************** Berkeley db 3.x/4.x native definitions ******************/
546 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
547 # define EXIM_DB DB_ENV
548 /* Cursor type, for scanning */
549 # define EXIM_CURSOR DBC
551 /* The datum type used for queries */
552 # define EXIM_DATUM DBT
554 /* Some text for messages */
555 # define EXIM_DBTYPE "db (v4.1+)"
557 /* Only more-recent versions. 5+ ? */
558 # ifndef DB_FORCESYNC
559 # define DB_FORCESYNC 0
563 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
564 errors. This should help with debugging strange DB problems, e.g. getting "File
565 exists" when you try to open a db file. The API for this function was changed
566 at DB release 4.3. */
569 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
572 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
578 /* Access functions (BDB 4.1+) */
581 exim_lockfile_needed(void)
586 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
587 /* The API changed for DB 4.1. - and we also starting using the "env" with a
588 specified working dir, to avoid the DBCONFIG file trap. */
590 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
592 static inline EXIM_DB *
593 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
598 if ( db_env_create(&dbp, 0) != 0
599 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
600 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
603 if (db_create(&b, dbp, 0) == 0)
605 dbp->app_private = b;
606 if (b->open(b, NULL, CS name, NULL,
607 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
608 flags & O_CREAT ? DB_CREATE
609 : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY,
620 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
622 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
624 DB * b = ENV_TO_DB(dbp);
625 return b->get(b, NULL, key, res, 0) == 0;
628 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
630 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
632 DB * b = ENV_TO_DB(dbp);
633 return b->put(b, NULL, key, data, 0);
636 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
638 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
640 DB * b = ENV_TO_DB(dbp);
641 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
644 /* Return values from EXIM_DBPUTB */
646 # define EXIM_DBPUTB_OK 0
647 # define EXIM_DBPUTB_DUP DB_KEYEXIST
651 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
653 DB * b = ENV_TO_DB(dbp);
654 return b->del(b, NULL, key, 0);
657 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
659 static inline EXIM_CURSOR *
660 exim_dbcreate_cursor(EXIM_DB * dbp)
662 DB * b = ENV_TO_DB(dbp);
664 b->cursor(b, NULL, &c, 0);
668 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
670 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
671 EXIM_CURSOR * cursor)
673 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
676 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
678 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
679 { cursor->c_close(cursor); }
683 exim_dbclose__(EXIM_DB * dbp_o)
685 DB_ENV * dbp = dbp_o;
686 DB * b = ENV_TO_DB(dbp);
688 dbp->close(dbp, DB_FORCESYNC);
693 static inline uschar *
694 exim_datum_data_get(EXIM_DATUM * dp)
697 exim_datum_data_set(EXIM_DATUM * dp, void * s)
700 static inline unsigned
701 exim_datum_size_get(EXIM_DATUM * dp)
704 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
707 /* The whole datum structure contains other fields that must be cleared
708 before use, but we don't have to free anything after reading data. */
711 exim_datum_init(EXIM_DATUM * d)
712 { memset(d, 0, sizeof(*d)); }
715 exim_datum_free(EXIM_DATUM * d)
718 # else /* pre- 4.1 */
722 /* Cursor type, for scanning */
723 # define EXIM_CURSOR DBC
725 /* The datum type used for queries */
726 # define EXIM_DATUM DBT
728 /* Some text for messages */
729 # define EXIM_DBTYPE "db (v3/4)"
731 /* Access functions (BDB 3/4) */
734 exim_lockfile_needed(void)
739 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
740 static inline EXIM_DB *
741 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
745 return db_create(&dbp, NULL, 0) == 0
746 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
747 dbp->open(dbp, CS name, NULL,
748 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
749 flags & O_CREAT ? DB_CREATE
750 : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY,
756 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
758 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
759 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
761 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
763 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
764 { return dbp->put(dbp, NULL, key, data, 0); }
766 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
768 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
769 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
771 /* Return values from EXIM_DBPUTB */
773 # define EXIM_DBPUTB_OK 0
774 # define EXIM_DBPUTB_DUP DB_KEYEXIST
778 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
779 { return dbp->del(dbp, NULL, key, 0); }
781 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
783 static inline EXIM_CURSOR *
784 exim_dbcreate_cursor(EXIM_DB * dbp)
787 dbp->cursor(dbp, NULL, &c, 0);
791 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
793 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
794 EXIM_CURSOR * cursor)
796 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
799 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
801 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
802 { cursor->c_close(cursor); }
806 exim_dbclose__(EXIM_DB * dbp)
807 { dbp->close(dbp, 0); }
811 static inline uschar *
812 exim_datum_data_get(EXIM_DATUM * dp)
813 { return US dp->dptr; }
815 exim_datum_data_set(EXIM_DATUM * dp, void * s)
818 static inline uschar *
819 exim_datum_size_get(EXIM_DATUM * dp)
820 { return US dp->size; }
822 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
825 /* The whole datum structure contains other fields that must be cleared
826 before use, but we don't have to free anything after reading data. */
829 exim_datum_init(EXIM_DATUM * d)
830 { memset(d, 0, sizeof(*d)); }
833 exim_datum_free(EXIM_DATUM * d)
839 # else /* DB_VERSION_MAJOR >= 3 */
840 # error Berkeley DB versions earlier than 3 are not supported */
841 # endif /* DB_VERSION_MAJOR */
843 # error Berkeley DB version 1 is no longer supported
844 # endif /* DB_VERSION_STRING */
847 /* all BDB versions */
850 # define EXIM_DB_RLIMIT 150
857 /********************* gdbm interface definitions **********************/
859 #elif defined USE_GDBM
860 /*XXX TODO: exim's lockfile not needed? */
862 # if defined(USE_TDB) || defined(USE_DB) || defined(USE_SQLITE)
863 # error USE_GDBM conflict with alternate definition
870 GDBM_FILE gdbm; /* Database */
871 datum lkey; /* Last key, for scans */
874 /* Cursor type, not used with gdbm: just set up a dummy */
875 # define EXIM_CURSOR int
877 /* The datum type used for queries */
878 # define EXIM_DATUM datum
880 /* Some text for messages */
882 # define EXIM_DBTYPE "gdbm"
884 /* Access functions (gdbm) */
887 exim_lockfile_needed(void)
892 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
893 static inline EXIM_DB *
894 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
897 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
900 dbp->lkey.dptr = NULL;
901 dbp->gdbm = gdbm_open(CS name, 0,
902 flags & O_CREAT ? GDBM_WRCREAT
903 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER : GDBM_READER,
905 if (dbp->gdbm) return dbp;
911 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
913 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
915 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
916 return res->dptr != NULL;
919 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
921 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
922 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
924 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
926 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
927 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
929 /* Returns from EXIM_DBPUTB */
931 # define EXIM_DBPUTB_OK 0
932 # define EXIM_DBPUTB_DUP 1
936 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
937 { return gdbm_delete(dbp->gdbm, *key); }
939 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
940 static inline EXIM_CURSOR *
941 exim_dbcreate_cursor(EXIM_DB * dbp)
946 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
947 EXIM_CURSOR * cursor)
950 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
951 if ((s = dbp->lkey.dptr)) free(s);
953 return key->dptr != NULL;
956 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
958 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
963 exim_dbclose__(EXIM_DB * dbp)
966 gdbm_close(dbp->gdbm);
967 if ((s = dbp->lkey.dptr)) free(s);
971 /* Datum access types */
973 static inline uschar *
974 exim_datum_data_get(EXIM_DATUM * dp)
975 { return US dp->dptr; }
977 exim_datum_data_set(EXIM_DATUM * dp, void * s)
980 static inline unsigned
981 exim_datum_size_get(EXIM_DATUM * dp)
982 { return dp->dsize; }
984 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
987 /* There's no clearing required before use, but we have to free the dptr
988 after reading data. */
991 exim_datum_init(EXIM_DATUM * d)
995 exim_datum_free(EXIM_DATUM * d)
998 /* size limit. GDBM is int-max limited, but we want to be less silly */
1000 # define EXIM_DB_RLIMIT 150
1002 #else /* USE_GDBM */
1009 /* If none of USE_DB, USG_GDBM, USE_SQLITE or USE_TDB are set,
1010 the default is the NDBM interface (which seems to be a wrapper for GDBM) */
1013 /********************* ndbm interface definitions **********************/
1018 # define EXIM_DB DBM
1020 /* Cursor type, not used with ndbm: just set up a dummy */
1021 # define EXIM_CURSOR int
1023 /* The datum type used for queries */
1024 # define EXIM_DATUM datum
1026 /* Some text for messages */
1028 # define EXIM_DBTYPE "ndbm"
1030 /* Access functions (ndbm) */
1033 exim_lockfile_needed(void)
1038 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
1039 /* Check that the name given is not present. This catches
1040 a directory name; otherwise we would create the name.pag and
1041 name.dir files in the directory's parent. */
1043 static inline EXIM_DB *
1044 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
1048 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
1049 return dbm_open(CS name, flags, mode);
1050 #ifndef COMPILE_UTILITY
1051 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
1053 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
1057 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
1059 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
1061 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
1062 return res->dptr != NULL;
1065 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
1067 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1068 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
1070 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
1072 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1073 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
1075 /* Returns from EXIM_DBPUTB */
1077 # define EXIM_DBPUTB_OK 0
1078 # define EXIM_DBPUTB_DUP 1
1082 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
1083 { return dbm_delete(dbp, *key); }
1085 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
1086 static inline EXIM_CURSOR *
1087 exim_dbcreate_cursor(EXIM_DB * dbp)
1092 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
1093 EXIM_CURSOR * cursor)
1095 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
1096 return key->dptr != NULL;
1099 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
1101 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
1106 exim_dbclose__(EXIM_DB * dbp)
1109 /* Datum access types */
1111 static inline uschar *
1112 exim_datum_data_get(EXIM_DATUM * dp)
1113 { return US dp->dptr; }
1115 exim_datum_data_set(EXIM_DATUM * dp, void * s)
1118 static inline unsigned
1119 exim_datum_size_get(EXIM_DATUM * dp)
1120 { return dp->dsize; }
1122 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
1125 /* There's no clearing required before use, and we don't have to free anything
1126 after reading data. */
1129 exim_datum_init(EXIM_DATUM * d)
1133 exim_datum_free(EXIM_DATUM * d)
1138 # define EXIM_DB_RLIMIT 150
1140 #endif /* !USE_GDBM */
1146 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
1148 static inline EXIM_DB *
1149 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1152 return exim_dbopen__(name, dirname, flags, mode);
1156 exim_dbclose(EXIM_DB * dbp)
1157 { exim_dbclose__(dbp); }
1159 #else /* exim mainline code */
1161 /* Wrappers for open/close with debug tracing */
1163 extern void debug_printf_indent(const char *, ...);
1164 static inline BOOL is_tainted(const void *);
1166 static inline EXIM_DB *
1167 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1171 DEBUG(D_hints_lookup)
1172 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
1174 flags == O_RDONLY ? "O_RDONLY"
1175 : flags == O_RDWR ? "O_RDWR"
1176 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
1178 if (is_tainted(name) || is_tainted(dirname))
1180 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
1184 dbp = exim_dbopen__(name, dirname, flags, mode);
1186 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
1191 exim_dbclose(EXIM_DB * dbp)
1193 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
1194 exim_dbclose__(dbp);
1197 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
1199 /********************* End of dbm library definitions **********************/
1202 #endif /* whole file */
1203 /* End of hintsdb.h */