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