citrus_mapper.c revision 252464
1284677Sdim/* $FreeBSD: head/lib/libc/iconv/citrus_mapper.c 252464 2013-07-01 08:38:31Z peter $ */ 2284677Sdim/* $NetBSD: citrus_mapper.c,v 1.7 2008/07/25 14:05:25 christos Exp $ */ 3284677Sdim 4284677Sdim/*- 5284677Sdim * Copyright (c)2003 Citrus Project, 6284677Sdim * All rights reserved. 7284677Sdim * 8284677Sdim * Redistribution and use in source and binary forms, with or without 9284677Sdim * modification, are permitted provided that the following conditions 10284677Sdim * are met: 11341825Sdim * 1. Redistributions of source code must retain the above copyright 12284677Sdim * notice, this list of conditions and the following disclaimer. 13284677Sdim * 2. Redistributions in binary form must reproduce the above copyright 14284677Sdim * notice, this list of conditions and the following disclaimer in the 15284677Sdim * documentation and/or other materials provided with the distribution. 16284677Sdim * 17284677Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18284677Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19314564Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20284677Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21284677Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22341825Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23314564Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24314564Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25314564Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26314564Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27314564Sdim * SUCH DAMAGE. 28314564Sdim */ 29284677Sdim 30314564Sdim#include <sys/cdefs.h> 31314564Sdim#include <sys/types.h> 32314564Sdim#include <sys/stat.h> 33314564Sdim#include <sys/queue.h> 34314564Sdim 35284677Sdim#include <assert.h> 36314564Sdim#include <errno.h> 37284677Sdim#include <limits.h> 38284677Sdim#include <stdio.h> 39314564Sdim#include <stdlib.h> 40314564Sdim#include <string.h> 41314564Sdim 42314564Sdim#include "citrus_namespace.h" 43314564Sdim#include "citrus_types.h" 44341825Sdim#include "citrus_region.h" 45314564Sdim#include "citrus_lock.h" 46314564Sdim#include "citrus_memstream.h" 47314564Sdim#include "citrus_bcs.h" 48314564Sdim#include "citrus_mmap.h" 49314564Sdim#include "citrus_module.h" 50284677Sdim#include "citrus_hash.h" 51284677Sdim#include "citrus_mapper.h" 52284677Sdim 53341825Sdim#define _CITRUS_MAPPER_DIR "mapper.dir" 54341825Sdim 55309124Sdim#define CM_HASH_SIZE 101 56309124Sdim#define REFCOUNT_PERSISTENT -1 57341825Sdim 58341825Sdimstruct _citrus_mapper_area { 59341825Sdim _CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache; 60341825Sdim char *ma_dir; 61341825Sdim}; 62341825Sdim 63341825Sdim/* 64284677Sdim * _citrus_mapper_create_area: 65341825Sdim * create mapper area 66284677Sdim */ 67309124Sdim 68309124Sdimint 69309124Sdim_citrus_mapper_create_area( 70309124Sdim struct _citrus_mapper_area *__restrict *__restrict rma, 71309124Sdim const char *__restrict area) 72309124Sdim{ 73309124Sdim struct _citrus_mapper_area *ma; 74309124Sdim struct stat st; 75309124Sdim char path[PATH_MAX]; 76309124Sdim int ret; 77309124Sdim 78309124Sdim WLOCK; 79309124Sdim 80309124Sdim if (*rma != NULL) { 81309124Sdim ret = 0; 82309124Sdim goto quit; 83309124Sdim } 84309124Sdim 85309124Sdim snprintf(path, (size_t)PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR); 86309124Sdim 87309124Sdim ret = stat(path, &st); 88309124Sdim if (ret) 89309124Sdim goto quit; 90309124Sdim 91309124Sdim ma = malloc(sizeof(*ma)); 92309124Sdim if (ma == NULL) { 93309124Sdim ret = errno; 94309124Sdim goto quit; 95309124Sdim } 96309124Sdim ma->ma_dir = strdup(area); 97309124Sdim if (ma->ma_dir == NULL) { 98309124Sdim ret = errno; 99309124Sdim free(ma); 100309124Sdim goto quit; 101309124Sdim } 102309124Sdim _CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE); 103309124Sdim 104314564Sdim *rma = ma; 105314564Sdim ret = 0; 106314564Sdimquit: 107314564Sdim UNLOCK; 108314564Sdim 109314564Sdim return (ret); 110314564Sdim} 111314564Sdim 112314564Sdim 113314564Sdim/* 114314564Sdim * lookup_mapper_entry: 115314564Sdim * lookup mapper.dir entry in the specified directory. 116309124Sdim * 117309124Sdim * line format of iconv.dir file: 118309124Sdim * mapper module arg 119309124Sdim * mapper : mapper name. 120309124Sdim * module : mapper module name. 121284677Sdim * arg : argument for the module (generally, description file name) 122284677Sdim */ 123284677Sdim 124284677Sdimstatic int 125284677Sdimlookup_mapper_entry(const char *dir, const char *mapname, void *linebuf, 126284677Sdim size_t linebufsize, const char **module, const char **variable) 127284677Sdim{ 128284677Sdim struct _region r; 129284677Sdim struct _memstream ms; 130284677Sdim const char *cp, *cq; 131284677Sdim char *p; 132284677Sdim char path[PATH_MAX]; 133284677Sdim size_t len; 134284677Sdim int ret; 135284677Sdim 136284677Sdim /* create mapper.dir path */ 137284677Sdim snprintf(path, (size_t)PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR); 138284677Sdim 139284677Sdim /* open read stream */ 140284677Sdim ret = _map_file(&r, path); 141284677Sdim if (ret) 142284677Sdim return (ret); 143284677Sdim 144284677Sdim _memstream_bind(&ms, &r); 145284677Sdim 146284677Sdim /* search the line matching to the map name */ 147284677Sdim cp = _memstream_matchline(&ms, mapname, &len, 0); 148284677Sdim if (!cp) { 149284677Sdim ret = ENOENT; 150284677Sdim goto quit; 151284677Sdim } 152341825Sdim if (!len || len > linebufsize - 1) { 153341825Sdim ret = EINVAL; 154341825Sdim goto quit; 155341825Sdim } 156341825Sdim 157284677Sdim p = linebuf; 158284677Sdim /* get module name */ 159284677Sdim *module = p; 160284677Sdim cq = _bcs_skip_nonws_len(cp, &len); 161284677Sdim strlcpy(p, cp, (size_t)(cq - cp + 1)); 162284677Sdim p += cq - cp + 1; 163309124Sdim 164284677Sdim /* get variable */ 165284677Sdim *variable = p; 166284677Sdim cp = _bcs_skip_ws_len(cq, &len); 167284677Sdim strlcpy(p, cp, len + 1); 168284677Sdim 169284677Sdim ret = 0; 170284677Sdim 171284677Sdimquit: 172284677Sdim _unmap_file(&r); 173284677Sdim return (ret); 174284677Sdim} 175284677Sdim 176284677Sdim/* 177284677Sdim * mapper_close: 178284677Sdim * simply close a mapper. (without handling hash) 179284677Sdim */ 180284677Sdimstatic void 181284677Sdimmapper_close(struct _citrus_mapper *cm) 182284677Sdim{ 183284677Sdim if (cm->cm_module) { 184284677Sdim if (cm->cm_ops) { 185284677Sdim if (cm->cm_closure) 186284677Sdim (*cm->cm_ops->mo_uninit)(cm); 187284677Sdim free(cm->cm_ops); 188284677Sdim } 189284677Sdim _citrus_unload_module(cm->cm_module); 190284677Sdim } 191284677Sdim free(cm->cm_traits); 192284677Sdim free(cm); 193284677Sdim} 194284677Sdim 195284677Sdim/* 196284677Sdim * mapper_open: 197284677Sdim * simply open a mapper. (without handling hash) 198284677Sdim */ 199284677Sdimstatic int 200284677Sdimmapper_open(struct _citrus_mapper_area *__restrict ma, 201284677Sdim struct _citrus_mapper * __restrict * __restrict rcm, 202284677Sdim const char * __restrict module, 203284677Sdim const char * __restrict variable) 204284677Sdim{ 205284677Sdim struct _citrus_mapper *cm; 206284677Sdim _citrus_mapper_getops_t getops; 207284677Sdim int ret; 208284677Sdim 209284677Sdim /* initialize mapper handle */ 210284677Sdim cm = malloc(sizeof(*cm)); 211284677Sdim if (!cm) 212284677Sdim return (errno); 213284677Sdim 214284677Sdim cm->cm_module = NULL; 215284677Sdim cm->cm_ops = NULL; 216284677Sdim cm->cm_closure = NULL; 217284677Sdim cm->cm_traits = NULL; 218284677Sdim cm->cm_refcount = 0; 219284677Sdim cm->cm_key = NULL; 220284677Sdim 221327952Sdim /* load module */ 222327952Sdim ret = _citrus_load_module(&cm->cm_module, module); 223327952Sdim if (ret) 224327952Sdim goto err; 225327952Sdim 226341825Sdim /* get operators */ 227341825Sdim getops = (_citrus_mapper_getops_t) 228341825Sdim _citrus_find_getops(cm->cm_module, module, "mapper"); 229341825Sdim if (!getops) { 230341825Sdim ret = EOPNOTSUPP; 231341825Sdim goto err; 232341825Sdim } 233341825Sdim cm->cm_ops = malloc(sizeof(*cm->cm_ops)); 234341825Sdim if (!cm->cm_ops) { 235341825Sdim ret = errno; 236341825Sdim goto err; 237341825Sdim } 238341825Sdim ret = (*getops)(cm->cm_ops); 239341825Sdim if (ret) 240341825Sdim goto err; 241341825Sdim 242341825Sdim if (!cm->cm_ops->mo_init || 243341825Sdim !cm->cm_ops->mo_uninit || 244341825Sdim !cm->cm_ops->mo_convert || 245341825Sdim !cm->cm_ops->mo_init_state) 246341825Sdim goto err; 247341825Sdim 248341825Sdim /* allocate traits structure */ 249341825Sdim cm->cm_traits = malloc(sizeof(*cm->cm_traits)); 250341825Sdim if (cm->cm_traits == NULL) { 251341825Sdim ret = errno; 252341825Sdim goto err; 253341825Sdim } 254284677Sdim /* initialize the mapper */ 255284677Sdim ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir, 256284677Sdim (const void *)variable, strlen(variable) + 1, 257284677Sdim cm->cm_traits, sizeof(*cm->cm_traits)); 258284677Sdim if (ret) 259284677Sdim goto err; 260284677Sdim 261284677Sdim *rcm = cm; 262284677Sdim 263284677Sdim return (0); 264321369Sdim 265321369Sdimerr: 266321369Sdim mapper_close(cm); 267321369Sdim return (ret); 268321369Sdim} 269321369Sdim 270321369Sdim/* 271321369Sdim * _citrus_mapper_open_direct: 272321369Sdim * open a mapper. 273284677Sdim */ 274309124Sdimint 275309124Sdim_citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma, 276309124Sdim struct _citrus_mapper * __restrict * __restrict rcm, 277309124Sdim const char * __restrict module, const char * __restrict variable) 278309124Sdim{ 279309124Sdim 280314564Sdim return (mapper_open(ma, rcm, module, variable)); 281284677Sdim} 282284677Sdim 283296417Sdim/* 284314564Sdim * hash_func 285314564Sdim */ 286341825Sdimstatic __inline int 287296417Sdimhash_func(const char *key) 288296417Sdim{ 289309124Sdim 290309124Sdim return (_string_hash_func(key, CM_HASH_SIZE)); 291309124Sdim} 292314564Sdim 293284677Sdim/* 294309124Sdim * match_func 295341825Sdim */ 296284677Sdimstatic __inline int 297309124Sdimmatch_func(struct _citrus_mapper *cm, const char *key) 298284677Sdim{ 299284677Sdim 300284677Sdim return (strcmp(cm->cm_key, key)); 301309124Sdim} 302341825Sdim 303284677Sdim/* 304284677Sdim * _citrus_mapper_open: 305284677Sdim * open a mapper with looking up "mapper.dir". 306284677Sdim */ 307309124Sdimint 308341825Sdim_citrus_mapper_open(struct _citrus_mapper_area *__restrict ma, 309284677Sdim struct _citrus_mapper * __restrict * __restrict rcm, 310284677Sdim const char * __restrict mapname) 311284677Sdim{ 312341825Sdim struct _citrus_mapper *cm; 313309124Sdim char linebuf[PATH_MAX]; 314321369Sdim const char *module, *variable; 315284677Sdim int hashval, ret; 316284677Sdim 317284677Sdim variable = NULL; 318284677Sdim 319284677Sdim WLOCK; 320284677Sdim 321341825Sdim /* search in the cache */ 322309124Sdim hashval = hash_func(mapname); 323341825Sdim _CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname, 324309124Sdim hashval); 325309124Sdim if (cm) { 326284677Sdim /* found */ 327284677Sdim cm->cm_refcount++; 328284677Sdim *rcm = cm; 329341825Sdim ret = 0; 330309124Sdim goto quit; 331341825Sdim } 332309124Sdim 333309124Sdim /* search mapper entry */ 334284677Sdim ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf, 335284677Sdim (size_t)PATH_MAX, &module, &variable); 336284677Sdim if (ret) 337341825Sdim goto quit; 338309124Sdim 339284677Sdim /* open mapper */ 340284677Sdim UNLOCK; 341309124Sdim ret = mapper_open(ma, &cm, module, variable); 342284677Sdim WLOCK; 343284677Sdim if (ret) 344284677Sdim goto quit; 345341825Sdim cm->cm_key = strdup(mapname); 346309124Sdim if (cm->cm_key == NULL) { 347309124Sdim ret = errno; 348309124Sdim _mapper_close(cm); 349309124Sdim goto quit; 350309124Sdim } 351284677Sdim 352314564Sdim /* insert to the cache */ 353341825Sdim cm->cm_refcount = 1; 354309124Sdim _CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval); 355309124Sdim 356284677Sdim *rcm = cm; 357314564Sdim ret = 0; 358341825Sdimquit: 359309124Sdim UNLOCK; 360309124Sdim 361341825Sdim return (ret); 362341825Sdim} 363309124Sdim 364309124Sdim/* 365309124Sdim * _citrus_mapper_close: 366309124Sdim * close the specified mapper. 367314564Sdim */ 368341825Sdimvoid 369309124Sdim_citrus_mapper_close(struct _citrus_mapper *cm) 370341825Sdim{ 371341825Sdim 372309124Sdim if (cm) { 373284677Sdim WLOCK; 374284677Sdim if (cm->cm_refcount == REFCOUNT_PERSISTENT) 375284677Sdim goto quit; 376341825Sdim if (cm->cm_refcount > 0) { 377341825Sdim if (--cm->cm_refcount > 0) 378341825Sdim goto quit; 379309124Sdim _CITRUS_HASH_REMOVE(cm, cm_entry); 380321369Sdim free(cm->cm_key); 381321369Sdim } 382309124Sdim mapper_close(cm); 383284677Sdimquit: 384314564Sdim UNLOCK; 385341825Sdim } 386309124Sdim} 387321369Sdim 388321369Sdim/* 389321369Sdim * _citrus_mapper_set_persistent: 390309124Sdim * set persistent count. 391296417Sdim */ 392284677Sdimvoid 393341825Sdim_citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm) 394341825Sdim{ 395321369Sdim 396309124Sdim WLOCK; 397284677Sdim cm->cm_refcount = REFCOUNT_PERSISTENT; 398341825Sdim UNLOCK; 399284677Sdim} 400341825Sdim