1219019Sgabor/* $FreeBSD$ */ 2264497Stijl/* $NetBSD: citrus_mapper.c,v 1.10 2012/06/08 07:49:42 martin Exp $ */ 3219019Sgabor 4219019Sgabor/*- 5219019Sgabor * Copyright (c)2003 Citrus Project, 6219019Sgabor * All rights reserved. 7219019Sgabor * 8219019Sgabor * Redistribution and use in source and binary forms, with or without 9219019Sgabor * modification, are permitted provided that the following conditions 10219019Sgabor * are met: 11219019Sgabor * 1. Redistributions of source code must retain the above copyright 12219019Sgabor * notice, this list of conditions and the following disclaimer. 13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 14219019Sgabor * notice, this list of conditions and the following disclaimer in the 15219019Sgabor * documentation and/or other materials provided with the distribution. 16219019Sgabor * 17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219019Sgabor * SUCH DAMAGE. 28219019Sgabor */ 29219019Sgabor 30219019Sgabor#include <sys/cdefs.h> 31219019Sgabor#include <sys/types.h> 32219019Sgabor#include <sys/stat.h> 33219019Sgabor#include <sys/queue.h> 34219019Sgabor 35219019Sgabor#include <assert.h> 36219019Sgabor#include <errno.h> 37219019Sgabor#include <limits.h> 38219019Sgabor#include <stdio.h> 39219019Sgabor#include <stdlib.h> 40219019Sgabor#include <string.h> 41219019Sgabor 42219019Sgabor#include "citrus_namespace.h" 43219019Sgabor#include "citrus_types.h" 44219019Sgabor#include "citrus_region.h" 45219019Sgabor#include "citrus_lock.h" 46219019Sgabor#include "citrus_memstream.h" 47219019Sgabor#include "citrus_bcs.h" 48219019Sgabor#include "citrus_mmap.h" 49219019Sgabor#include "citrus_module.h" 50219019Sgabor#include "citrus_hash.h" 51219019Sgabor#include "citrus_mapper.h" 52219019Sgabor 53219019Sgabor#define _CITRUS_MAPPER_DIR "mapper.dir" 54219019Sgabor 55219019Sgabor#define CM_HASH_SIZE 101 56219019Sgabor#define REFCOUNT_PERSISTENT -1 57219019Sgabor 58252584Speterstatic pthread_rwlock_t cm_lock = PTHREAD_RWLOCK_INITIALIZER; 59252584Speter 60219019Sgaborstruct _citrus_mapper_area { 61219019Sgabor _CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache; 62219019Sgabor char *ma_dir; 63219019Sgabor}; 64219019Sgabor 65219019Sgabor/* 66219019Sgabor * _citrus_mapper_create_area: 67219019Sgabor * create mapper area 68219019Sgabor */ 69219019Sgabor 70219019Sgaborint 71219019Sgabor_citrus_mapper_create_area( 72219019Sgabor struct _citrus_mapper_area *__restrict *__restrict rma, 73219019Sgabor const char *__restrict area) 74219019Sgabor{ 75219019Sgabor struct _citrus_mapper_area *ma; 76219019Sgabor struct stat st; 77219019Sgabor char path[PATH_MAX]; 78219019Sgabor int ret; 79219019Sgabor 80252584Speter WLOCK(&cm_lock); 81219019Sgabor 82219019Sgabor if (*rma != NULL) { 83219019Sgabor ret = 0; 84219019Sgabor goto quit; 85219019Sgabor } 86219019Sgabor 87219019Sgabor snprintf(path, (size_t)PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR); 88219019Sgabor 89219019Sgabor ret = stat(path, &st); 90219019Sgabor if (ret) 91219019Sgabor goto quit; 92219019Sgabor 93219019Sgabor ma = malloc(sizeof(*ma)); 94219019Sgabor if (ma == NULL) { 95219019Sgabor ret = errno; 96219019Sgabor goto quit; 97219019Sgabor } 98219019Sgabor ma->ma_dir = strdup(area); 99219019Sgabor if (ma->ma_dir == NULL) { 100219019Sgabor ret = errno; 101252464Speter free(ma); 102219019Sgabor goto quit; 103219019Sgabor } 104219019Sgabor _CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE); 105219019Sgabor 106219019Sgabor *rma = ma; 107219019Sgabor ret = 0; 108219019Sgaborquit: 109252584Speter UNLOCK(&cm_lock); 110219019Sgabor 111219019Sgabor return (ret); 112219019Sgabor} 113219019Sgabor 114219019Sgabor 115219019Sgabor/* 116219019Sgabor * lookup_mapper_entry: 117219019Sgabor * lookup mapper.dir entry in the specified directory. 118219019Sgabor * 119219019Sgabor * line format of iconv.dir file: 120219019Sgabor * mapper module arg 121219019Sgabor * mapper : mapper name. 122219019Sgabor * module : mapper module name. 123219019Sgabor * arg : argument for the module (generally, description file name) 124219019Sgabor */ 125219019Sgabor 126219019Sgaborstatic int 127219019Sgaborlookup_mapper_entry(const char *dir, const char *mapname, void *linebuf, 128219019Sgabor size_t linebufsize, const char **module, const char **variable) 129219019Sgabor{ 130219019Sgabor struct _region r; 131219019Sgabor struct _memstream ms; 132219019Sgabor const char *cp, *cq; 133219019Sgabor char *p; 134219019Sgabor char path[PATH_MAX]; 135219019Sgabor size_t len; 136219019Sgabor int ret; 137219019Sgabor 138219019Sgabor /* create mapper.dir path */ 139219019Sgabor snprintf(path, (size_t)PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR); 140219019Sgabor 141219019Sgabor /* open read stream */ 142219019Sgabor ret = _map_file(&r, path); 143219019Sgabor if (ret) 144219019Sgabor return (ret); 145219019Sgabor 146219019Sgabor _memstream_bind(&ms, &r); 147219019Sgabor 148219019Sgabor /* search the line matching to the map name */ 149219019Sgabor cp = _memstream_matchline(&ms, mapname, &len, 0); 150219019Sgabor if (!cp) { 151219019Sgabor ret = ENOENT; 152219019Sgabor goto quit; 153219019Sgabor } 154219019Sgabor if (!len || len > linebufsize - 1) { 155219019Sgabor ret = EINVAL; 156219019Sgabor goto quit; 157219019Sgabor } 158219019Sgabor 159219019Sgabor p = linebuf; 160219019Sgabor /* get module name */ 161219019Sgabor *module = p; 162219019Sgabor cq = _bcs_skip_nonws_len(cp, &len); 163219019Sgabor strlcpy(p, cp, (size_t)(cq - cp + 1)); 164219019Sgabor p += cq - cp + 1; 165219019Sgabor 166219019Sgabor /* get variable */ 167219019Sgabor *variable = p; 168219019Sgabor cp = _bcs_skip_ws_len(cq, &len); 169219019Sgabor strlcpy(p, cp, len + 1); 170219019Sgabor 171219019Sgabor ret = 0; 172219019Sgabor 173219019Sgaborquit: 174219019Sgabor _unmap_file(&r); 175219019Sgabor return (ret); 176219019Sgabor} 177219019Sgabor 178219019Sgabor/* 179219019Sgabor * mapper_close: 180219019Sgabor * simply close a mapper. (without handling hash) 181219019Sgabor */ 182219019Sgaborstatic void 183219019Sgabormapper_close(struct _citrus_mapper *cm) 184219019Sgabor{ 185219019Sgabor if (cm->cm_module) { 186219019Sgabor if (cm->cm_ops) { 187219019Sgabor if (cm->cm_closure) 188219019Sgabor (*cm->cm_ops->mo_uninit)(cm); 189219019Sgabor free(cm->cm_ops); 190219019Sgabor } 191219019Sgabor _citrus_unload_module(cm->cm_module); 192219019Sgabor } 193219019Sgabor free(cm->cm_traits); 194219019Sgabor free(cm); 195219019Sgabor} 196219019Sgabor 197219019Sgabor/* 198219019Sgabor * mapper_open: 199219019Sgabor * simply open a mapper. (without handling hash) 200219019Sgabor */ 201219019Sgaborstatic int 202219019Sgabormapper_open(struct _citrus_mapper_area *__restrict ma, 203219019Sgabor struct _citrus_mapper * __restrict * __restrict rcm, 204219019Sgabor const char * __restrict module, 205219019Sgabor const char * __restrict variable) 206219019Sgabor{ 207219019Sgabor struct _citrus_mapper *cm; 208219019Sgabor _citrus_mapper_getops_t getops; 209219019Sgabor int ret; 210219019Sgabor 211219019Sgabor /* initialize mapper handle */ 212219019Sgabor cm = malloc(sizeof(*cm)); 213219019Sgabor if (!cm) 214219019Sgabor return (errno); 215219019Sgabor 216219019Sgabor cm->cm_module = NULL; 217219019Sgabor cm->cm_ops = NULL; 218219019Sgabor cm->cm_closure = NULL; 219219019Sgabor cm->cm_traits = NULL; 220219019Sgabor cm->cm_refcount = 0; 221219019Sgabor cm->cm_key = NULL; 222219019Sgabor 223219019Sgabor /* load module */ 224219019Sgabor ret = _citrus_load_module(&cm->cm_module, module); 225219019Sgabor if (ret) 226219019Sgabor goto err; 227219019Sgabor 228219019Sgabor /* get operators */ 229219019Sgabor getops = (_citrus_mapper_getops_t) 230219019Sgabor _citrus_find_getops(cm->cm_module, module, "mapper"); 231219019Sgabor if (!getops) { 232219019Sgabor ret = EOPNOTSUPP; 233219019Sgabor goto err; 234219019Sgabor } 235219019Sgabor cm->cm_ops = malloc(sizeof(*cm->cm_ops)); 236219019Sgabor if (!cm->cm_ops) { 237219019Sgabor ret = errno; 238219019Sgabor goto err; 239219019Sgabor } 240219019Sgabor ret = (*getops)(cm->cm_ops); 241219019Sgabor if (ret) 242219019Sgabor goto err; 243219019Sgabor 244219019Sgabor if (!cm->cm_ops->mo_init || 245219019Sgabor !cm->cm_ops->mo_uninit || 246219019Sgabor !cm->cm_ops->mo_convert || 247264497Stijl !cm->cm_ops->mo_init_state) { 248264497Stijl ret = EINVAL; 249219019Sgabor goto err; 250264497Stijl } 251219019Sgabor 252219019Sgabor /* allocate traits structure */ 253219019Sgabor cm->cm_traits = malloc(sizeof(*cm->cm_traits)); 254219019Sgabor if (cm->cm_traits == NULL) { 255219019Sgabor ret = errno; 256219019Sgabor goto err; 257219019Sgabor } 258219019Sgabor /* initialize the mapper */ 259219019Sgabor ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir, 260219019Sgabor (const void *)variable, strlen(variable) + 1, 261219019Sgabor cm->cm_traits, sizeof(*cm->cm_traits)); 262219019Sgabor if (ret) 263219019Sgabor goto err; 264219019Sgabor 265219019Sgabor *rcm = cm; 266219019Sgabor 267219019Sgabor return (0); 268219019Sgabor 269219019Sgaborerr: 270219019Sgabor mapper_close(cm); 271219019Sgabor return (ret); 272219019Sgabor} 273219019Sgabor 274219019Sgabor/* 275219019Sgabor * _citrus_mapper_open_direct: 276219019Sgabor * open a mapper. 277219019Sgabor */ 278219019Sgaborint 279219019Sgabor_citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma, 280219019Sgabor struct _citrus_mapper * __restrict * __restrict rcm, 281219019Sgabor const char * __restrict module, const char * __restrict variable) 282219019Sgabor{ 283219019Sgabor 284219019Sgabor return (mapper_open(ma, rcm, module, variable)); 285219019Sgabor} 286219019Sgabor 287219019Sgabor/* 288219019Sgabor * hash_func 289219019Sgabor */ 290219019Sgaborstatic __inline int 291219019Sgaborhash_func(const char *key) 292219019Sgabor{ 293219019Sgabor 294219019Sgabor return (_string_hash_func(key, CM_HASH_SIZE)); 295219019Sgabor} 296219019Sgabor 297219019Sgabor/* 298219019Sgabor * match_func 299219019Sgabor */ 300219019Sgaborstatic __inline int 301219019Sgabormatch_func(struct _citrus_mapper *cm, const char *key) 302219019Sgabor{ 303219019Sgabor 304219019Sgabor return (strcmp(cm->cm_key, key)); 305219019Sgabor} 306219019Sgabor 307219019Sgabor/* 308219019Sgabor * _citrus_mapper_open: 309219019Sgabor * open a mapper with looking up "mapper.dir". 310219019Sgabor */ 311219019Sgaborint 312219019Sgabor_citrus_mapper_open(struct _citrus_mapper_area *__restrict ma, 313219019Sgabor struct _citrus_mapper * __restrict * __restrict rcm, 314219019Sgabor const char * __restrict mapname) 315219019Sgabor{ 316219019Sgabor struct _citrus_mapper *cm; 317219019Sgabor char linebuf[PATH_MAX]; 318219019Sgabor const char *module, *variable; 319219019Sgabor int hashval, ret; 320219019Sgabor 321219019Sgabor variable = NULL; 322219019Sgabor 323252584Speter WLOCK(&cm_lock); 324219019Sgabor 325219019Sgabor /* search in the cache */ 326219019Sgabor hashval = hash_func(mapname); 327219019Sgabor _CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname, 328219019Sgabor hashval); 329219019Sgabor if (cm) { 330219019Sgabor /* found */ 331219019Sgabor cm->cm_refcount++; 332219019Sgabor *rcm = cm; 333219019Sgabor ret = 0; 334219019Sgabor goto quit; 335219019Sgabor } 336219019Sgabor 337219019Sgabor /* search mapper entry */ 338219019Sgabor ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf, 339219019Sgabor (size_t)PATH_MAX, &module, &variable); 340219019Sgabor if (ret) 341219019Sgabor goto quit; 342219019Sgabor 343219019Sgabor /* open mapper */ 344252584Speter UNLOCK(&cm_lock); 345219019Sgabor ret = mapper_open(ma, &cm, module, variable); 346252584Speter WLOCK(&cm_lock); 347219019Sgabor if (ret) 348219019Sgabor goto quit; 349219019Sgabor cm->cm_key = strdup(mapname); 350219019Sgabor if (cm->cm_key == NULL) { 351219019Sgabor ret = errno; 352219019Sgabor _mapper_close(cm); 353219019Sgabor goto quit; 354219019Sgabor } 355219019Sgabor 356219019Sgabor /* insert to the cache */ 357219019Sgabor cm->cm_refcount = 1; 358219019Sgabor _CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval); 359219019Sgabor 360219019Sgabor *rcm = cm; 361219019Sgabor ret = 0; 362219019Sgaborquit: 363252584Speter UNLOCK(&cm_lock); 364219019Sgabor 365219019Sgabor return (ret); 366219019Sgabor} 367219019Sgabor 368219019Sgabor/* 369219019Sgabor * _citrus_mapper_close: 370219019Sgabor * close the specified mapper. 371219019Sgabor */ 372219019Sgaborvoid 373219019Sgabor_citrus_mapper_close(struct _citrus_mapper *cm) 374219019Sgabor{ 375219019Sgabor 376219019Sgabor if (cm) { 377252584Speter WLOCK(&cm_lock); 378219019Sgabor if (cm->cm_refcount == REFCOUNT_PERSISTENT) 379219019Sgabor goto quit; 380219019Sgabor if (cm->cm_refcount > 0) { 381219019Sgabor if (--cm->cm_refcount > 0) 382219019Sgabor goto quit; 383219019Sgabor _CITRUS_HASH_REMOVE(cm, cm_entry); 384219019Sgabor free(cm->cm_key); 385219019Sgabor } 386257039Sdelphij UNLOCK(&cm_lock); 387219019Sgabor mapper_close(cm); 388257039Sdelphij return; 389219019Sgaborquit: 390252584Speter UNLOCK(&cm_lock); 391219019Sgabor } 392219019Sgabor} 393219019Sgabor 394219019Sgabor/* 395219019Sgabor * _citrus_mapper_set_persistent: 396219019Sgabor * set persistent count. 397219019Sgabor */ 398219019Sgaborvoid 399219019Sgabor_citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm) 400219019Sgabor{ 401219019Sgabor 402252584Speter WLOCK(&cm_lock); 403219019Sgabor cm->cm_refcount = REFCOUNT_PERSISTENT; 404252584Speter UNLOCK(&cm_lock); 405219019Sgabor} 406