1/*++ 2/* NAME 3/* mkmap_open 3 4/* SUMMARY 5/* create or rewrite database, generic interface 6/* SYNOPSIS 7/* #include <mkmap.h> 8/* 9/* MKMAP *mkmap_open(type, path, open_flags, dict_flags) 10/* char *type; 11/* char *path; 12/* int open_flags; 13/* int dict_flags; 14/* 15/* void mkmap_append(mkmap, key, value, lineno) 16/* MKMAP *mkmap; 17/* char *key; 18/* char *value; 19/* int lineno; 20/* 21/* void mkmap_close(mkmap) 22/* MKMAP *mkmap; 23/* DESCRIPTION 24/* This module implements support for creating Postfix databases. 25/* It is a dict(3) wrapper that adds global locking to dict-level 26/* routines where appropriate. 27/* 28/* mkmap_open() creates or truncates the named database, after 29/* appending the appropriate suffixes to the specified filename. 30/* Before the database is updated, it is locked for exclusive 31/* access, and signal delivery is suspended. 32/* See dict(3) for a description of \fBopen_flags\fR and \fBdict_flags\fR. 33/* All errors are fatal. 34/* 35/* mkmap_append() appends the named (key, value) pair to the 36/* database. Update errors are fatal; duplicate keys are ignored 37/* (but a warning is issued). 38/* \fBlineno\fR is used for diagnostics. 39/* 40/* mkmap_close() closes the database, releases any locks, 41/* and resumes signal delivery. All errors are fatal. 42/* SEE ALSO 43/* sigdelay(3) suspend/resume signal delivery 44/* LICENSE 45/* .ad 46/* .fi 47/* The Secure Mailer license must be distributed with this software. 48/* AUTHOR(S) 49/* Wietse Venema 50/* IBM T.J. Watson Research 51/* P.O. Box 704 52/* Yorktown Heights, NY 10598, USA 53/*--*/ 54 55/* System library. */ 56 57#include <sys_defs.h> 58#include <unistd.h> 59#include <string.h> 60 61/* Utility library. */ 62 63#include <msg.h> 64#include <dict.h> 65#include <dict_db.h> 66#include <dict_cdb.h> 67#include <dict_dbm.h> 68#include <dict_lmdb.h> 69#include <dict_sdbm.h> 70#include <dict_proxy.h> 71#include <dict_fail.h> 72#include <sigdelay.h> 73#include <mymalloc.h> 74 75/* Global library. */ 76 77#include "mkmap.h" 78 79 /* 80 * Information about available database types. Here, we list only those map 81 * types that support "create" operations. 82 * 83 * We use a different table (in dict_open.c) when querying maps. 84 */ 85typedef struct { 86 char *type; 87 MKMAP *(*before_open) (const char *); 88} MKMAP_OPEN_INFO; 89 90static const MKMAP_OPEN_INFO mkmap_types[] = { 91 DICT_TYPE_PROXY, mkmap_proxy_open, 92#ifdef HAS_CDB 93 DICT_TYPE_CDB, mkmap_cdb_open, 94#endif 95#ifdef HAS_SDBM 96 DICT_TYPE_SDBM, mkmap_sdbm_open, 97#endif 98#ifdef HAS_DBM 99 DICT_TYPE_DBM, mkmap_dbm_open, 100#endif 101#ifdef HAS_DB 102 DICT_TYPE_HASH, mkmap_hash_open, 103 DICT_TYPE_BTREE, mkmap_btree_open, 104#endif 105#ifdef HAS_LMDB 106 DICT_TYPE_LMDB, mkmap_lmdb_open, 107#endif 108 DICT_TYPE_FAIL, mkmap_fail_open, 109 0, 110}; 111 112/* mkmap_append - append entry to map */ 113 114#undef mkmap_append 115 116void mkmap_append(MKMAP *mkmap, const char *key, const char *value) 117{ 118 DICT *dict = mkmap->dict; 119 120 if (dict_put(dict, key, value) != 0 && dict->error != 0) 121 msg_fatal("%s:%s: update failed", dict->type, dict->name); 122} 123 124/* mkmap_close - close database */ 125 126void mkmap_close(MKMAP *mkmap) 127{ 128 129 /* 130 * Close the database. 131 */ 132 dict_close(mkmap->dict); 133 134 /* 135 * Do whatever special processing is needed after closing the database, 136 * such as releasing a global exclusive lock on the database file. 137 * Individual Postfix dict modules implement locking only for individual 138 * record operations, because most Postfix applications don't need global 139 * exclusive locks. 140 */ 141 if (mkmap->after_close) 142 mkmap->after_close(mkmap); 143 144 /* 145 * Resume signal delivery. 146 */ 147 if (mkmap->multi_writer == 0) 148 sigresume(); 149 150 /* 151 * Cleanup. 152 */ 153 myfree((char *) mkmap); 154} 155 156/* mkmap_open - create or truncate database */ 157 158MKMAP *mkmap_open(const char *type, const char *path, 159 int open_flags, int dict_flags) 160{ 161 MKMAP *mkmap; 162 const MKMAP_OPEN_INFO *mp; 163 164 /* 165 * Find out what map type to use. 166 */ 167 for (mp = mkmap_types; /* void */ ; mp++) { 168 if (mp->type == 0) 169 msg_fatal("unsupported map type for this operation: %s", type); 170 if (strcmp(type, mp->type) == 0) 171 break; 172 } 173 if (msg_verbose) 174 msg_info("open %s %s", type, path); 175 176 /* 177 * Do whatever before-open initialization is needed, such as acquiring a 178 * global exclusive lock on an existing database file. Individual Postfix 179 * dict modules implement locking only for individual record operations, 180 * because most Postfix applications don't need global exclusive locks. 181 */ 182 mkmap = mp->before_open(path); 183 184 /* 185 * Delay signal delivery, so that we won't leave the database in an 186 * inconsistent state if we can avoid it. 187 */ 188 sigdelay(); 189 190 /* 191 * Truncate the database upon open, and update it. Read-write mode is 192 * needed because the underlying routines read as well as write. We 193 * explicitly clobber lock_fd to trigger a fatal error when a map wants 194 * to unlock the database after individual transactions: that would 195 * result in race condition problems. We clobbber stat_fd as well, 196 * because that, too, is used only for individual-transaction clients. 197 */ 198 mkmap->dict = mkmap->open(path, open_flags, dict_flags); 199 mkmap->dict->lock_fd = -1; /* XXX just in case */ 200 mkmap->dict->stat_fd = -1; /* XXX just in case */ 201 mkmap->dict->flags |= DICT_FLAG_DUP_WARN; 202 mkmap->multi_writer = (mkmap->dict->flags & DICT_FLAG_MULTI_WRITER); 203 204 /* 205 * Do whatever post-open initialization is needed, such as acquiring a 206 * global exclusive lock on a database file that did not exist. 207 * Individual Postfix dict modules implement locking only for individual 208 * record operations, because most Postfix applications don't need global 209 * exclusive locks. 210 */ 211 if (mkmap->after_open) 212 mkmap->after_open(mkmap); 213 214 /* 215 * Resume signal delivery if multi-writer safe. 216 */ 217 if (mkmap->multi_writer) 218 sigresume(); 219 220 return (mkmap); 221} 222