xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/mkmap_open.c (revision c48c605c14fd8622b523d1d6a3f0c0bad133ea89)
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