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 = pool; parent; parent = apr_pool_parent_get(pool)) 133 pool = parent; 134 135 /* deprecate in 2.0 - permit implicit initialization */ 136 apu_dso_init(pool); 137 138 drivers = apr_hash_make(pool); 139 apr_hash_set(drivers, "sdbm", APR_HASH_KEY_STRING, &apr_dbm_type_sdbm); 140 141 apr_pool_cleanup_register(pool, NULL, dbm_term, 142 apr_pool_cleanup_null); 143 144 apr_atomic_dec32(&in_init); 145 } 146 147 rv = apu_dso_mutex_lock(); 148 if (rv) { 149 *vtable = NULL; 150 return rv; 151 } 152 153 *vtable = apr_hash_get(drivers, type, APR_HASH_KEY_STRING); 154 if (*vtable) { 155 apu_dso_mutex_unlock(); 156 return APR_SUCCESS; 157 } 158 159 /* The driver DSO must have exactly the same lifetime as the 160 * drivers hash table; ignore the passed-in pool */ 161 pool = apr_hash_pool_get(drivers); 162 163#if defined(NETWARE) 164 apr_snprintf(modname, sizeof(modname), "dbm%s.nlm", type); 165#elif defined(WIN32) 166 apr_snprintf(modname, sizeof(modname), 167 "apr_dbm_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".dll", type); 168#else 169 apr_snprintf(modname, sizeof(modname), 170 "apr_dbm_%s-" APU_STRINGIFY(APU_MAJOR_VERSION) ".so", type); 171#endif 172 apr_snprintf(symname, sizeof(symname), "apr_dbm_type_%s", type); 173 174 rv = apu_dso_load(NULL, &symbol, modname, symname, pool); 175 if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */ 176 *vtable = symbol; 177 if (usertype) 178 type = apr_pstrdup(pool, type); 179 apr_hash_set(drivers, type, APR_HASH_KEY_STRING, *vtable); 180 rv = APR_SUCCESS; 181 } 182 else 183 *vtable = NULL; 184 185 apu_dso_mutex_unlock(); 186 return rv; 187 188#endif /* APU_DSO_BUILD */ 189} 190 191APU_DECLARE(apr_status_t) apr_dbm_open_ex(apr_dbm_t **pdb, const char *type, 192 const char *pathname, 193 apr_int32_t mode, 194 apr_fileperms_t perm, 195 apr_pool_t *pool) 196{ 197 apr_dbm_type_t const* vtable = NULL; 198 apr_status_t rv = dbm_open_type(&vtable, type, pool); 199 200 if (rv == APR_SUCCESS) { 201 rv = (vtable->open)(pdb, pathname, mode, perm, pool); 202 } 203 return rv; 204} 205 206APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **pdb, const char *pathname, 207 apr_int32_t mode, apr_fileperms_t perm, 208 apr_pool_t *pool) 209{ 210 return apr_dbm_open_ex(pdb, DBM_NAME, pathname, mode, perm, pool); 211} 212 213APU_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm) 214{ 215 (*dbm->type->close)(dbm); 216} 217 218APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key, 219 apr_datum_t *pvalue) 220{ 221 return (*dbm->type->fetch)(dbm, key, pvalue); 222} 223 224APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key, 225 apr_datum_t value) 226{ 227 return (*dbm->type->store)(dbm, key, value); 228} 229 230APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key) 231{ 232 return (*dbm->type->del)(dbm, key); 233} 234 235APU_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key) 236{ 237 return (*dbm->type->exists)(dbm, key); 238} 239 240APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey) 241{ 242 return (*dbm->type->firstkey)(dbm, pkey); 243} 244 245APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey) 246{ 247 return (*dbm->type->nextkey)(dbm, pkey); 248} 249 250APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data) 251{ 252 (*dbm->type->freedatum)(dbm, data); 253} 254 255APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode, 256 char *errbuf, apr_size_t errbufsize) 257{ 258 if (errcode != NULL) 259 *errcode = dbm->errcode; 260 261 /* assert: errbufsize > 0 */ 262 263 if (dbm->errmsg == NULL) 264 *errbuf = '\0'; 265 else 266 (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize); 267 return errbuf; 268} 269 270APU_DECLARE(apr_status_t) apr_dbm_get_usednames_ex(apr_pool_t *p, 271 const char *type, 272 const char *pathname, 273 const char **used1, 274 const char **used2) 275{ 276 apr_dbm_type_t const* vtable; 277 apr_status_t rv = dbm_open_type(&vtable, type, p); 278 279 if (rv == APR_SUCCESS) { 280 (vtable->getusednames)(p, pathname, used1, used2); 281 return APR_SUCCESS; 282 } 283 return rv; 284} 285 286APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *p, 287 const char *pathname, 288 const char **used1, 289 const char **used2) 290{ 291 apr_dbm_get_usednames_ex(p, DBM_NAME, pathname, used1, used2); 292} 293 294/* Most DBM libraries take a POSIX mode for creating files. Don't trust 295 * the mode_t type, some platforms may not support it, int is safe. 296 */ 297APU_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm) 298{ 299 int mode = 0; 300 301 mode |= 0700 & (perm >> 2); /* User is off-by-2 bits */ 302 mode |= 0070 & (perm >> 1); /* Group is off-by-1 bit */ 303 mode |= 0007 & (perm); /* World maps 1 for 1 */ 304 return mode; 305} 306