Postfix3.3.1
mkmap_open.c
[詳解]
1 /*++
2 /* NAME
3 /* mkmap_open 3
4 /* SUMMARY
5 /* create or rewrite database, generic interface
6 /* SYNOPSIS
7 /* #include <mkmap.h>
8 /*
9 /* typedef struct MKMAP {
10 /* DICT_OPEN_FN open; /* dict_xx_open() */
11 /* DICT *dict; /* dict_xx_open() result */
12 /* void (*after_open) (struct MKMAP *); /* may be null */
13 /* void (*after_close) (struct MKMAP *); /* may be null */
14 /* int multi_writer; /* multi-writer safe */
15 /* } MKMAP;
16 /*
17 /* MKMAP *mkmap_open(type, path, open_flags, dict_flags)
18 /* char *type;
19 /* char *path;
20 /* int open_flags;
21 /* int dict_flags;
22 /*
23 /* void mkmap_append(mkmap, key, value, lineno)
24 /* MKMAP *mkmap;
25 /* char *key;
26 /* char *value;
27 /* int lineno;
28 /*
29 /* void mkmap_close(mkmap)
30 /* MKMAP *mkmap;
31 /*
32 /* typedef MKMAP *(*MKMAP_OPEN_FN) (const char *);
33 /* typedef MKMAP_OPEN_FN *(*MKMAP_OPEN_EXTEND_FN) (const char *);
34 /*
35 /* void mkmap_open_register(type, open_fn)
36 /* const char *type;
37 /* MKMAP_OPEN_FN open_fn;
38 /*
39 /* MKMAP_OPEN_EXTEND_FN mkmap_open_extend(call_back)
40 /* MKMAP_OPEN_EXTEND_FN call_back;
41 /* DESCRIPTION
42 /* This module implements support for creating Postfix databases.
43 /* It is a dict(3) wrapper that adds global locking to dict-level
44 /* routines where appropriate.
45 /*
46 /* mkmap_open() creates or truncates the named database, after
47 /* appending the appropriate suffixes to the specified filename.
48 /* Before the database is updated, it is locked for exclusive
49 /* access, and signal delivery is suspended.
50 /* See dict(3) for a description of \fBopen_flags\fR and
51 /* \fBdict_flags\fR. All errors are fatal.
52 /*
53 /* mkmap_append() appends the named (key, value) pair to the
54 /* database. Update errors are fatal; duplicate keys are ignored
55 /* (but a warning is issued).
56 /* \fBlineno\fR is used for diagnostics.
57 /*
58 /* mkmap_close() closes the database, releases any locks,
59 /* and resumes signal delivery. All errors are fatal.
60 /*
61 /* mkmap_open_register() adds support for a new database type.
62 /*
63 /* mkmap_open_extend() registers a call-back function that looks
64 /* up the mkmap open() function for a database type that is not
65 /* registered, or null in case of error. The result value is the
66 /* last previously-registered call-back or null. A mkmap open()
67 /* function is cached after it is looked up through this extension
68 /* mechanism.
69 /* SEE ALSO
70 /* sigdelay(3) suspend/resume signal delivery
71 /* LICENSE
72 /* .ad
73 /* .fi
74 /* The Secure Mailer license must be distributed with this software.
75 /* AUTHOR(S)
76 /* Wietse Venema
77 /* IBM T.J. Watson Research
78 /* P.O. Box 704
79 /* Yorktown Heights, NY 10598, USA
80 /*--*/
81 
82 /* System library. */
83 
84 #include <sys_defs.h>
85 #include <unistd.h>
86 #include <string.h>
87 
88 /* Utility library. */
89 
90 #include <msg.h>
91 #include <htable.h>
92 #include <dict.h>
93 #include <dict_db.h>
94 #include <dict_cdb.h>
95 #include <dict_dbm.h>
96 #include <dict_lmdb.h>
97 #include <dict_sdbm.h>
98 #include <dict_proxy.h>
99 #include <dict_fail.h>
100 #include <sigdelay.h>
101 #include <mymalloc.h>
102 #include <stringops.h>
103 
104 /* Global library. */
105 
106 #include "mkmap.h"
107 
108  /*
109  * Information about available database types. Here, we list only those map
110  * types that support "bulk create" operations.
111  *
112  * We use a different table (in dict_open.c and mail_dict.c) when querying maps
113  * or when making incremental updates.
114  */
115 typedef struct {
116  const char *type;
119 
120 static const MKMAP_OPEN_INFO mkmap_open_info[] = {
121 #ifndef USE_DYNAMIC_MAPS
122 #ifdef HAS_CDB
124 #endif
125 #ifdef HAS_SDBM
127 #endif
128 #ifdef HAS_LMDB
130 #endif
131 #endif /* !USE_DYNAMIC_MAPS */
132 #ifdef HAS_DBM
134 #endif
135 #ifdef HAS_DB
138 #endif
140  0,
141 };
142 
143 static HTABLE *mkmap_open_hash;
144 
145 static MKMAP_OPEN_EXTEND_FN mkmap_open_extend_hook = 0;
146 
147 /* mkmap_open_init - one-off initialization */
148 
149 static void mkmap_open_init(void)
150 {
151  static const char myname[] = "mkmap_open_init";
152  const MKMAP_OPEN_INFO *mp;
153 
154  if (mkmap_open_hash != 0)
155  msg_panic("%s: multiple initialization", myname);
156  mkmap_open_hash = htable_create(10);
157 
158  for (mp = mkmap_open_info; mp->type; mp++)
159  htable_enter(mkmap_open_hash, mp->type, (void *) mp);
160 }
161 
162 /* mkmap_open_register - register dictionary type */
163 
164 void mkmap_open_register(const char *type, MKMAP_OPEN_FN open_fn)
165 {
166  static const char myname[] = "mkmap_open_register";
167  MKMAP_OPEN_INFO *mp;
168  HTABLE_INFO *ht;
169 
170  if (mkmap_open_hash == 0)
171  mkmap_open_init();
172  if (htable_find(mkmap_open_hash, type))
173  msg_panic("%s: database type exists: %s", myname, type);
174  mp = (MKMAP_OPEN_INFO *) mymalloc(sizeof(*mp));
175  mp->before_open = open_fn;
176  ht = htable_enter(mkmap_open_hash, type, (void *) mp);
177  mp->type = ht->key;
178 }
179 
180 /* mkmap_open_extend - register alternate lookup function */
181 
183 {
184  MKMAP_OPEN_EXTEND_FN old_cb;
185 
186  old_cb = mkmap_open_extend_hook;
187  mkmap_open_extend_hook = new_cb;
188  return (old_cb);
189 }
190 
191 /* mkmap_append - append entry to map */
192 
193 #undef mkmap_append
194 
195 void mkmap_append(MKMAP *mkmap, const char *key, const char *value)
196 {
197  DICT *dict = mkmap->dict;
198 
199  if (dict_put(dict, key, value) != 0 && dict->error != 0)
200  msg_fatal("%s:%s: update failed", dict->type, dict->name);
201 }
202 
203 /* mkmap_close - close database */
204 
205 void mkmap_close(MKMAP *mkmap)
206 {
207 
208  /*
209  * Close the database.
210  */
211  dict_close(mkmap->dict);
212 
213  /*
214  * Do whatever special processing is needed after closing the database,
215  * such as releasing a global exclusive lock on the database file.
216  * Individual Postfix dict modules implement locking only for individual
217  * record operations, because most Postfix applications don't need global
218  * exclusive locks.
219  */
220  if (mkmap->after_close)
221  mkmap->after_close(mkmap);
222 
223  /*
224  * Resume signal delivery.
225  */
226  if (mkmap->multi_writer == 0)
227  sigresume();
228 
229  /*
230  * Cleanup.
231  */
232  myfree((void *) mkmap);
233 }
234 
235 /* mkmap_open - create or truncate database */
236 
237 MKMAP *mkmap_open(const char *type, const char *path,
238  int open_flags, int dict_flags)
239 {
240  MKMAP *mkmap;
241  const MKMAP_OPEN_INFO *mp;
242  MKMAP_OPEN_FN open_fn;
243 
244  /*
245  * Find out what map type to use.
246  */
247  if (mkmap_open_hash == 0)
248  mkmap_open_init();
249  if ((mp = (MKMAP_OPEN_INFO *) htable_find(mkmap_open_hash, type)) == 0) {
250  if (mkmap_open_extend_hook != 0 &&
251  (open_fn = mkmap_open_extend_hook(type)) != 0) {
252  mkmap_open_register(type, open_fn);
253  mp = (MKMAP_OPEN_INFO *) htable_find(mkmap_open_hash, type);
254  }
255  if (mp == 0)
256  msg_fatal("unsupported map type for this operation: %s", type);
257  }
258  if (msg_verbose)
259  msg_info("open %s %s", type, path);
260 
261  /*
262  * Do whatever before-open initialization is needed, such as acquiring a
263  * global exclusive lock on an existing database file. Individual Postfix
264  * dict modules implement locking only for individual record operations,
265  * because most Postfix applications don't need global exclusive locks.
266  */
267  mkmap = mp->before_open(path);
268 
269  /*
270  * Delay signal delivery, so that we won't leave the database in an
271  * inconsistent state if we can avoid it.
272  */
273  sigdelay();
274 
275  /*
276  * Truncate the database upon open, and update it. Read-write mode is
277  * needed because the underlying routines read as well as write. We
278  * explicitly clobber lock_fd to trigger a fatal error when a map wants
279  * to unlock the database after individual transactions: that would
280  * result in race condition problems. We clobbber stat_fd as well,
281  * because that, too, is used only for individual-transaction clients.
282  */
283  mkmap->dict = mkmap->open(path, open_flags, dict_flags);
284  mkmap->dict->lock_fd = -1; /* XXX just in case */
285  mkmap->dict->stat_fd = -1; /* XXX just in case */
286  mkmap->dict->flags |= DICT_FLAG_DUP_WARN;
287  mkmap->multi_writer = (mkmap->dict->flags & DICT_FLAG_MULTI_WRITER);
288 
289  /*
290  * Do whatever post-open initialization is needed, such as acquiring a
291  * global exclusive lock on a database file that did not exist.
292  * Individual Postfix dict modules implement locking only for individual
293  * record operations, because most Postfix applications don't need global
294  * exclusive locks.
295  */
296  if (mkmap->after_open)
297  mkmap->after_open(mkmap);
298 
299  /*
300  * Wrap the dictionary for UTF-8 syntax checks and casefolding.
301  */
302  if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
304  mkmap->dict = dict_utf8_activate(mkmap->dict);
305 
306  /*
307  * Resume signal delivery if multi-writer safe.
308  */
309  if (mkmap->multi_writer)
310  sigresume();
311 
312  return (mkmap);
313 }
int msg_verbose
Definition: msg.c:177
void myfree(void *ptr)
Definition: mymalloc.c:207
#define DICT_NEED_UTF8_ACTIVATION(enable, flags)
Definition: dict.h:171
#define dict_put(dp, key, val)
Definition: dict.h:237
MKMAP * mkmap_sdbm_open(const char *)
MKMAP_OPEN_EXTEND_FN mkmap_open_extend(MKMAP_OPEN_EXTEND_FN new_cb)
Definition: mkmap_open.c:182
void mkmap_append(MKMAP *mkmap, const char *key, const char *value)
Definition: mkmap_open.c:195
void(* after_open)(struct MKMAP *)
Definition: mkmap.h:28
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
void(* after_close)(struct MKMAP *)
Definition: mkmap.h:29
char * name
Definition: dict.h:80
int flags
Definition: dict.h:81
void sigresume(void)
Definition: sigdelay.c:67
MKMAP * mkmap_lmdb_open(const char *)
void sigdelay(void)
Definition: sigdelay.c:78
#define DICT_FLAG_MULTI_WRITER
Definition: dict.h:129
Definition: htable.h:25
#define DICT_TYPE_FAIL
Definition: dict_fail.h:22
int multi_writer
Definition: mkmap.h:30
#define DICT_TYPE_LMDB
Definition: dict_lmdb.h:22
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
Definition: dict.h:78
char * type
Definition: dict.h:79
void mkmap_open_register(const char *type, MKMAP_OPEN_FN open_fn)
Definition: mkmap_open.c:164
MKMAP * mkmap_btree_open(const char *)
MKMAP * mkmap_cdb_open(const char *)
MKMAP_OPEN_FN before_open
Definition: mkmap_open.c:117
int stat_fd
Definition: dict.h:90
MKMAP * mkmap_dbm_open(const char *)
#define DICT_TYPE_SDBM
Definition: dict_sdbm.h:22
int lock_fd
Definition: dict.h:89
char * key
Definition: htable.h:17
void * htable_find(HTABLE *table, const char *key)
Definition: htable.c:227
int error
Definition: dict.h:94
#define DICT_FLAG_DUP_WARN
Definition: dict.h:110
MKMAP_OPEN_FN(* MKMAP_OPEN_EXTEND_FN)(const char *)
Definition: mkmap.h:49
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
const char * type
Definition: mkmap_open.c:116
Definition: mkmap.h:25
#define DICT_TYPE_HASH
Definition: dict_db.h:22
#define DICT_TYPE_BTREE
Definition: dict_db.h:23
MKMAP * mkmap_open(const char *type, const char *path, int open_flags, int dict_flags)
Definition: mkmap_open.c:237
#define DICT_TYPE_DBM
Definition: dict_dbm.h:22
MKMAP * mkmap_fail_open(const char *)
Definition: mkmap_fail.c:45
MKMAP *(* MKMAP_OPEN_FN)(const char *)
Definition: mkmap.h:48
DICT * dict_utf8_activate(DICT *)
Definition: dict_utf8.c:248
int util_utf8_enable
Definition: printable.c:47
MKMAP * mkmap_hash_open(const char *)
struct DICT * dict
Definition: mkmap.h:27
DICT_OPEN_FN open
Definition: mkmap.h:26
#define DICT_TYPE_CDB
Definition: dict_cdb.h:22
void mkmap_close(MKMAP *mkmap)
Definition: mkmap_open.c:205
#define DICT_FLAG_UTF8_ACTIVE
Definition: dict.h:131
#define dict_close(dp)
Definition: dict.h:240
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199