Postfix3.3.1
mkmap_db.c
[詳解]
1 /*++
2 /* NAME
3 /* mkmap_db 3
4 /* SUMMARY
5 /* create or open database, DB style
6 /* SYNOPSIS
7 /* #include <mkmap.h>
8 /*
9 /* MKMAP *mkmap_hash_open(path)
10 /* const char *path;
11 /*
12 /* MKMAP *mkmap_btree_open(path)
13 /* const char *path;
14 /* DESCRIPTION
15 /* This module implements support for creating DB databases.
16 /*
17 /* mkmap_hash_open() and mkmap_btree_open() take a file name,
18 /* append the ".db" suffix, and do whatever initialization is
19 /* required before the Berkeley DB open routine is called.
20 /*
21 /* All errors are fatal.
22 /* SEE ALSO
23 /* dict_db(3), DB dictionary interface.
24 /* LICENSE
25 /* .ad
26 /* .fi
27 /* The Secure Mailer license must be distributed with this software.
28 /* AUTHOR(S)
29 /* Wietse Venema
30 /* IBM T.J. Watson Research
31 /* P.O. Box 704
32 /* Yorktown Heights, NY 10598, USA
33 /*--*/
34 
35 /* System library. */
36 
37 #include <sys_defs.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <errno.h>
41 
42 /* Utility library. */
43 
44 #include <msg.h>
45 #include <mymalloc.h>
46 #include <stringops.h>
47 #include <dict.h>
48 #include <dict_db.h>
49 #include <myflock.h>
50 #include <warn_stat.h>
51 
52 /* Global library. */
53 
54 #include <mail_params.h>
55 
56 /* Application-specific. */
57 
58 #include "mkmap.h"
59 
60 #ifdef HAS_DB
61 #ifdef PATH_DB_H
62 #include PATH_DB_H
63 #else
64 #include <db.h>
65 #endif
66 
67 typedef struct MKMAP_DB {
68  MKMAP mkmap; /* parent class */
69  char *lock_file; /* path name */
70  int lock_fd; /* -1 or open locked file */
71 } MKMAP_DB;
72 
73 /* mkmap_db_after_close - clean up after closing database */
74 
75 static void mkmap_db_after_close(MKMAP *mp)
76 {
77  MKMAP_DB *mkmap = (MKMAP_DB *) mp;
78 
79  if (mkmap->lock_fd >= 0 && close(mkmap->lock_fd) < 0)
80  msg_warn("close %s: %m", mkmap->lock_file);
81  myfree(mkmap->lock_file);
82 }
83 
84 /* mkmap_db_after_open - lock newly created database */
85 
86 static void mkmap_db_after_open(MKMAP *mp)
87 {
88  MKMAP_DB *mkmap = (MKMAP_DB *) mp;
89 
90  if (mkmap->lock_fd < 0) {
91  if ((mkmap->lock_fd = open(mkmap->lock_file, O_RDWR, 0644)) < 0)
92  msg_fatal("open lockfile %s: %m", mkmap->lock_file);
93  if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
94  msg_fatal("lock %s: %m", mkmap->lock_file);
95  }
96 }
97 
98 /* mkmap_db_before_open - lock existing database */
99 
100 static MKMAP *mkmap_db_before_open(const char *path,
101  DICT *(*db_open) (const char *, int, int))
102 {
103  MKMAP_DB *mkmap = (MKMAP_DB *) mymalloc(sizeof(*mkmap));
104  struct stat st;
105 
106  /*
107  * Override the default per-table cache size for map (re)builds.
108  *
109  * db_cache_size" is defined in util/dict_db.c and defaults to 128kB, which
110  * works well for the lookup code.
111  *
112  * We use a larger per-table cache when building ".db" files. For "hash"
113  * files performance degrades rapidly unless the memory pool is O(file
114  * size).
115  *
116  * For "btree" files performance is good with sorted input even for small
117  * memory pools, but with random input degrades rapidly unless the memory
118  * pool is O(file size).
119  *
120  * XXX This should be specified via the DICT interface so that the buffer
121  * size becomes an object property, instead of being specified by poking
122  * a global variable so that it becomes a class property.
123  */
125 
126  /*
127  * Fill in the generic members.
128  */
129  mkmap->lock_file = concatenate(path, ".db", (char *) 0);
130  mkmap->mkmap.open = db_open;
131  mkmap->mkmap.after_open = mkmap_db_after_open;
132  mkmap->mkmap.after_close = mkmap_db_after_close;
133 
134  /*
135  * Unfortunately, not all systems that might support db databases do
136  * support locking on open(), so we open the file before updating it.
137  *
138  * XXX Berkeley DB 4.1 refuses to open a zero-length file. This means we can
139  * open and lock only an existing file, and that we must not truncate it.
140  */
141  if ((mkmap->lock_fd = open(mkmap->lock_file, O_RDWR, 0644)) < 0) {
142  if (errno != ENOENT)
143  msg_fatal("open %s: %m", mkmap->lock_file);
144  }
145 
146  /*
147  * Get an exclusive lock - we're going to change the database so we can't
148  * have any spectators.
149  *
150  * XXX Horror. Berkeley DB 4.1 refuses to open a zero-length file. This
151  * means that we must examine the size while the file is locked, and that
152  * we must unlink a zero-length file while it is locked. Avoid a race
153  * condition where two processes try to open the same zero-length file
154  * and where the second process ends up deleting the wrong file.
155  */
156  else {
157  if (myflock(mkmap->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
158  msg_fatal("lock %s: %m", mkmap->lock_file);
159  if (fstat(mkmap->lock_fd, &st) < 0)
160  msg_fatal("fstat %s: %m", mkmap->lock_file);
161  if (st.st_size == 0) {
162  if (st.st_nlink > 0) {
163  if (unlink(mkmap->lock_file) < 0)
164  msg_fatal("cannot remove zero-length database file %s: %m",
165  mkmap->lock_file);
166  msg_warn("removing zero-length database file: %s",
167  mkmap->lock_file);
168  }
169  close(mkmap->lock_fd);
170  mkmap->lock_fd = -1;
171  }
172  }
173 
174  return (&mkmap->mkmap);
175 }
176 
177 /* mkmap_hash_open - create or open hashed DB file */
178 
179 MKMAP *mkmap_hash_open(const char *path)
180 {
181  return (mkmap_db_before_open(path, dict_hash_open));
182 }
183 
184 /* mkmap_btree_open - create or open btree DB file */
185 
186 MKMAP *mkmap_btree_open(const char *path)
187 {
188  return (mkmap_db_before_open(path, dict_btree_open));
189 }
190 
191 #endif
void myfree(void *ptr)
Definition: mymalloc.c:207
#define stat(p, s)
Definition: warn_stat.h:18
#define MYFLOCK_OP_EXCLUSIVE
Definition: myflock.h:30
int dict_db_cache_size
Definition: dict.h:78
MKMAP * mkmap_btree_open(const char *)
int var_db_create_buf
Definition: mail_params.c:314
void msg_warn(const char *fmt,...)
Definition: msg.c:215
int myflock(int fd, int lock_style, int operation)
Definition: myflock.c:87
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
DICT * dict_btree_open(const char *, int, int)
Definition: mkmap.h:25
MKMAP * mkmap_hash_open(const char *)
DICT * dict_hash_open(const char *, int, int)
#define fstat(f, s)
Definition: warn_stat.h:20
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150