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)
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
60 /* ********************* sqlite3 interface ************************ */
65 # define EXIM_DB sqlite3
67 # define EXIM_CURSOR int
69 # /* The datum type used for queries */
70 # define EXIM_DATUM blob
72 /* Some text for messages */
73 # define EXIM_DBTYPE "sqlite3"
75 # /* Access functions */
77 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
78 static inline EXIM_DB *
79 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
83 int ret, sflags = flags & O_RDWR ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
84 if (flags & O_CREAT) sflags |= SQLITE_OPEN_CREATE;
85 if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK)
87 sqlite3_busy_timeout(dbp, 5000);
89 ret == sqlite3_exec(dbp,
90 "CREATE TABLE IF NOT EXISTS tbl (ky TEXT PRIMARY KEY, dat BLOB);",
94 // fprintf(stderr, "sqlite3_open_v2: %s\n", sqlite3_errmsg(dbp));
95 return ret == SQLITE_OK ? dbp : NULL;
98 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
99 /* note we alloc'n'copy - the caller need not do so */
100 /* result has a NUL appended, but the length is as per the DB */
103 exim_dbget__(EXIM_DB * dbp, const uschar * s, EXIM_DATUM * res)
105 sqlite3_stmt * statement;
108 res->len = (size_t) -1;
109 /* fprintf(stderr, "exim_dbget__(%s)\n", s); */
110 if ((ret = sqlite3_prepare_v2(dbp, CCS s, -1, &statement, NULL)) != SQLITE_OK)
112 /* fprintf(stderr, "prepare fail: %s\n", sqlite3_errmsg(dbp)); */
115 if (sqlite3_step(statement) != SQLITE_ROW)
117 /* fprintf(stderr, "step fail: %s\n", sqlite3_errmsg(dbp)); */
118 sqlite3_finalize(statement);
122 res->len = sqlite3_column_bytes(statement, 0);
123 res->data = store_get(res->len + 1, GET_TAINTED);
124 memcpy(res->data, sqlite3_column_blob(statement, 0), res->len);
125 res->data[res->len] = '\0';
126 /* fprintf(stderr, "res %d bytes: '%.*s'\n", (int)res->len, (int)res->len, res->data); */
127 sqlite3_finalize(statement);
132 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
134 # define FMT "SELECT dat FROM tbl WHERE ky = '%.*s';"
139 # ifdef COMPILE_UTILITY
140 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
141 qry = malloc(i = snprintf(NULL, 0, FMT, (int) key->len, key->data));
142 snprintf(CS qry, i, FMT, (int) key->len, key->data);
143 ret = exim_dbget__(dbp, qry, res);
146 /* fprintf(stderr, "exim_dbget(k len %d '%.*s')\n", (int)key->len, (int)key->len, key->data); */
147 qry = string_sprintf(FMT, (int) key->len, key->data);
148 ret = exim_dbget__(dbp, qry, res);
156 # define EXIM_DBPUTB_OK 0
157 # define EXIM_DBPUTB_DUP (-1)
160 exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const uschar * alt)
162 # define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%.*s', X'%.*s');"
163 uschar * hex = store_get(data->len * 2, data->data), * qry;
166 for (const uschar * s = data->data, * t = s + data->len; s < t; s++)
167 sprintf(CS hex + 2 * (s - data->data), "%02X", *s);
169 # ifdef COMPILE_UTILITY
170 res = snprintf(NULL, 0, FMT,
171 alt, (int) key->len, key->data, (int)data->len * 2, hex);
173 snprintf(CS qry, res, FMT, alt, (int) key->len, key->data, (int)data->len * 2, hex);
174 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
175 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
178 qry = string_sprintf(FMT, alt, (int) key->len, key->data, (int)data->len * 2, hex);
179 /* fprintf(stderr, "exim_s_dbp(%s)\n", qry); */
180 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
181 /* fprintf(stderr, "exim_s_dbp res %d\n", res); */
184 if (res != SQLITE_OK)
185 fprintf(stderr, "sqlite3_exec: %s\n", sqlite3_errmsg(dbp));
187 return res == SQLITE_OK ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP;
191 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
194 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
196 /* fprintf(stderr, "exim_dbput()\n"); */
197 (void) exim_s_dbp(dbp, key, data, US"REPLACE");
201 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
203 /* Returns from EXIM_DBPUTB */
206 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
208 return exim_s_dbp(dbp, key, data, US"ABORT");
213 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
215 # define FMT "DELETE FROM tbl WHERE ky = '%.*s';"
219 # ifdef COMPILE_UTILITY
220 res = snprintf(NULL, 0, FMT, (int) key->len, key->data);
222 snprintf(CS qry, res, FMT, (int) key->len, key->data);
223 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
226 qry = string_sprintf(FMT, (int) key->len, key->data);
227 res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
235 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
236 /* Cursors are inefficiently emulated by repeating searches */
238 static inline EXIM_CURSOR *
239 exim_dbcreate_cursor(EXIM_DB * dbp)
241 EXIM_CURSOR * c = store_malloc(sizeof(int));
247 /* Note that we return the (next) key, not the record value */
249 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
250 EXIM_CURSOR * cursor)
252 # define FMT "SELECT ky FROM tbl ORDER BY ky LIMIT 1 OFFSET %d;"
257 # ifdef COMPILE_UTILITY
258 qry = malloc(i = snprintf(NULL, 0, FMT, *cursor));
259 snprintf(CS qry, i, FMT, *cursor);
260 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
261 ret = exim_dbget__(dbp, qry, key);
263 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
265 qry = string_sprintf(FMT, *cursor);
266 /* fprintf(stderr, "exim_dbscan(%s)\n", qry); */
267 ret = exim_dbget__(dbp, qry, key);
268 /* fprintf(stderr, "exim_dbscan ret %c\n", ret ? 'T':'F'); */
270 if (ret) *cursor = *cursor + 1;
275 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
277 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
278 { store_free(cursor); }
283 exim_dbclose__(EXIM_DB * db)
284 { sqlite3_close(db); }
290 exim_datum_data_get(EXIM_DATUM * dp)
291 { return US dp->data; }
293 exim_datum_data_set(EXIM_DATUM * dp, void * s)
297 exim_datum_size_get(EXIM_DATUM * dp)
300 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
306 exim_datum_init(EXIM_DATUM * dp)
307 { dp->data = NULL; } /* compiler quietening */
309 /* No free needed for a datum */
312 exim_datum_free(EXIM_DATUM * dp)
317 # define EXIM_DB_RLIMIT 150
324 #elif defined(USE_TDB)
326 # if defined(USE_DB) || defined(USE_GDBM)
327 # error USE_TDB conflict with alternate definition
330 /* ************************* tdb interface ************************ */
331 /*XXX https://manpages.org/tdb/3 mentions concurrent writes.
332 Could we lose the file lock? */
337 # define EXIM_DB TDB_CONTEXT
339 /* Cursor type: tdb uses the previous "key" in _nextkey() (really it wants
340 tdb_traverse to be called) */
341 # define EXIM_CURSOR TDB_DATA
343 /* The datum type used for queries */
344 # define EXIM_DATUM TDB_DATA
346 /* Some text for messages */
347 # define EXIM_DBTYPE "tdb"
349 /* Access functions */
351 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
352 static inline EXIM_DB *
353 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
356 return tdb_open(CS name, 0, TDB_DEFAULT, flags, mode);
359 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
361 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
363 *res = tdb_fetch(dbp, *key); /* A struct arg and return!! */
364 return res->dptr != NULL;
367 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
369 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
370 { return tdb_store(dbp, *key, *data, TDB_REPLACE); }
372 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
374 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
375 { return tdb_store(dbp, *key, *data, TDB_INSERT); }
377 /* Returns from EXIM_DBPUTB */
379 # define EXIM_DBPUTB_OK 0
380 # define EXIM_DBPUTB_DUP (-1)
384 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
385 { return tdb_delete(dbp, *key); }
387 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
388 static inline EXIM_CURSOR *
389 exim_dbcreate_cursor(EXIM_DB * dbp)
391 EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA));
396 /* EXIM_DBSCAN - This is complicated because we have to free the last datum
397 free() must not die when passed NULL */
400 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first,
401 EXIM_CURSOR * cursor)
403 *key = first ? tdb_firstkey(dbp) : tdb_nextkey(dbp, *cursor);
406 return key->dptr != NULL;
409 /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */
411 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
412 { store_free(cursor); }
416 exim_dbclose__(EXIM_DB * db)
421 static inline uschar *
422 exim_datum_data_get(EXIM_DATUM * dp)
423 { return US dp->dptr; }
425 exim_datum_data_set(EXIM_DATUM * dp, void * s)
428 static inline unsigned
429 exim_datum_size_get(EXIM_DATUM * dp)
432 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
435 /* No initialization is needed. */
438 exim_datum_init(EXIM_DATUM * d)
441 /* Free the stuff inside the datum. */
444 exim_datum_free(EXIM_DATUM * d)
452 # define EXIM_DB_RLIMIT 150
459 /********************* Berkeley db native definitions **********************/
463 # if defined(USE_TDB) || defined(USE_GDBM)
464 # error USE_DB conflict with alternate definition
469 /* 1.x did no locking
470 2.x had facilities, but exim does it's own
474 /* We can distinguish between versions 1.x and 2.x/3.x by looking for a
475 definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
477 # ifdef DB_VERSION_STRING
479 # if DB_VERSION_MAJOR >= 6
480 # error Version 6 and later BDB API is not supported
483 /* The API changed (again!) between the 2.x and 3.x versions */
485 # if DB_VERSION_MAJOR >= 3
487 /***************** Berkeley db 3.x/4.x native definitions ******************/
490 # if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
491 # define EXIM_DB DB_ENV
492 /* Cursor type, for scanning */
493 # define EXIM_CURSOR DBC
495 /* The datum type used for queries */
496 # define EXIM_DATUM DBT
498 /* Some text for messages */
499 # define EXIM_DBTYPE "db (v4.1+)"
501 /* Only more-recent versions. 5+ ? */
502 # ifndef DB_FORCESYNC
503 # define DB_FORCESYNC 0
507 /* For Berkeley DB >= 2, we can define a function to be called in case of DB
508 errors. This should help with debugging strange DB problems, e.g. getting "File
509 exists" when you try to open a db file. The API for this function was changed
510 at DB release 4.3. */
513 dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg)
516 log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
522 /* Access functions */
524 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
525 /* The API changed for DB 4.1. - and we also starting using the "env" with a
526 specified working dir, to avoid the DBCONFIG file trap. */
528 # define ENV_TO_DB(env) ((DB *)(((EXIM_DB *)env)->app_private))
530 static inline EXIM_DB *
531 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
536 if ( db_env_create(&dbp, 0) != 0
537 || (dbp->set_errcall(dbp, dbfn_bdb_error_callback), 0)
538 || dbp->open(dbp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0
541 if (db_create(&b, dbp, 0) == 0)
543 dbp->app_private = b;
544 if (b->open(b, NULL, CS name, NULL,
545 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
546 flags & O_CREAT ? DB_CREATE
547 : flags & O_RDONLY ? DB_RDONLY
548 : 0, /*XXX is there a writeable if exists option? */
559 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
561 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
563 DB * b = ENV_TO_DB(dbp);
564 return b->get(b, NULL, key, res, 0) == 0;
567 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
569 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
571 DB * b = ENV_TO_DB(dbp);
572 return b->put(b, NULL, key, data, 0);
575 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
577 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
579 DB * b = ENV_TO_DB(dbp);
580 return b->put(b, NULL, key, data, DB_NOOVERWRITE);
583 /* Return values from EXIM_DBPUTB */
585 # define EXIM_DBPUTB_OK 0
586 # define EXIM_DBPUTB_DUP DB_KEYEXIST
590 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
592 DB * b = ENV_TO_DB(dbp);
593 return b->del(b, NULL, key, 0);
596 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
598 static inline EXIM_CURSOR *
599 exim_dbcreate_cursor(EXIM_DB * dbp)
601 DB * b = ENV_TO_DB(dbp);
603 b->cursor(b, NULL, &c, 0);
607 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
609 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
610 EXIM_CURSOR * cursor)
612 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
615 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
617 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
618 { cursor->c_close(cursor); }
622 exim_dbclose__(EXIM_DB * dbp_o)
624 DB_ENV * dbp = dbp_o;
625 DB * b = ENV_TO_DB(dbp);
627 dbp->close(dbp, DB_FORCESYNC);
632 static inline uschar *
633 exim_datum_data_get(EXIM_DATUM * dp)
636 exim_datum_data_set(EXIM_DATUM * dp, void * s)
639 static inline unsigned
640 exim_datum_size_get(EXIM_DATUM * dp)
643 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
646 /* The whole datum structure contains other fields that must be cleared
647 before use, but we don't have to free anything after reading data. */
650 exim_datum_init(EXIM_DATUM * d)
651 { memset(d, 0, sizeof(*d)); }
654 exim_datum_free(EXIM_DATUM * d)
657 # else /* pre- 4.1 */
661 /* Cursor type, for scanning */
662 # define EXIM_CURSOR DBC
664 /* The datum type used for queries */
665 # define EXIM_DATUM DBT
667 /* Some text for messages */
668 # define EXIM_DBTYPE "db (v3/4)"
670 /* Access functions */
672 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
673 static inline EXIM_DB *
674 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
678 return db_create(&dbp, NULL, 0) == 0
679 && ( dbp->set_errcall(dbp, dbfn_bdb_error_callback),
680 dbp->open(dbp, CS name, NULL,
681 flags & O_CREAT ? DB_HASH : DB_UNKNOWN,
682 flags & O_CREAT ? DB_CREATE
683 : flags & O_RDONLY ? DB_RDONLY
690 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
692 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
693 { return dbp->get(dbp, NULL, key, res, 0) == 0; }
695 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
697 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
698 { return dbp->put(dbp, NULL, key, data, 0); }
700 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
702 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
703 { return dbp->put(dbp, NULL, key, data, DB_NOOVERWRITE); }
705 /* Return values from EXIM_DBPUTB */
707 # define EXIM_DBPUTB_OK 0
708 # define EXIM_DBPUTB_DUP DB_KEYEXIST
712 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
713 { return dbp->del(dbp, NULL, key, 0); }
715 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
717 static inline EXIM_CURSOR *
718 exim_dbcreate_cursor(EXIM_DB * dbp)
721 dbp->cursor(dbp, NULL, &c, 0);
725 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
727 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
728 EXIM_CURSOR * cursor)
730 return cursor->c_get(cursor, key, data, first ? DB_FIRST : DB_NEXT) == 0;
733 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
735 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
736 { cursor->c_close(cursor); }
740 exim_dbclose__(EXIM_DB * dbp)
741 { dbp->close(dbp, 0); }
745 static inline uschar *
746 exim_datum_data_get(EXIM_DATUM * dp)
747 { return US dp->dptr; }
749 exim_datum_data_set(EXIM_DATUM * dp, void * s)
752 static inline uschar *
753 exim_datum_size_get(EXIM_DATUM * dp)
754 { return US dp->size; }
756 exim_datum_size_set(EXIM_DATUM * dp, uschar * s)
759 /* The whole datum structure contains other fields that must be cleared
760 before use, but we don't have to free anything after reading data. */
763 exim_datum_init(EXIM_DATUM * d)
764 { memset(d, 0, sizeof(*d)); }
767 exim_datum_free(EXIM_DATUM * d)
773 # else /* DB_VERSION_MAJOR >= 3 */
774 # error Berkeley DB versions earlier than 3 are not supported */
775 # endif /* DB_VERSION_MAJOR */
777 # error Berkeley DB version 1 is no longer supported
778 # endif /* DB_VERSION_STRING */
781 /* all BDB versions */
784 # define EXIM_DB_RLIMIT 150
791 /********************* gdbm interface definitions **********************/
793 #elif defined USE_GDBM
794 /*XXX TODO: exim's locfile not needed */
796 # if defined(USE_TDB) || defined(USE_DB)
797 # error USE_GDBM conflict with alternate definition
804 GDBM_FILE gdbm; /* Database */
805 datum lkey; /* Last key, for scans */
808 /* Cursor type, not used with gdbm: just set up a dummy */
809 # define EXIM_CURSOR int
811 /* The datum type used for queries */
812 # define EXIM_DATUM datum
814 /* Some text for messages */
816 # define EXIM_DBTYPE "gdbm"
818 /* Access functions */
820 /* EXIM_DBOPEN - return pointer to an EXIM_DB, NULL if failed */
821 static inline EXIM_DB *
822 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
825 EXIM_DB * dbp = malloc(sizeof(EXIM_DB)); /*XXX why not exim mem-mgmt? */
828 dbp->lkey.dptr = NULL;
829 dbp->gdbm = gdbm_open(CS name, 0,
830 flags & O_CREAT ? GDBM_WRCREAT
831 : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER
834 if (dbp->gdbm) return dbp;
840 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
842 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
844 *res = gdbm_fetch(dbp->gdbm, *key); /* A struct arg & return! */
845 return res->dptr != NULL;
848 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
850 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
851 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_REPLACE); }
853 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
855 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
856 { return gdbm_store(dbp->gdbm, *key, *data, GDBM_INSERT); }
858 /* Returns from EXIM_DBPUTB */
860 # define EXIM_DBPUTB_OK 0
861 # define EXIM_DBPUTB_DUP 1
865 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
866 { return gdbm_delete(dbp->gdbm, *key); }
868 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
869 static inline EXIM_CURSOR *
870 exim_dbcreate_cursor(EXIM_DB * dbp)
875 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
876 EXIM_CURSOR * cursor)
879 *key = first ? gdbm_firstkey(dbp->gdbm) : gdbm_nextkey(dbp->gdbm, dbp->lkey);
880 if ((s = dbp->lkey.dptr)) free(s);
882 return key->dptr != NULL;
885 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
887 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
892 exim_dbclose__(EXIM_DB * dbp)
895 gdbm_close(dbp->gdbm);
896 if ((s = dbp->lkey.dptr)) free(s);
900 /* Datum access types */
902 static inline uschar *
903 exim_datum_data_get(EXIM_DATUM * dp)
904 { return US dp->dptr; }
906 exim_datum_data_set(EXIM_DATUM * dp, void * s)
909 static inline unsigned
910 exim_datum_size_get(EXIM_DATUM * dp)
911 { return dp->dsize; }
913 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
916 /* There's no clearing required before use, but we have to free the dptr
917 after reading data. */
920 exim_datum_init(EXIM_DATUM * d)
924 exim_datum_free(EXIM_DATUM * d)
927 /* size limit. GDBM is int-max limited, but we want to be less silly */
929 # define EXIM_DB_RLIMIT 150
938 /* If none of USE_DB, USG_GDBM, or USE_TDB are set, the default is the NDBM
939 interface (which seems to be a wrapper for GDBM) */
942 /********************* ndbm interface definitions **********************/
949 /* Cursor type, not used with ndbm: just set up a dummy */
950 # define EXIM_CURSOR int
952 /* The datum type used for queries */
953 # define EXIM_DATUM datum
955 /* Some text for messages */
957 # define EXIM_DBTYPE "ndbm"
959 /* Access functions */
961 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
962 /* Check that the name given is not present. This catches
963 a directory name; otherwise we would create the name.pag and
964 name.dir files in the directory's parent. */
966 static inline EXIM_DB *
967 exim_dbopen__(const uschar * name, const uschar * dirname, int flags,
971 if (!(flags & O_CREAT) || lstat(CCS name, &st) != 0 && errno == ENOENT)
972 return dbm_open(CS name, flags, mode);
973 #ifndef COMPILE_UTILITY
974 debug_printf("%s %d errno %s\n", __FUNCTION__, __LINE__, strerror(errno));
976 errno = (st.st_mode & S_IFMT) == S_IFDIR ? EISDIR : EEXIST;
980 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
982 exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res)
984 *res = dbm_fetch(dbp, *key); /* A struct arg & return! */
985 return res->dptr != NULL;
988 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
990 exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
991 { return dbm_store(dbp, *key, *data, DBM_REPLACE); }
993 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
995 exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data)
996 { return dbm_store(dbp, *key, *data, DBM_INSERT); }
998 /* Returns from EXIM_DBPUTB */
1000 # define EXIM_DBPUTB_OK 0
1001 # define EXIM_DBPUTB_DUP 1
1005 exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key)
1006 { return dbm_delete(dbp, *key); }
1008 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation (null) */
1009 static inline EXIM_CURSOR *
1010 exim_dbcreate_cursor(EXIM_DB * dbp)
1015 exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, BOOL first,
1016 EXIM_CURSOR * cursor)
1018 *key = first ? dbm_firstkey(dbp) : dbm_nextkey(dbp);
1019 return key->dptr != NULL;
1022 /* EXIM_DBDELETE_CURSOR - terminate scanning operation (null). */
1024 exim_dbdelete_cursor(EXIM_CURSOR * cursor)
1029 exim_dbclose__(EXIM_DB * dbp)
1032 /* Datum access types */
1034 static inline uschar *
1035 exim_datum_data_get(EXIM_DATUM * dp)
1036 { return US dp->dptr; }
1038 exim_datum_data_set(EXIM_DATUM * dp, void * s)
1041 static inline unsigned
1042 exim_datum_size_get(EXIM_DATUM * dp)
1043 { return dp->dsize; }
1045 exim_datum_size_set(EXIM_DATUM * dp, unsigned n)
1048 /* There's no clearing required before use, and we don't have to free anything
1049 after reading data. */
1052 exim_datum_init(EXIM_DATUM * d)
1056 exim_datum_free(EXIM_DATUM * d)
1061 # define EXIM_DB_RLIMIT 150
1063 #endif /* !USE_GDBM */
1069 #if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF)
1071 static inline EXIM_DB *
1072 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1075 return exim_dbopen__(name, dirname, flags, mode);
1079 exim_dbclose(EXIM_DB * dbp)
1080 { exim_dbclose__(dbp); }
1082 #else /* exim mainline code */
1084 /* Wrappers for open/close with debug tracing */
1086 extern void debug_printf_indent(const char *, ...);
1087 static inline BOOL is_tainted(const void *);
1089 static inline EXIM_DB *
1090 exim_dbopen(const uschar * name, const uschar * dirname, int flags,
1094 DEBUG(D_hints_lookup)
1095 debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n",
1097 flags == O_RDONLY ? "O_RDONLY"
1098 : flags == O_RDWR ? "O_RDWR"
1099 : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
1101 if (is_tainted(name) || is_tainted(dirname))
1103 log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted");
1107 dbp = exim_dbopen__(name, dirname, flags, mode);
1109 DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp);
1114 exim_dbclose(EXIM_DB * dbp)
1116 DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp);
1117 exim_dbclose__(dbp);
1120 # endif /* defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) */
1122 /********************* End of dbm library definitions **********************/
1125 #endif /* whole file */
1126 /* End of hintsdb.h */