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_dbopen O_RDONLY/O_RDWR, optionally OR'd with O_CREAT
30 exim_dbputb (non-overwriting put)
33 exim_dbscan (get, and bump cursor)
36 exim_datum_size_get/set
37 exim_datum_data_get/set
41 EXIM_CURSOR datatype for cursor
42 EXIM_DATUM datatype for "value"
43 EXIM_DBTYPE text for logging & debuug
45 Selection of the shim layer implementation, and backend, is by #defines.
47 The users of this API are:
48 hintsdb interface dbfn.c
49 hintsdb utilities exim_dbutil.c and exim_dbmvuild.c
50 dbmdb lookup lookups/dbmdb,c
51 autoreply transport transports/autoreply.c
53 Note that the dbmdb lookup use, bypassing the dbfn.c layer,
54 means that no file-locking is done.
55 XXX This feels like a layering violation; I don't see it commented on
58 Future: consider re-architecting to support caching of the open-handle
59 for hintsdb uses (the dbmdb use gets that already). This would need APIs
60 for transaction locks. Perhaps merge the implementation with the lookups
61 layer, in some way, for the open-handle caching (since that manages closes
62 required by Exim's process transisitions)?
70 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_TDB)
71 # error USE_SQLITE conflict with alternate definition
74 /* ********************* sqlite3 interface ************************ */
79 # define EXIM_DB sqlite3
81 # define EXIM_CURSOR int
83 # /* The datum type used for queries */
84 # define EXIM_DATUM blob
86 /* Some text for messages */
87 # define EXIM_DBTYPE "sqlite3"
89 # /* Access functions */
91 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
92 static inline EXIM_DB *
93 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
97 int ret, sflags = flags & O_RDWR ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
98 if (flags & O_CREAT) sflags |= SQLITE_OPEN_CREATE;
99 if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK)
101 sqlite3_busy_timeout(dbp, 5000);
103 ret == sqlite3_exec(dbp,
104 "CREATE TABLE IF NOT EXISTS tbl (ky TEXT PRIMARY KEY, dat BLOB);",
108 // fprintf(stderr, "sqlite3_open_v2: %s\n", sqlite3_errmsg(dbp));
109 return ret == SQLITE_OK ? dbp : NULL;
112 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
113 /* note we alloc'n'copy - the caller need not do so */
114 /* result has a NUL appended, but the length is as per the DB */
117 exim_dbget__(EXIM_DB * dbp, const uschar * s, EXIM_DATUM * res)
119 sqlite3_stmt * statement;
122 res->len = (size_t) -1;
123 /* fprintf(stderr, "exim_dbget__(%s)\n", s); */
124 if ((ret = sqlite3_prepare_v2(dbp, CCS s, -1, &statement, NULL)) != SQLITE_OK)
126 /* fprintf(stderr, "prepare fail: %s\n", sqlite3_errmsg(dbp)); */
129 if (sqlite3_step(statement) != SQLITE_ROW)
131 /* fprintf(stderr, "step fail: %s\n", sqlite3_errmsg(dbp)); */
132 sqlite3_finalize(statement);
136 res->len = sqlite3_column_bytes(statement, 0);
137 res->data = store_get(res->len + 1, GET_TAINTED);
138 memcpy(res->data, sqlite3_column_blob(statement, 0), res->len);
139 res->data[res->len] = '\0';
140 /* fprintf(stderr, "res %d bytes: '%.*s'\n", (int)res->len, (int)res->len, res->data); */
141 sqlite3_finalize(statement);
146 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
148 # define FMT "SELECT dat FROM tbl WHERE ky = '%.*s';"
153 # ifdef COMPILE_UTILITY
154 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
155 qry = malloc(i = snprintf(NULL, 0, FMT, (int) key->len, key->data));
156 snprintf(CS qry, i, FMT, (int) key->len, key->data);
157 ret = exim_dbget__(dbp, qry, res);
160 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
161 qry = string_sprintf(FMT, (int) key->len, key->data);
162 ret = exim_dbget__(dbp, qry, res);
170 # define EXIM_DBPUTB_OK 0
171 # define EXIM_DBPUTB_DUP (-1)
174 exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const uschar * alt)
176 # define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%.*s', X'%.*s');"
177 uschar * hex = store_get(data->len * 2, data->data), * qry;
180 for (const uschar * s = data->data, * t = s + data->len; s < t; s++)
181 sprintf(CS hex + 2 * (s - data->data), "%02X", *s);
183 # ifdef COMPILE_UTILITY
184 res = snprintf(NULL, 0, FMT,
185 alt, (int) key->len, key->data, (int)data->len * 2, hex);
187 snprintf(CS qry, res, FMT, alt, (int) key->len, key->data, (int)data->len * 2, hex);
188 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
189 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
192 qry = string_sprintf(FMT, alt, (int) key->len, key->data, (int)data->len * 2, hex);
193 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
194 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
195 /* fprintf(stderr, "exim_s_dbp res %d\n", res); */
198 if (res != SQLITE_OK)
199 fprintf(stderr, "sqlite3_exec: %s\n", sqlite3_errmsg(dbp));
201 return res == SQLITE_OK ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP;
205 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
208 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
210 /* fprintf(stderr, "exim_dbput()\n"); */
211 (void) exim_s_dbp(dbp, key, data, US"REPLACE");
215 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
217 /* Returns from EXIM_DBPUTB */
220 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
222 return exim_s_dbp(dbp, key, data, US"ABORT");
227 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
229 # define FMT "DELETE FROM tbl WHERE ky = '%.*s';"
233 # ifdef COMPILE_UTILITY
234 res = snprintf(NULL, 0, FMT, (int) key->len, key->data);
236 snprintf(CS qry, res, FMT, (int) key->len, key->data);
237 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
240 qry = string_sprintf(FMT, (int) key->len, key->data);
241 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
249 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
250 /* Cursors are inefficiently emulated by repeating searches */
252 static inline EXIM_CURSOR *
253 exim_dbcreate_cursor(EXIM_DB * dbp)
255 EXIM_CURSOR * c = store_malloc(sizeof(int));
261 /* Note that we return the (next) key, not the record value */
263 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
264 EXIM_CURSOR * cursor)
266 # define FMT "SELECT ky FROM tbl ORDER BY ky LIMIT 1 OFFSET %d;"
271 # ifdef COMPILE_UTILITY
272 qry = malloc(i = snprintf(NULL, 0, FMT, *cursor));
273 snprintf(CS qry, i, FMT, *cursor);
274 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
275 ret = exim_dbget__(dbp, qry, key);
277 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
279 qry = string_sprintf(FMT, *cursor);
280 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
281 ret = exim_dbget__(dbp, qry, key);
282 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
284 if (ret) *cursor = *cursor + 1;
289 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
291 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
292 { store_free(cursor); }
297 exim_dbclose__(EXIM_DB * db)
298 { sqlite3_close(db); }
304 exim_datum_data_get(EXIM_DATUM * dp)
305 { return US dp->data; }
307 exim_datum_data_set(EXIM_DATUM * dp, void * s)
311 exim_datum_size_get(EXIM_DATUM * dp)
314 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
320 exim_datum_init(EXIM_DATUM * dp)
321 { dp->data = NULL; } /* compiler quietening */
323 /* No free needed for a datum */
326 exim_datum_free(EXIM_DATUM * dp)
331 # define EXIM_DB_RLIMIT 150
338 #elif defined(USE_TDB)
340 # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_SQLITE)
341 # error USE_TDB conflict with alternate definition
344 /* ************************* tdb interface ************************ */
345 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
346 Could we lose the file lock? */
351 # define EXIM_DB TDB_CONTEXT
353 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
354 tdb_traverse to be called) */
355 # define EXIM_CURSOR TDB_DATA
357 /* The datum type used for queries */
358 # define EXIM_DATUM TDB_DATA
360 /* Some text for messages */
361 # define EXIM_DBTYPE "tdb"
363 /* Access functions */
365 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
366 static inline EXIM_DB *
367 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
370 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
373 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
375 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
377 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
378 return res->dptr != NULL;
381 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
383 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
384 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
386 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
388 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
389 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
391 /* Returns from EXIM_DBPUTB */
393 # define EXIM_DBPUTB_OK 0
394 # define EXIM_DBPUTB_DUP (-1)
398 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
399 { return tdb_delete(dbp, *key); }
401 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
402 static inline EXIM_CURSOR *
403 exim_dbcreate_cursor(EXIM_DB * dbp)
405 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
410 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
411 free() must not die when passed NULL */
414 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
415 EXIM_CURSOR * cursor)
417 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
420 return key->dptr != NULL;
423 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
425 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
426 { store_free(cursor); }
430 exim_dbclose__(EXIM_DB * db)
435 static inline uschar *
436 exim_datum_data_get(EXIM_DATUM * dp)
437 { return US dp->dptr; }
439 exim_datum_data_set(EXIM_DATUM * dp, void * s)
442 static inline unsigned
443 exim_datum_size_get(EXIM_DATUM * dp)
444 { return dp->dsize; }
446 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
449 /* No initialization is needed. */
452 exim_datum_init(EXIM_DATUM * d)
455 /* Free the stuff inside the datum. */
458 exim_datum_free(EXIM_DATUM * d)
466 # define EXIM_DB_RLIMIT 150
473 /********************* Berkeley db native definitions **********************/
477 # if defined(USE_TDB) || defined(USE_GDBM) || defined(USE_SQLITE)
478 # error USE_DB conflict with alternate definition
483 /* 1.x did no locking
484 2.x had facilities, but exim does it's own
488 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
489 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
491 # ifdef DB_VERSION_STRING
493 # if DB_VERSION_MAJOR >= 6
494 # error Version 6 and later BDB API is not supported
497 /* The API changed (again!) between the 2.x and 3.x versions */
499 # if DB_VERSION_MAJOR >= 3
501 /***************** Berkeley db 3.x/4.x native definitions ******************/
504 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
505 # define EXIM_DB DB_ENV
506 /* Cursor type, for scanning */
507 # define EXIM_CURSOR DBC
509 /* The datum type used for queries */
510 # define EXIM_DATUM DBT
512 /* Some text for messages */
513 # define EXIM_DBTYPE "db (v4.1+)"
515 /* Only more-recent versions. 5+ ? */
516 # ifndef DB_FORCESYNC
517 # define DB_FORCESYNC 0
521 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
522 errors. This should help with debugging strange DB problems, e.g. getting "File
523 exists" when you try to open a db file. The API for this function was changed
524 at DB release 4.3. */
527 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
530 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
536 /* Access functions */
538 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
539 /* The API changed for DB 4.1. - and we also starting using the "env" with a
540 specified working dir, to avoid the DBCONFIG file trap. */
542 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
544 static inline EXIM_DB *
545 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
550 if ( db_env_create(&dbp, 0) != 0
551 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
552 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
555 if (db_create(&b, dbp, 0) == 0)
557 dbp->app_private = b;
558 if (b->open(b, NULL, CS name, NULL,
559 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
560 flags & O_CREAT ? DB_CREATE
561 : flags & O_RDONLY ? DB_RDONLY
562 : 0, /*XXX is there a writeable if exists option? */
573 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
575 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
577 DB * b = ENV_TO_DB(dbp);
578 return b->get(b, NULL, key, res, 0) == 0;
581 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
583 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
585 DB * b = ENV_TO_DB(dbp);
586 return b->put(b, NULL, key, data, 0);
589 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
591 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
593 DB * b = ENV_TO_DB(dbp);
594 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
597 /* Return values from EXIM_DBPUTB */
599 # define EXIM_DBPUTB_OK 0
600 # define EXIM_DBPUTB_DUP DB_KEYEXIST
604 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
606 DB * b = ENV_TO_DB(dbp);
607 return b->del(b, NULL, key, 0);
610 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
612 static inline EXIM_CURSOR *
613 exim_dbcreate_cursor(EXIM_DB * dbp)
615 DB * b = ENV_TO_DB(dbp);
617 b->cursor(b, NULL, &c, 0);
621 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
623 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
624 EXIM_CURSOR * cursor)
626 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
629 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
631 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
632 { cursor->c_close(cursor); }
636 exim_dbclose__(EXIM_DB * dbp_o)
638 DB_ENV * dbp = dbp_o;
639 DB * b = ENV_TO_DB(dbp);
641 dbp->close(dbp, DB_FORCESYNC);
646 static inline uschar *
647 exim_datum_data_get(EXIM_DATUM * dp)
650 exim_datum_data_set(EXIM_DATUM * dp, void * s)
653 static inline unsigned
654 exim_datum_size_get(EXIM_DATUM * dp)
657 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
660 /* The whole datum structure contains other fields that must be cleared
661 before use, but we don't have to free anything after reading data. */
664 exim_datum_init(EXIM_DATUM * d)
665 { memset(d, 0, sizeof(*d)); }
668 exim_datum_free(EXIM_DATUM * d)
671 # else /* pre- 4.1 */
675 /* Cursor type, for scanning */
676 # define EXIM_CURSOR DBC
678 /* The datum type used for queries */
679 # define EXIM_DATUM DBT
681 /* Some text for messages */
682 # define EXIM_DBTYPE "db (v3/4)"
684 /* Access functions */
686 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
687 static inline EXIM_DB *
688 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
692 return db_create(&dbp, NULL, 0) == 0
693 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
694 dbp->open(dbp, CS name, NULL,
695 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
696 flags & O_CREAT ? DB_CREATE
697 : flags & O_RDONLY ? DB_RDONLY
704 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
706 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
707 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
709 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
711 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
712 { return dbp->put(dbp, NULL, key, data, 0); }
714 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
716 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
717 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
719 /* Return values from EXIM_DBPUTB */
721 # define EXIM_DBPUTB_OK 0
722 # define EXIM_DBPUTB_DUP DB_KEYEXIST
726 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
727 { return dbp->del(dbp, NULL, key, 0); }
729 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
731 static inline EXIM_CURSOR *
732 exim_dbcreate_cursor(EXIM_DB * dbp)
735 dbp->cursor(dbp, NULL, &c, 0);
739 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
741 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
742 EXIM_CURSOR * cursor)
744 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
747 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
749 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
750 { cursor->c_close(cursor); }
754 exim_dbclose__(EXIM_DB * dbp)
755 { dbp->close(dbp, 0); }
759 static inline uschar *
760 exim_datum_data_get(EXIM_DATUM * dp)
761 { return US dp->dptr; }
763 exim_datum_data_set(EXIM_DATUM * dp, void * s)
766 static inline uschar *
767 exim_datum_size_get(EXIM_DATUM * dp)
768 { return US dp->size; }
770 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
773 /* The whole datum structure contains other fields that must be cleared
774 before use, but we don't have to free anything after reading data. */
777 exim_datum_init(EXIM_DATUM * d)
778 { memset(d, 0, sizeof(*d)); }
781 exim_datum_free(EXIM_DATUM * d)
787 # else /* DB_VERSION_MAJOR >= 3 */
788 # error Berkeley DB versions earlier than 3 are not supported */
789 # endif /* DB_VERSION_MAJOR */
791 # error Berkeley DB version 1 is no longer supported
792 # endif /* DB_VERSION_STRING */
795 /* all BDB versions */
798 # define EXIM_DB_RLIMIT 150
805 /********************* gdbm interface definitions **********************/
807 #elif defined USE_GDBM
808 /*XXX TODO: exim's lockfile not needed? */
810 # if defined(USE_TDB) || defined(USE_DB) || defined(USE_SQLITE)
811 # error USE_GDBM conflict with alternate definition
818 GDBM_FILE gdbm; /* Database */
819 datum lkey; /* Last key, for scans */
822 /* Cursor type, not used with gdbm: just set up a dummy */
823 # define EXIM_CURSOR int
825 /* The datum type used for queries */
826 # define EXIM_DATUM datum
828 /* Some text for messages */
830 # define EXIM_DBTYPE "gdbm"
832 /* Access functions */
834 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
835 static inline EXIM_DB *
836 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
839 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
842 dbp->lkey.dptr = NULL;
843 dbp->gdbm = gdbm_open(CS name, 0,
844 flags & O_CREAT ? GDBM_WRCREAT
845 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
848 if (dbp->gdbm) return dbp;
854 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
856 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
858 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
859 return res->dptr != NULL;
862 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
864 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
865 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
867 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
869 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
870 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
872 /* Returns from EXIM_DBPUTB */
874 # define EXIM_DBPUTB_OK 0
875 # define EXIM_DBPUTB_DUP 1
879 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
880 { return gdbm_delete(dbp->gdbm, *key); }
882 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
883 static inline EXIM_CURSOR *
884 exim_dbcreate_cursor(EXIM_DB * dbp)
889 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
890 EXIM_CURSOR * cursor)
893 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
894 if ((s = dbp->lkey.dptr)) free(s);
896 return key->dptr != NULL;
899 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
901 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
906 exim_dbclose__(EXIM_DB * dbp)
909 gdbm_close(dbp->gdbm);
910 if ((s = dbp->lkey.dptr)) free(s);
914 /* Datum access types */
916 static inline uschar *
917 exim_datum_data_get(EXIM_DATUM * dp)
918 { return US dp->dptr; }
920 exim_datum_data_set(EXIM_DATUM * dp, void * s)
923 static inline unsigned
924 exim_datum_size_get(EXIM_DATUM * dp)
925 { return dp->dsize; }
927 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
930 /* There's no clearing required before use, but we have to free the dptr
931 after reading data. */
934 exim_datum_init(EXIM_DATUM * d)
938 exim_datum_free(EXIM_DATUM * d)
941 /* size limit. GDBM is int-max limited, but we want to be less silly */
943 # define EXIM_DB_RLIMIT 150
952 /* If none of USE_DB, USG_GDBM, USE_SQLITE or USE_TDB are set,
953 the default is the NDBM interface (which seems to be a wrapper for GDBM) */
956 /********************* ndbm interface definitions **********************/
963 /* Cursor type, not used with ndbm: just set up a dummy */
964 # define EXIM_CURSOR int
966 /* The datum type used for queries */
967 # define EXIM_DATUM datum
969 /* Some text for messages */
971 # define EXIM_DBTYPE "ndbm"
973 /* Access functions */
975 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
976 /* Check that the name given is not present. This catches
977 a directory name; otherwise we would create the name.pag and
978 name.dir files in the directory's parent. */
980 static inline EXIM_DB *
981 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
985 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
986 return dbm_open(CS name, flags, mode);
987 #ifndef COMPILE_UTILITY
988 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
990 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
994 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
996 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
998 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
999 return res->dptr != NULL;
1002 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
1004 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1005 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
1007 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
1009 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
1010 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
1012 /* Returns from EXIM_DBPUTB */
1014 # define EXIM_DBPUTB_OK 0
1015 # define EXIM_DBPUTB_DUP 1
1019 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
1020 { return dbm_delete(dbp, *key); }
1022 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
1023 static inline EXIM_CURSOR *
1024 exim_dbcreate_cursor(EXIM_DB * dbp)
1029 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
1030 EXIM_CURSOR * cursor)
1032 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
1033 return key->dptr != NULL;
1036 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
1038 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
1043 exim_dbclose__(EXIM_DB * dbp)
1046 /* Datum access types */
1048 static inline uschar *
1049 exim_datum_data_get(EXIM_DATUM * dp)
1050 { return US dp->dptr; }
1052 exim_datum_data_set(EXIM_DATUM * dp, void * s)
1055 static inline unsigned
1056 exim_datum_size_get(EXIM_DATUM * dp)
1057 { return dp->dsize; }
1059 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
1062 /* There's no clearing required before use, and we don't have to free anything
1063 after reading data. */
1066 exim_datum_init(EXIM_DATUM * d)
1070 exim_datum_free(EXIM_DATUM * d)
1075 # define EXIM_DB_RLIMIT 150
1077 #endif /* !USE_GDBM */
1083 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
1085 static inline EXIM_DB *
1086 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1089 return exim_dbopen__(name, dirname, flags, mode);
1093 exim_dbclose(EXIM_DB * dbp)
1094 { exim_dbclose__(dbp); }
1096 #else /* exim mainline code */
1098 /* Wrappers for open/close with debug tracing */
1100 extern void debug_printf_indent(const char *, ...);
1101 static inline BOOL is_tainted(const void *);
1103 static inline EXIM_DB *
1104 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1108 DEBUG(D_hints_lookup)
1109 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
1111 flags == O_RDONLY ? "O_RDONLY"
1112 : flags == O_RDWR ? "O_RDWR"
1113 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
1115 if (is_tainted(name) || is_tainted(dirname))
1117 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
1121 dbp = exim_dbopen__(name, dirname, flags, mode);
1123 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
1128 exim_dbclose(EXIM_DB * dbp)
1130 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
1131 exim_dbclose__(dbp);
1134 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
1136 /********************* End of dbm library definitions **********************/
1139 #endif /* whole file */
1140 /* End of hintsdb.h */