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_sdbm.h> 69#include <dict_proxy.h> 70#include <dict_fail.h> 71#include <sigdelay.h> 72#include <mymalloc.h> 73 74/* Global library. */ 75 76#include "mkmap.h" 77 78 /* 79 * Information about available database types. Here, we list only those map 80 * types that support "create" operations. 81 * 82 * We use a different table (in dict_open.c) when querying maps. 83 */ 84typedef struct { 85 char *type; 86 MKMAP *(*before_open) (const char *); 87} MKMAP_OPEN_INFO; 88 89static const MKMAP_OPEN_INFO mkmap_types[] = { 90 DICT_TYPE_PROXY, mkmap_proxy_open, 91#ifdef HAS_CDB 92 DICT_TYPE_CDB, mkmap_cdb_open, 93#endif 94#ifdef HAS_SDBM 95 DICT_TYPE_SDBM, mkmap_sdbm_open, 96#endif 97#ifdef HAS_DBM 98 DICT_TYPE_DBM, mkmap_dbm_open, 99#endif 100#ifdef HAS_DB 101 DICT_TYPE_HASH, mkmap_hash_open, 102 DICT_TYPE_BTREE, mkmap_btree_open, 103#endif 104 DICT_TYPE_FAIL, mkmap_fail_open, 105 0, 106}; 107 108/* mkmap_append - append entry to map */ 109 110#undef mkmap_append 111 112void mkmap_append(MKMAP *mkmap, const char *key, const char *value) 113{ 114 DICT *dict = mkmap->dict; 115 116 if (dict_put(dict, key, value) != 0 && dict->error != 0) 117 msg_fatal("%s:%s: update failed", dict->type, dict->name); 118} 119 120/* mkmap_close - close database */ 121 122void mkmap_close(MKMAP *mkmap) 123{ 124 125 /* 126 * Close the database. 127 */ 128 dict_close(mkmap->dict); 129 130 /* 131 * Do whatever special processing is needed after closing the database, 132 * such as releasing a global exclusive lock on the database file. 133 * Individual Postfix dict modules implement locking only for individual 134 * record operations, because most Postfix applications don't need global 135 * exclusive locks. 136 */ 137 if (mkmap->after_close) 138 mkmap->after_close(mkmap); 139 140 /* 141 * Resume signal delivery. 142 */ 143 sigresume(); 144 145 /* 146 * Cleanup. 147 */ 148 myfree((char *) mkmap); 149} 150 151/* mkmap_open - create or truncate database */ 152 153MKMAP *mkmap_open(const char *type, const char *path, 154 int open_flags, int dict_flags) 155{ 156 MKMAP *mkmap; 157 const MKMAP_OPEN_INFO *mp; 158 159 /* 160 * Find out what map type to use. 161 */ 162 for (mp = mkmap_types; /* void */ ; mp++) { 163 if (mp->type == 0) 164 msg_fatal("unsupported map type: %s", type); 165 if (strcmp(type, mp->type) == 0) 166 break; 167 } 168 if (msg_verbose) 169 msg_info("open %s %s", type, path); 170 171 /* 172 * Do whatever before-open initialization is needed, such as acquiring a 173 * global exclusive lock on an existing database file. Individual Postfix 174 * dict modules implement locking only for individual record operations, 175 * because most Postfix applications don't need global exclusive locks. 176 */ 177 mkmap = mp->before_open(path); 178 179 /* 180 * Delay signal delivery, so that we won't leave the database in an 181 * inconsistent state if we can avoid it. 182 */ 183 sigdelay(); 184 185 /* 186 * Truncate the database upon open, and update it. Read-write mode is 187 * needed because the underlying routines read as well as write. 188 */ 189 mkmap->dict = mkmap->open(path, open_flags, dict_flags); 190 mkmap->dict->lock_fd = -1; /* XXX just in case */ 191 mkmap->dict->stat_fd = -1; /* XXX just in case */ 192 mkmap->dict->flags |= DICT_FLAG_DUP_WARN; 193 194 /* 195 * Do whatever post-open initialization is needed, such as acquiring a 196 * global exclusive lock on a database file that did not exist. 197 * Individual Postfix dict modules implement locking only for individual 198 * record operations, because most Postfix applications don't need global 199 * exclusive locks. 200 */ 201 if (mkmap->after_open) 202 mkmap->after_open(mkmap); 203 204 return (mkmap); 205} 206