xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/mkmap_db.c (revision c48c605c14fd8622b523d1d6a3f0c0bad133ea89)
1*c48c605cSchristos /*	$NetBSD: mkmap_db.c,v 1.2 2023/12/23 20:30:46 christos Exp $	*/
2059c16a8Schristos 
3059c16a8Schristos /*++
4059c16a8Schristos /* NAME
5059c16a8Schristos /*	mkmap_db 3
6059c16a8Schristos /* SUMMARY
7059c16a8Schristos /*	create or open database, DB style
8059c16a8Schristos /* SYNOPSIS
9059c16a8Schristos /*	#include <dict_db.h>
10059c16a8Schristos /*
11059c16a8Schristos /*	MKMAP	*mkmap_hash_open(path)
12059c16a8Schristos /*	const char *path;
13059c16a8Schristos /*
14059c16a8Schristos /*	MKMAP	*mkmap_btree_open(path)
15059c16a8Schristos /*	const char *path;
16059c16a8Schristos /* DESCRIPTION
17059c16a8Schristos /*	This module implements support for creating DB databases.
18059c16a8Schristos /*
19059c16a8Schristos /*	mkmap_hash_open() and mkmap_btree_open() take a file name,
20059c16a8Schristos /*	append the ".db" suffix, and do whatever initialization is
21059c16a8Schristos /*	required before the Berkeley DB open routine is called.
22059c16a8Schristos /*
23059c16a8Schristos /*	All errors are fatal.
24059c16a8Schristos /* SEE ALSO
25059c16a8Schristos /*	dict_db(3), DB dictionary interface.
26059c16a8Schristos /* LICENSE
27059c16a8Schristos /* .ad
28059c16a8Schristos /* .fi
29059c16a8Schristos /*	The Secure Mailer license must be distributed with this software.
30059c16a8Schristos /* AUTHOR(S)
31059c16a8Schristos /*	Wietse Venema
32059c16a8Schristos /*	IBM T.J. Watson Research
33059c16a8Schristos /*	P.O. Box 704
34059c16a8Schristos /*	Yorktown Heights, NY 10598, USA
35059c16a8Schristos /*
36059c16a8Schristos /*	Wietse Venema
37059c16a8Schristos /*	Google, Inc.
38059c16a8Schristos /*	111 8th Avenue
39059c16a8Schristos /*	New York, NY 10011, USA
40059c16a8Schristos /*--*/
41059c16a8Schristos 
42059c16a8Schristos /* System library. */
43059c16a8Schristos 
44059c16a8Schristos #include <sys_defs.h>
45059c16a8Schristos #include <sys/stat.h>
46059c16a8Schristos #include <unistd.h>
47059c16a8Schristos #include <errno.h>
48059c16a8Schristos 
49059c16a8Schristos /* Utility library. */
50059c16a8Schristos 
51059c16a8Schristos #include <msg.h>
52059c16a8Schristos #include <mymalloc.h>
53059c16a8Schristos #include <stringops.h>
54059c16a8Schristos #include <dict_db.h>
55059c16a8Schristos #include <myflock.h>
56059c16a8Schristos #include <warn_stat.h>
57059c16a8Schristos 
58059c16a8Schristos #ifdef HAS_DB
59059c16a8Schristos #ifdef PATH_DB_H
60059c16a8Schristos #include PATH_DB_H
61059c16a8Schristos #else
62059c16a8Schristos #include <db.h>
63059c16a8Schristos #endif
64059c16a8Schristos 
65059c16a8Schristos typedef struct MKMAP_DB {
66059c16a8Schristos     MKMAP   mkmap;			/* parent class */
67059c16a8Schristos     char   *lock_file;			/* path name */
68059c16a8Schristos     int     lock_fd;			/* -1 or open locked file */
69059c16a8Schristos } MKMAP_DB;
70059c16a8Schristos 
71059c16a8Schristos /* mkmap_db_after_close - clean up after closing database */
72059c16a8Schristos 
mkmap_db_after_close(MKMAP * mp)73059c16a8Schristos static void mkmap_db_after_close(MKMAP *mp)
74059c16a8Schristos {
75059c16a8Schristos     MKMAP_DB *mkmap = (MKMAP_DB *) mp;
76059c16a8Schristos 
77059c16a8Schristos     if (mkmap->lock_fd >= 0 && close(mkmap->lock_fd) < 0)
78059c16a8Schristos 	msg_warn("close %s: %m", mkmap->lock_file);
79059c16a8Schristos     myfree(mkmap->lock_file);
80059c16a8Schristos }
81059c16a8Schristos 
82059c16a8Schristos /* mkmap_db_after_open - lock newly created database */
83059c16a8Schristos 
mkmap_db_after_open(MKMAP * mp)84059c16a8Schristos static void mkmap_db_after_open(MKMAP *mp)
85059c16a8Schristos {
86059c16a8Schristos     MKMAP_DB *mkmap = (MKMAP_DB *) mp;
87059c16a8Schristos 
88059c16a8Schristos     if (mkmap->lock_fd < 0) {
89059c16a8Schristos 	if ((mkmap->lock_fd = open(mkmap->lock_file, O_RDWR, 0644)) < 0)
90059c16a8Schristos 	    msg_fatal("open lockfile %s: %m", mkmap->lock_file);
91059c16a8Schristos 	if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
92059c16a8Schristos 	    msg_fatal("lock %s: %m", mkmap->lock_file);
93059c16a8Schristos     }
94059c16a8Schristos }
95059c16a8Schristos 
96059c16a8Schristos /* mkmap_db_before_open - lock existing database */
97059c16a8Schristos 
mkmap_db_before_open(const char * path,DICT * (* db_open)(const char *,int,int))98059c16a8Schristos static MKMAP *mkmap_db_before_open(const char *path,
99059c16a8Schristos 			          DICT *(*db_open) (const char *, int, int))
100059c16a8Schristos {
101059c16a8Schristos     MKMAP_DB *mkmap = (MKMAP_DB *) mymalloc(sizeof(*mkmap));
102059c16a8Schristos     struct stat st;
103059c16a8Schristos 
104059c16a8Schristos     /*
105059c16a8Schristos      * Assumes that  dict_db_cache_size = var_db_create_buf was done in the
106059c16a8Schristos      * caller, because this code has no access to Postfix variables.
107059c16a8Schristos      */
108059c16a8Schristos 
109059c16a8Schristos     /*
110059c16a8Schristos      * Fill in the generic members.
111059c16a8Schristos      */
112059c16a8Schristos     mkmap->lock_file = concatenate(path, ".db", (char *) 0);
113059c16a8Schristos     mkmap->mkmap.open = db_open;
114059c16a8Schristos     mkmap->mkmap.after_open = mkmap_db_after_open;
115059c16a8Schristos     mkmap->mkmap.after_close = mkmap_db_after_close;
116059c16a8Schristos 
117059c16a8Schristos     /*
118059c16a8Schristos      * Unfortunately, not all systems that might support db databases do
119059c16a8Schristos      * support locking on open(), so we open the file before updating it.
120059c16a8Schristos      *
121059c16a8Schristos      * XXX Berkeley DB 4.1 refuses to open a zero-length file. This means we can
122059c16a8Schristos      * open and lock only an existing file, and that we must not truncate it.
123059c16a8Schristos      */
124059c16a8Schristos     if ((mkmap->lock_fd = open(mkmap->lock_file, O_RDWR, 0644)) < 0) {
125059c16a8Schristos 	if (errno != ENOENT)
126059c16a8Schristos 	    msg_fatal("open %s: %m", mkmap->lock_file);
127059c16a8Schristos     }
128059c16a8Schristos 
129059c16a8Schristos     /*
130059c16a8Schristos      * Get an exclusive lock - we're going to change the database so we can't
131059c16a8Schristos      * have any spectators.
132059c16a8Schristos      *
133059c16a8Schristos      * XXX Horror. Berkeley DB 4.1 refuses to open a zero-length file. This
134059c16a8Schristos      * means that we must examine the size while the file is locked, and that
135059c16a8Schristos      * we must unlink a zero-length file while it is locked. Avoid a race
136059c16a8Schristos      * condition where two processes try to open the same zero-length file
137059c16a8Schristos      * and where the second process ends up deleting the wrong file.
138059c16a8Schristos      */
139059c16a8Schristos     else {
140059c16a8Schristos 	if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
141059c16a8Schristos 	    msg_fatal("lock %s: %m", mkmap->lock_file);
142059c16a8Schristos 	if (fstat(mkmap->lock_fd, &st) < 0)
143059c16a8Schristos 	    msg_fatal("fstat %s: %m", mkmap->lock_file);
144059c16a8Schristos 	if (st.st_size == 0) {
145059c16a8Schristos 	    if (st.st_nlink > 0) {
146059c16a8Schristos 		if (unlink(mkmap->lock_file) < 0)
147059c16a8Schristos 		    msg_fatal("cannot remove zero-length database file %s: %m",
148059c16a8Schristos 			      mkmap->lock_file);
149059c16a8Schristos 		msg_warn("removing zero-length database file: %s",
150059c16a8Schristos 			 mkmap->lock_file);
151059c16a8Schristos 	    }
152059c16a8Schristos 	    close(mkmap->lock_fd);
153059c16a8Schristos 	    mkmap->lock_fd = -1;
154059c16a8Schristos 	}
155059c16a8Schristos     }
156059c16a8Schristos 
157059c16a8Schristos     return (&mkmap->mkmap);
158059c16a8Schristos }
159059c16a8Schristos 
160059c16a8Schristos /* mkmap_hash_open - create or open hashed DB file */
161059c16a8Schristos 
mkmap_hash_open(const char * path)162059c16a8Schristos MKMAP  *mkmap_hash_open(const char *path)
163059c16a8Schristos {
164059c16a8Schristos     return (mkmap_db_before_open(path, dict_hash_open));
165059c16a8Schristos }
166059c16a8Schristos 
167059c16a8Schristos /* mkmap_btree_open - create or open btree DB file */
168059c16a8Schristos 
mkmap_btree_open(const char * path)169059c16a8Schristos MKMAP  *mkmap_btree_open(const char *path)
170059c16a8Schristos {
171059c16a8Schristos     return (mkmap_db_before_open(path, dict_btree_open));
172059c16a8Schristos }
173059c16a8Schristos 
174059c16a8Schristos #endif
175