1 /* $NetBSD: citrus_mapper.c,v 1.1 2003/06/25 09:51:36 tshiozak Exp $ */ 2 3 /*- 4 * Copyright (c)2003 Citrus Project, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #if defined(LIBC_SCCS) && !defined(lint) 31 __RCSID("$NetBSD: citrus_mapper.c,v 1.1 2003/06/25 09:51:36 tshiozak Exp $"); 32 #endif /* LIBC_SCCS and not lint */ 33 34 #include "namespace.h" 35 #include "reentrant.h" 36 #include <assert.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <errno.h> 41 #include <limits.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 45 #include "citrus_namespace.h" 46 #include "citrus_types.h" 47 #include "citrus_region.h" 48 #include "citrus_memstream.h" 49 #include "citrus_bcs.h" 50 #include "citrus_mmap.h" 51 #include "citrus_module.h" 52 #include "citrus_hash.h" 53 #include "citrus_mapper.h" 54 55 #define _CITRUS_MAPPER_DIR "mapper.dir" 56 57 #define CM_HASH_SIZE 101 58 #define REFCOUNT_PERSISTENT -1 59 60 #ifdef _REENTRANT 61 static rwlock_t lock = RWLOCK_INITIALIZER; 62 #endif 63 64 struct _citrus_mapper_area { 65 _CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache; 66 char *ma_dir; 67 }; 68 69 /* 70 * _citrus_mapper_create_area: 71 * create mapper area 72 */ 73 74 int 75 _citrus_mapper_create_area( 76 struct _citrus_mapper_area *__restrict *__restrict rma, 77 const char *__restrict area) 78 { 79 struct stat st; 80 int ret; 81 char path[PATH_MAX]; 82 struct _citrus_mapper_area *ma; 83 84 rwlock_wrlock(&lock); 85 86 if (*rma != NULL) { 87 ret = 0; 88 goto quit; 89 } 90 91 snprintf(path, PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR); 92 93 ret = stat(path, &st); 94 if (ret) 95 goto quit; 96 97 ma = malloc(sizeof(*ma)); 98 if (ma == NULL) { 99 ret = errno; 100 goto quit; 101 } 102 ma->ma_dir = strdup(area); 103 if (ma->ma_dir == NULL) { 104 ret = errno; 105 free(ma->ma_dir); 106 goto quit; 107 } 108 _CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE); 109 110 *rma = ma; 111 ret = 0; 112 quit: 113 rwlock_unlock(&lock); 114 115 return ret; 116 } 117 118 119 /* 120 * lookup_mapper_entry: 121 * lookup mapper.dir entry in the specified directory. 122 * 123 * line format of iconv.dir file: 124 * mapper module arg 125 * mapper : mapper name. 126 * module : mapper module name. 127 * arg : argument for the module (generally, description file name) 128 */ 129 130 static int 131 lookup_mapper_entry(const char *dir, const char *mapname, 132 void *linebuf, size_t linebufsize, 133 const char **module, const char **variable) 134 { 135 struct _region r; 136 struct _memstream ms; 137 int ret; 138 const char *cp, *cq; 139 char *p; 140 size_t len; 141 char path[PATH_MAX]; 142 143 /* create mapper.dir path */ 144 snprintf(path, PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR); 145 146 /* open read stream */ 147 ret = _map_file(&r, path); 148 if (ret) 149 return ret; 150 151 _memstream_bind(&ms, &r); 152 153 /* search the line matching to the map name */ 154 cp = _memstream_matchline(&ms, mapname, &len, 0); 155 if (!cp) { 156 ret = ENOENT; 157 goto quit; 158 } 159 if (!len || len>linebufsize-1) { 160 ret = EINVAL; 161 goto quit; 162 } 163 164 p = linebuf; 165 /* get module name */ 166 *module = p; 167 cq = _bcs_skip_nonws_len(cp, &len); 168 strlcpy(p, cp, (size_t)(cq-cp+1)); 169 p += cq-cp+1; 170 171 /* get variable */ 172 *variable = p; 173 cp = _bcs_skip_ws_len(cq, &len); 174 strlcpy(p, cp, len+1); 175 176 ret = 0; 177 178 quit: 179 _unmap_file(&r); 180 return ret; 181 } 182 183 /* 184 * mapper_open: 185 */ 186 static int 187 mapper_open(struct _citrus_mapper_area *__restrict ma, 188 struct _citrus_mapper * __restrict * __restrict rcm, 189 const char * __restrict module, 190 const char * __restrict variable) 191 { 192 int ret; 193 struct _citrus_mapper *cm; 194 _citrus_mapper_getops_t getops; 195 196 /* initialize mapper handle */ 197 cm = malloc(sizeof(*cm)); 198 if (!cm) 199 return errno; 200 201 cm->cm_module = NULL; 202 cm->cm_ops = NULL; 203 cm->cm_closure = NULL; 204 cm->cm_traits = NULL; 205 cm->cm_refcount = 0; 206 cm->cm_key = NULL; 207 208 /* load module */ 209 ret = _citrus_load_module(&cm->cm_module, module); 210 if (ret) 211 goto err; 212 213 /* get operators */ 214 getops = (_citrus_mapper_getops_t) 215 _citrus_find_getops(cm->cm_module, module, "mapper"); 216 if (!getops) { 217 ret = EOPNOTSUPP; 218 goto err; 219 } 220 cm->cm_ops = malloc(sizeof(*cm->cm_ops)); 221 if (!cm->cm_ops) { 222 ret = errno; 223 goto err; 224 } 225 ret = (*getops)(cm->cm_ops, sizeof(*cm->cm_ops), 226 _CITRUS_MAPPER_ABI_VERSION); 227 if (ret) 228 goto err; 229 230 if (!cm->cm_ops->mo_init || 231 !cm->cm_ops->mo_uninit || 232 !cm->cm_ops->mo_convert || 233 !cm->cm_ops->mo_init_state) 234 goto err; 235 236 /* allocate traits structure */ 237 cm->cm_traits = malloc(sizeof(*cm->cm_traits)); 238 if (cm->cm_traits == NULL) { 239 ret = errno; 240 goto err; 241 } 242 /* initialize the mapper */ 243 ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir, 244 (const void *)variable, 245 strlen(variable)+1, 246 cm->cm_traits, sizeof(*cm->cm_traits)); 247 if (ret) 248 goto err; 249 250 *rcm = cm; 251 252 return 0; 253 err: 254 _citrus_mapper_close(cm); 255 return ret; 256 } 257 258 /* 259 * _citrus_mapper_open_direct: 260 * open a mapper. 261 */ 262 int 263 _citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma, 264 struct _citrus_mapper * __restrict * __restrict rcm, 265 const char * __restrict module, 266 const char * __restrict variable) 267 { 268 return mapper_open(ma, rcm, module, variable); 269 } 270 271 /* 272 * hash_func 273 */ 274 static __inline int 275 hash_func(const char *key) 276 { 277 return _string_hash_func(key, CM_HASH_SIZE); 278 } 279 280 /* 281 * match_func 282 */ 283 static __inline int 284 match_func(struct _citrus_mapper *cm, const char *key) 285 { 286 return strcmp(cm->cm_key, key); 287 } 288 289 /* 290 * _citrus_mapper_open: 291 * open a mapper with looking up "mapper.dir". 292 */ 293 int 294 _citrus_mapper_open(struct _citrus_mapper_area *__restrict ma, 295 struct _citrus_mapper * __restrict * __restrict rcm, 296 const char * __restrict mapname) 297 { 298 int ret; 299 char linebuf[PATH_MAX]; 300 const char *module, *variable; 301 struct _citrus_mapper *cm; 302 int hashval; 303 304 rwlock_wrlock(&lock); 305 306 /* search in the cache */ 307 hashval = hash_func(mapname); 308 _CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname, 309 hashval); 310 if (cm) { 311 /* found */ 312 cm->cm_refcount++; 313 *rcm = cm; 314 ret = 0; 315 goto quit; 316 } 317 318 /* search mapper entry */ 319 ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf, PATH_MAX, 320 &module, &variable); 321 if (ret) 322 goto quit; 323 324 /* open mapper */ 325 ret = mapper_open(ma, &cm, module, variable); 326 if (ret) 327 goto quit; 328 cm->cm_key = strdup(mapname); 329 if (cm->cm_key == NULL) { 330 ret = errno; 331 rwlock_unlock(&lock); 332 _mapper_close(cm); 333 return ret; 334 } 335 336 /* insert to the cache */ 337 cm->cm_refcount = 1; 338 _CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval); 339 340 *rcm = cm; 341 ret = 0; 342 quit: 343 rwlock_unlock(&lock); 344 return ret; 345 } 346 347 /* 348 * _citrus_mapper_close: 349 * close the specified mapper. 350 */ 351 void 352 _citrus_mapper_close(struct _citrus_mapper *cm) 353 { 354 if (cm) { 355 rwlock_wrlock(&lock); 356 if (cm->cm_refcount == REFCOUNT_PERSISTENT) { 357 rwlock_unlock(&lock); 358 return; 359 } 360 if (cm->cm_refcount > 0) { 361 if (--cm->cm_refcount > 0) { 362 rwlock_unlock(&lock); 363 return; 364 } else { 365 _CITRUS_HASH_REMOVE(cm, cm_entry); 366 } 367 } 368 if (cm->cm_module) { 369 if (cm->cm_ops) { 370 if (cm->cm_closure) 371 (*cm->cm_ops->mo_uninit)(cm); 372 free(cm->cm_ops); 373 } 374 _citrus_unload_module(cm->cm_module); 375 } 376 free(cm->cm_key); 377 free(cm->cm_traits); 378 free(cm); 379 rwlock_unlock(&lock); 380 } 381 } 382 383 /* 384 * _citrus_mapper_set_persistent: 385 * set persistent count. 386 */ 387 void 388 _citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm) 389 { 390 rwlock_wrlock(&lock); 391 cm->cm_refcount = REFCOUNT_PERSISTENT; 392 rwlock_unlock(&lock); 393 } 394