1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apr.h"
18 #include "apr_dso.h"
19 #include "apr_hash.h"
20 #include "apr_errno.h"
21 #include "apr_pools.h"
22 #include "apr_strings.h"
23 #define APR_WANT_MEMFUNC
24 #define APR_WANT_STRFUNC
25 #include "apr_want.h"
26 #include "apr_general.h"
27 #include "apr_atomic.h"
28
29 #include "apu_config.h"
30 #include "apu.h"
31 #include "apu_internal.h"
32 #include "apu_version.h"
33 #include "apr_dbm_private.h"
34 #include "apu_select_dbm.h"
35 #include "apr_dbm.h"
36 #include "apr_dbm_private.h"
37
38 /* ### note: the setting of DBM_VTABLE will go away once we have multiple
39 ### DBMs in here.
40 ### Well, that day is here. So, do we remove DBM_VTABLE and the old
41 ### API entirely? Oh, what to do. We need an APU_DEFAULT_DBM #define.
42 ### Sounds like a job for autoconf. */
43
44 #if APU_USE_DB
45 #define DBM_VTABLE apr_dbm_type_db
46 #define DBM_NAME "db"
47 #elif APU_USE_GDBM
48 #define DBM_VTABLE apr_dbm_type_gdbm
49 #define DBM_NAME "gdbm"
50 #elif APU_USE_NDBM
51 #define DBM_VTABLE apr_dbm_type_ndbm
52 #define DBM_NAME "ndbm"
53 #elif APU_USE_SDBM
54 #define DBM_VTABLE apr_dbm_type_sdbm
55 #define DBM_NAME "sdbm"
56 #else /* Not in the USE_xDBM list above */
57 #error a DBM implementation was not specified
58 #endif
59
60 #if APU_DSO_BUILD
61
62 static apr_hash_t *drivers = NULL;
63 static apr_uint32_t initialised = 0, in_init = 1;
64
dbm_term(void * ptr)65 static apr_status_t dbm_term(void *ptr)
66 {
67 /* set drivers to NULL so init can work again */
68 drivers = NULL;
69
70 /* Everything else we need is handled by cleanups registered
71 * when we created mutexes and loaded DSOs
72 */
73 return APR_SUCCESS;
74 }
75
76 #endif /* APU_DSO_BUILD */
77
dbm_open_type(apr_dbm_type_t const ** vtable,const char * type,apr_pool_t * pool)78 static apr_status_t dbm_open_type(apr_dbm_type_t const* * vtable,
79 const char *type,
80 apr_pool_t *pool)
81 {
82 #if !APU_DSO_BUILD
83
84 *vtable = NULL;
85 if (!strcasecmp(type, "default")) *vtable = &DBM_VTABLE;
86 #if APU_HAVE_DB
87 else if (!strcasecmp(type, "db")) *vtable = &apr_dbm_type_db;
88 #endif
89 else if (*type && !strcasecmp(type + 1, "dbm")) {
90 #if APU_HAVE_GDBM
91 if (*type == 'G' || *type == 'g') *vtable = &apr_dbm_type_gdbm;
92 #endif
93 #if APU_HAVE_NDBM
94 if (*type == 'N' || *type == 'n') *vtable = &apr_dbm_type_ndbm;
95 #endif
96 #if APU_HAVE_SDBM
97 if (*type == 'S' || *type == 's') *vtable = &apr_dbm_type_sdbm;
98 #endif
99 /* avoid empty block */ ;
100 }
101 if (*vtable)
102 return APR_SUCCESS;
103 return APR_ENOTIMPL;
104
105 #else /* APU_DSO_BUILD */
106
107 char modname[32];
108 char symname[34];
109 apr_dso_handle_sym_t symbol;
110 apr_status_t rv;
111 int usertype = 0;
112
113 if (!strcasecmp(type, "default")) type = DBM_NAME;
114 else if (!strcasecmp(type, "db")) type = "db";
115 else if (*type && !strcasecmp(type + 1, "dbm")) {
116 if (*type == 'G' || *type == 'g') type = "gdbm";
117 else if (*type == 'N' || *type == 'n') type = "ndbm";
118 else if (*type == 'S' || *type == 's') type = "sdbm";
119 }
120 else usertype = 1;
121
122 if (apr_atomic_inc32(&initialised)) {
123 apr_atomic_set32(&initialised, 1); /* prevent wrap-around */
124
125 while (apr_atomic_read32(&in_init)) /* wait until we get fully inited */
126 ;
127 }
128 else {
129 apr_pool_t *parent;
130
131 /* Top level pool scope, need process-scope lifetime */
132 for (parent = apr_pool_parent_get(pool);
133 parent && parent != pool;
134 parent = apr_pool_parent_get(pool))
135 pool = parent;
136
137 /* deprecate in 2.0 - permit implicit initialization */
138 apu_dso_init(pool);
139
140 drivers = apr_hash_make(pool);
141 apr_hash_set(drivers, "sdbm", APR_HASH_KEY_STRING, &apr_dbm_type_sdbm);
142
143 apr_pool_cleanup_register(pool, NULL, dbm_term,
144 apr_pool_cleanup_null);
145
146 apr_atomic_dec32(&in_init);
147 }
148
149 rv = apu_dso_mutex_lock();
150 if (rv) {
151 *vtable = NULL;
152 return rv;
153 }
154
155 *vtable = apr_hash_get(drivers, type, APR_HASH_KEY_STRING);
156 if (*vtable) {
157 apu_dso_mutex_unlock();
158 return APR_SUCCESS;
159 }
160
161 /* The driver DSO must have exactly the same lifetime as the
162 * drivers hash table; ignore the passed-in pool */
163 pool = apr_hash_pool_get(drivers);
164
165 #if defined(NETWARE)
166 apr_snprintf(modname, sizeof(modname), "dbm%s.nlm", type);
167 #elif defined(WIN32) || defined (__CYGWIN__)
168 apr_snprintf(modname, sizeof(modname),
169 "apr_dbm_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".dll", type);
170 #else
171 apr_snprintf(modname, sizeof(modname),
172 "apr_dbm_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".so", type);
173 #endif
174 apr_snprintf(symname, sizeof(symname), "apr_dbm_type_%s", type);
175
176 rv = apu_dso_load(NULL, &symbol, modname, symname, pool);
177 if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */
178 *vtable = symbol;
179 if (usertype)
180 type = apr_pstrdup(pool, type);
181 apr_hash_set(drivers, type, APR_HASH_KEY_STRING, *vtable);
182 rv = APR_SUCCESS;
183 }
184 else
185 *vtable = NULL;
186
187 apu_dso_mutex_unlock();
188 return rv;
189
190 #endif /* APU_DSO_BUILD */
191 }
192
apr_dbm_open_ex(apr_dbm_t ** pdb,const char * type,const char * pathname,apr_int32_t mode,apr_fileperms_t perm,apr_pool_t * pool)193 APU_DECLARE(apr_status_t) apr_dbm_open_ex(apr_dbm_t **pdb, const char *type,
194 const char *pathname,
195 apr_int32_t mode,
196 apr_fileperms_t perm,
197 apr_pool_t *pool)
198 {
199 apr_dbm_type_t const* vtable = NULL;
200 apr_status_t rv = dbm_open_type(&vtable, type, pool);
201
202 if (rv == APR_SUCCESS) {
203 rv = (vtable->open)(pdb, pathname, mode, perm, pool);
204 }
205 return rv;
206 }
207
apr_dbm_open(apr_dbm_t ** pdb,const char * pathname,apr_int32_t mode,apr_fileperms_t perm,apr_pool_t * pool)208 APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **pdb, const char *pathname,
209 apr_int32_t mode, apr_fileperms_t perm,
210 apr_pool_t *pool)
211 {
212 return apr_dbm_open_ex(pdb, DBM_NAME, pathname, mode, perm, pool);
213 }
214
apr_dbm_close(apr_dbm_t * dbm)215 APU_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm)
216 {
217 (*dbm->type->close)(dbm);
218 }
219
apr_dbm_fetch(apr_dbm_t * dbm,apr_datum_t key,apr_datum_t * pvalue)220 APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key,
221 apr_datum_t *pvalue)
222 {
223 return (*dbm->type->fetch)(dbm, key, pvalue);
224 }
225
apr_dbm_store(apr_dbm_t * dbm,apr_datum_t key,apr_datum_t value)226 APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key,
227 apr_datum_t value)
228 {
229 return (*dbm->type->store)(dbm, key, value);
230 }
231
apr_dbm_delete(apr_dbm_t * dbm,apr_datum_t key)232 APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key)
233 {
234 return (*dbm->type->del)(dbm, key);
235 }
236
apr_dbm_exists(apr_dbm_t * dbm,apr_datum_t key)237 APU_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key)
238 {
239 return (*dbm->type->exists)(dbm, key);
240 }
241
apr_dbm_firstkey(apr_dbm_t * dbm,apr_datum_t * pkey)242 APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey)
243 {
244 return (*dbm->type->firstkey)(dbm, pkey);
245 }
246
apr_dbm_nextkey(apr_dbm_t * dbm,apr_datum_t * pkey)247 APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey)
248 {
249 return (*dbm->type->nextkey)(dbm, pkey);
250 }
251
apr_dbm_freedatum(apr_dbm_t * dbm,apr_datum_t data)252 APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data)
253 {
254 (*dbm->type->freedatum)(dbm, data);
255 }
256
apr_dbm_geterror(apr_dbm_t * dbm,int * errcode,char * errbuf,apr_size_t errbufsize)257 APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode,
258 char *errbuf, apr_size_t errbufsize)
259 {
260 if (errcode != NULL)
261 *errcode = dbm->errcode;
262
263 /* assert: errbufsize > 0 */
264
265 if (dbm->errmsg == NULL)
266 *errbuf = '\0';
267 else
268 (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize);
269 return errbuf;
270 }
271
apr_dbm_get_usednames_ex(apr_pool_t * p,const char * type,const char * pathname,const char ** used1,const char ** used2)272 APU_DECLARE(apr_status_t) apr_dbm_get_usednames_ex(apr_pool_t *p,
273 const char *type,
274 const char *pathname,
275 const char **used1,
276 const char **used2)
277 {
278 apr_dbm_type_t const* vtable;
279 apr_status_t rv = dbm_open_type(&vtable, type, p);
280
281 if (rv == APR_SUCCESS) {
282 (vtable->getusednames)(p, pathname, used1, used2);
283 return APR_SUCCESS;
284 }
285 return rv;
286 }
287
apr_dbm_get_usednames(apr_pool_t * p,const char * pathname,const char ** used1,const char ** used2)288 APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *p,
289 const char *pathname,
290 const char **used1,
291 const char **used2)
292 {
293 apr_dbm_get_usednames_ex(p, DBM_NAME, pathname, used1, used2);
294 }
295
296 /* Most DBM libraries take a POSIX mode for creating files. Don't trust
297 * the mode_t type, some platforms may not support it, int is safe.
298 */
apr_posix_perms2mode(apr_fileperms_t perm)299 APU_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm)
300 {
301 int mode = 0;
302
303 mode |= 0700 & (perm >> 2); /* User is off-by-2 bits */
304 mode |= 0070 & (perm >> 1); /* Group is off-by-1 bit */
305 mode |= 0007 & (perm); /* World maps 1 for 1 */
306 return mode;
307 }
308