1 /* $NetBSD: mkmap_open.c,v 1.2 2023/12/23 20:30:46 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* mkmap_open 3
6 /* SUMMARY
7 /* create or rewrite database, generic interface
8 /* SYNOPSIS
9 /* #include <mkmap.h>
10 /*
11 /* typedef struct MKMAP {
12 /* struct DICT *(*open) (const char *, int, int); /* dict_xx_open() */
13 /* struct DICT *dict; /* dict_xx_open() result */
14 /* void (*after_open) (struct MKMAP *); /* may be null */
15 /* void (*after_close) (struct MKMAP *); /* may be null */
16 /* int multi_writer; /* multi-writer safe */
17 /* } MKMAP;
18 /*
19 /* MKMAP *mkmap_open(type, path, open_flags, dict_flags)
20 /* char *type;
21 /* char *path;
22 /* int open_flags;
23 /* int dict_flags;
24 /*
25 /* void mkmap_append(mkmap, key, value, lineno)
26 /* MKMAP *mkmap;
27 /* char *key;
28 /* char *value;
29 /* int lineno;
30 /*
31 /* void mkmap_close(mkmap)
32 /* MKMAP *mkmap;
33 /* DESCRIPTION
34 /* This module implements support for creating Postfix databases.
35 /* It is a dict(3) wrapper that adds global locking to dict-level
36 /* routines where appropriate.
37 /*
38 /* mkmap_open() creates or truncates the named database, after
39 /* appending the appropriate suffixes to the specified filename.
40 /* Before the database is updated, it is locked for exclusive
41 /* access, and signal delivery is suspended.
42 /* See dict(3) for a description of \fBopen_flags\fR and
43 /* \fBdict_flags\fR. All errors are fatal.
44 /*
45 /* mkmap_append() appends the named (key, value) pair to the
46 /* database. Update errors are fatal; duplicate keys are ignored
47 /* (but a warning is issued).
48 /* \fBlineno\fR is used for diagnostics.
49 /*
50 /* mkmap_close() closes the database, releases any locks,
51 /* and resumes signal delivery. All errors are fatal.
52 /* SEE ALSO
53 /* sigdelay(3) suspend/resume signal delivery
54 /* LICENSE
55 /* .ad
56 /* .fi
57 /* The Secure Mailer license must be distributed with this software.
58 /* AUTHOR(S)
59 /* Wietse Venema
60 /* IBM T.J. Watson Research
61 /* P.O. Box 704
62 /* Yorktown Heights, NY 10598, USA
63 /*
64 /* Wietse Venema
65 /* Google, Inc.
66 /* 111 8th Avenue
67 /* New York, NY 10011, USA
68 /*--*/
69
70 /* System library. */
71
72 #include <sys_defs.h>
73 #include <unistd.h>
74 #include <string.h>
75
76 /* Utility library. */
77
78 #include <msg.h>
79 #include <dict.h>
80 #include <sigdelay.h>
81 #include <mymalloc.h>
82 #include <stringops.h>
83 #include <mkmap.h>
84
85 /* mkmap_close - close database */
86
mkmap_close(MKMAP * mkmap)87 void mkmap_close(MKMAP *mkmap)
88 {
89
90 /*
91 * Close the database.
92 */
93 dict_close(mkmap->dict);
94
95 /*
96 * Do whatever special processing is needed after closing the database,
97 * such as releasing a global exclusive lock on the database file.
98 * Individual Postfix dict modules implement locking only for individual
99 * record operations, because most Postfix applications don't need global
100 * exclusive locks.
101 */
102 if (mkmap->after_close)
103 mkmap->after_close(mkmap);
104
105 /*
106 * Resume signal delivery.
107 */
108 if (mkmap->multi_writer == 0)
109 sigresume();
110
111 /*
112 * Cleanup.
113 */
114 myfree((void *) mkmap);
115 }
116
117 /* mkmap_open - create or truncate database */
118
mkmap_open(const char * type,const char * path,int open_flags,int dict_flags)119 MKMAP *mkmap_open(const char *type, const char *path,
120 int open_flags, int dict_flags)
121 {
122 MKMAP *mkmap;
123 const DICT_OPEN_INFO *dp;
124
125 /*
126 * Find out what map type to use.
127 */
128 if ((dp = dict_open_lookup(type)) == 0)
129 msg_fatal("unsupported map type: %s", type);
130 if (dp->mkmap_fn == 0)
131 msg_fatal("no 'map create' support for this type: %s", type);
132 if (msg_verbose)
133 msg_info("open %s %s", type, path);
134
135 /*
136 * Do whatever before-open initialization is needed, such as acquiring a
137 * global exclusive lock on an existing database file. Individual Postfix
138 * dict modules implement locking only for individual record operations,
139 * because most Postfix applications don't need global exclusive locks.
140 */
141 mkmap = dp->mkmap_fn(path);
142
143 /*
144 * Delay signal delivery, so that we won't leave the database in an
145 * inconsistent state if we can avoid it.
146 */
147 sigdelay();
148
149 /*
150 * Truncate the database upon open, and update it. Read-write mode is
151 * needed because the underlying routines read as well as write. We
152 * explicitly clobber lock_fd to trigger a fatal error when a map wants
153 * to unlock the database after individual transactions: that would
154 * result in race condition problems. We clobbber stat_fd as well,
155 * because that, too, is used only for individual-transaction clients.
156 */
157 mkmap->dict = mkmap->open(path, open_flags, dict_flags);
158 mkmap->dict->lock_fd = -1; /* XXX just in case */
159 mkmap->dict->stat_fd = -1; /* XXX just in case */
160 mkmap->dict->flags |= DICT_FLAG_DUP_WARN;
161 mkmap->multi_writer = (mkmap->dict->flags & DICT_FLAG_MULTI_WRITER);
162
163 /*
164 * Do whatever post-open initialization is needed, such as acquiring a
165 * global exclusive lock on a database file that did not exist.
166 * Individual Postfix dict modules implement locking only for individual
167 * record operations, because most Postfix applications don't need global
168 * exclusive locks.
169 */
170 if (mkmap->after_open)
171 mkmap->after_open(mkmap);
172
173 /*
174 * Wrap the dictionary for UTF-8 syntax checks and casefolding.
175 */
176 if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
177 && DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags))
178 mkmap->dict = dict_utf8_activate(mkmap->dict);
179
180 /*
181 * Resume signal delivery if multi-writer safe.
182 */
183 if (mkmap->multi_writer)
184 sigresume();
185
186 return (mkmap);
187 }
188