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 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 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