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 62static apr_hash_t *drivers = NULL; 63static apr_uint32_t initialised = 0, in_init = 1; 64 65static 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 78static 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 193APU_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 208APU_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 215APU_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm) 216{ 217 (*dbm->type->close)(dbm); 218} 219 220APU_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 226APU_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 232APU_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 237APU_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key) 238{ 239 return (*dbm->type->exists)(dbm, key); 240} 241 242APU_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 247APU_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 252APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data) 253{ 254 (*dbm->type->freedatum)(dbm, data); 255} 256 257APU_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 272APU_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 288APU_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 */ 299APU_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