138494Sobrien/* 2174294Sobrien * Copyright (c) 1997-2006 Erez Zadok 338494Sobrien * Copyright (c) 1989 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1989 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042629Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * 40174294Sobrien * File: am-utils/amd/mapc.c 4138494Sobrien * 4238494Sobrien */ 4338494Sobrien 4438494Sobrien/* 4538494Sobrien * Mount map cache 4638494Sobrien */ 4738494Sobrien 4838494Sobrien#ifdef HAVE_CONFIG_H 4938494Sobrien# include <config.h> 5038494Sobrien#endif /* HAVE_CONFIG_H */ 5138494Sobrien#include <am_defs.h> 5238494Sobrien#include <amd.h> 5338494Sobrien 5438494Sobrien/* 5538494Sobrien * Make a duplicate reference to an existing map 5638494Sobrien */ 5738494Sobrien#define mapc_dup(m) ((m)->refc++, (m)) 5838494Sobrien 5938494Sobrien/* 6038494Sobrien * Map cache types 6138494Sobrien * default, none, incremental, all, regexp 6238494Sobrien * MAPC_RE implies MAPC_ALL and must be numerically 6338494Sobrien * greater. 6438494Sobrien */ 6538494Sobrien#define MAPC_DFLT 0x000 6638494Sobrien#define MAPC_NONE 0x001 6738494Sobrien#define MAPC_INC 0x002 6838494Sobrien#define MAPC_ROOT 0x004 6938494Sobrien#define MAPC_ALL 0x010 7038494Sobrien#define MAPC_CACHE_MASK 0x0ff 7138494Sobrien#define MAPC_SYNC 0x100 7238494Sobrien 7338494Sobrien#ifdef HAVE_REGEXEC 7438494Sobrien# define MAPC_RE 0x020 7538494Sobrien# define MAPC_ISRE(m) ((m)->alloc == MAPC_RE) 7638494Sobrien#else /* not HAVE_REGEXEC */ 7738494Sobrien# define MAPC_ISRE(m) FALSE 7838494Sobrien#endif /* not HAVE_REGEXEC */ 7938494Sobrien 8038494Sobrien/* 8138494Sobrien * Lookup recursion 8238494Sobrien */ 8338494Sobrien#define MREC_FULL 2 8438494Sobrien#define MREC_PART 1 8538494Sobrien#define MREC_NONE 0 8638494Sobrien 8738494Sobrienstatic struct opt_tab mapc_opt[] = 8838494Sobrien{ 8938494Sobrien {"all", MAPC_ALL}, 9038494Sobrien {"default", MAPC_DFLT}, 9138494Sobrien {"inc", MAPC_INC}, 9238494Sobrien {"mapdefault", MAPC_DFLT}, 9338494Sobrien {"none", MAPC_NONE}, 9438494Sobrien#ifdef HAVE_REGEXEC 9538494Sobrien {"re", MAPC_RE}, 9638494Sobrien {"regexp", MAPC_RE}, 9738494Sobrien#endif /* HAVE_REGEXEC */ 9838494Sobrien {"sync", MAPC_SYNC}, 9938494Sobrien {0, 0} 10038494Sobrien}; 10138494Sobrien 10238494Sobrien/* 10338494Sobrien * Wildcard key 10438494Sobrien */ 10538494Sobrienstatic char wildcard[] = "*"; 10638494Sobrien 10738494Sobrien/* 10838494Sobrien * Map type 10938494Sobrien */ 11038494Sobrientypedef struct map_type map_type; 11138494Sobrienstruct map_type { 11238494Sobrien char *name; /* Name of this map type */ 11342629Sobrien init_fn *init; /* Initialization */ 11438494Sobrien reload_fn *reload; /* Reload or fill */ 11538494Sobrien isup_fn *isup; /* Is service up or not? (1=up, 0=down) */ 11638494Sobrien search_fn *search; /* Search for new entry */ 11738494Sobrien mtime_fn *mtime; /* Find modify time */ 11838494Sobrien int def_alloc; /* Default allocation mode */ 11938494Sobrien}; 12038494Sobrien 12138494Sobrien/* 12238494Sobrien * Map for root node 12338494Sobrien */ 12438494Sobrienstatic mnt_map *root_map; 12538494Sobrien 12638494Sobrien/* 12738494Sobrien * List of known maps 12838494Sobrien */ 12938494Sobrienqelem map_list_head = {&map_list_head, &map_list_head}; 13038494Sobrien 13138494Sobrien/* 13238494Sobrien * Configuration 13338494Sobrien */ 13438494Sobrien 13538494Sobrien/* forward definitions */ 13638494Sobrienstatic const char *get_full_path(const char *map, const char *path, const char *type); 13738494Sobrienstatic int mapc_meta_search(mnt_map *, char *, char **, int); 13838494Sobrienstatic void mapc_sync(mnt_map *); 13952894Sobrienstatic void mapc_clear(mnt_map *); 14038494Sobrien 14138494Sobrien/* ROOT MAP */ 14238494Sobrienstatic int root_init(mnt_map *, char *, time_t *); 14338494Sobrien 14438494Sobrien/* ERROR MAP */ 14538494Sobrienstatic int error_init(mnt_map *, char *, time_t *); 14638494Sobrienstatic int error_reload(mnt_map *, char *, add_fn *); 14738494Sobrienstatic int error_search(mnt_map *, char *, char *, char **, time_t *); 14838494Sobrienstatic int error_mtime(mnt_map *, char *, time_t *); 14938494Sobrien 15038494Sobrien/* PASSWD MAPS */ 15138494Sobrien#ifdef HAVE_MAP_PASSWD 15238494Sobrienextern int passwd_init(mnt_map *, char *, time_t *); 15338494Sobrienextern int passwd_search(mnt_map *, char *, char *, char **, time_t *); 15438494Sobrien#endif /* HAVE_MAP_PASSWD */ 15538494Sobrien 15638494Sobrien/* HESIOD MAPS */ 15738494Sobrien#ifdef HAVE_MAP_HESIOD 15838494Sobrienextern int amu_hesiod_init(mnt_map *, char *map, time_t *tp); 15951292Sobrienextern int hesiod_isup(mnt_map *, char *); 16038494Sobrienextern int hesiod_search(mnt_map *, char *, char *, char **, time_t *); 16138494Sobrien#endif /* HAVE_MAP_HESIOD */ 16238494Sobrien 16338494Sobrien/* LDAP MAPS */ 16438494Sobrien#ifdef HAVE_MAP_LDAP 16538494Sobrienextern int amu_ldap_init(mnt_map *, char *map, time_t *tp); 16638494Sobrienextern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *); 16738494Sobrienextern int amu_ldap_mtime(mnt_map *, char *, time_t *); 16838494Sobrien#endif /* HAVE_MAP_LDAP */ 16938494Sobrien 17038494Sobrien/* UNION MAPS */ 17138494Sobrien#ifdef HAVE_MAP_UNION 17238494Sobrienextern int union_init(mnt_map *, char *, time_t *); 17338494Sobrienextern int union_search(mnt_map *, char *, char *, char **, time_t *); 17438494Sobrienextern int union_reload(mnt_map *, char *, add_fn *); 17538494Sobrien#endif /* HAVE_MAP_UNION */ 17638494Sobrien 17738494Sobrien/* Network Information Service PLUS (NIS+) */ 17838494Sobrien#ifdef HAVE_MAP_NISPLUS 17938494Sobrienextern int nisplus_init(mnt_map *, char *, time_t *); 18038494Sobrienextern int nisplus_reload(mnt_map *, char *, add_fn *); 18138494Sobrienextern int nisplus_search(mnt_map *, char *, char *, char **, time_t *); 18238494Sobrienextern int nisplus_mtime(mnt_map *, char *, time_t *); 18338494Sobrien#endif /* HAVE_MAP_NISPLUS */ 18438494Sobrien 18538494Sobrien/* Network Information Service (YP, Yellow Pages) */ 18638494Sobrien#ifdef HAVE_MAP_NIS 18738494Sobrienextern int nis_init(mnt_map *, char *, time_t *); 18838494Sobrienextern int nis_reload(mnt_map *, char *, add_fn *); 18938494Sobrienextern int nis_isup(mnt_map *, char *); 19038494Sobrienextern int nis_search(mnt_map *, char *, char *, char **, time_t *); 19138494Sobrienextern int nis_mtime(mnt_map *, char *, time_t *); 19238494Sobrien#endif /* HAVE_MAP_NIS */ 19338494Sobrien 19438494Sobrien/* NDBM MAPS */ 19538494Sobrien#ifdef HAVE_MAP_NDBM 19638494Sobrienextern int ndbm_init(mnt_map *, char *, time_t *); 19738494Sobrienextern int ndbm_search(mnt_map *, char *, char *, char **, time_t *); 19838494Sobrienextern int ndbm_mtime(mnt_map *, char *, time_t *); 19938494Sobrien#endif /* HAVE_MAP_NDBM */ 20038494Sobrien 201174294Sobrien/* EXECUTABLE MAPS */ 202174294Sobrien#ifdef HAVE_MAP_EXEC 203174294Sobrienextern int exec_init(mnt_map *, char *, time_t *); 204174294Sobrienextern int exec_search(mnt_map *, char *, char *, char **, time_t *); 205174294Sobrien#endif /* HAVE_MAP_EXEC */ 206174294Sobrien 20738494Sobrien/* FILE MAPS */ 20838494Sobrien#ifdef HAVE_MAP_FILE 209174294Sobrienextern int file_init_or_mtime(mnt_map *, char *, time_t *); 21038494Sobrienextern int file_reload(mnt_map *, char *, add_fn *); 21138494Sobrienextern int file_search(mnt_map *, char *, char *, char **, time_t *); 21238494Sobrien#endif /* HAVE_MAP_FILE */ 21338494Sobrien 21438494Sobrien 21538494Sobrien/* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */ 21638494Sobrienstatic map_type maptypes[] = 21738494Sobrien{ 21838494Sobrien { 21938494Sobrien "root", 22038494Sobrien root_init, 22138494Sobrien error_reload, 22238494Sobrien NULL, /* isup function */ 22338494Sobrien error_search, 22438494Sobrien error_mtime, 22538494Sobrien MAPC_ROOT 22638494Sobrien }, 22738494Sobrien#ifdef HAVE_MAP_PASSWD 22838494Sobrien { 22938494Sobrien "passwd", 23038494Sobrien passwd_init, 23138494Sobrien error_reload, 23238494Sobrien NULL, /* isup function */ 23338494Sobrien passwd_search, 23438494Sobrien error_mtime, 23582794Sobrien MAPC_INC 23638494Sobrien }, 23738494Sobrien#endif /* HAVE_MAP_PASSWD */ 23838494Sobrien#ifdef HAVE_MAP_HESIOD 23938494Sobrien { 24038494Sobrien "hesiod", 24138494Sobrien amu_hesiod_init, 24238494Sobrien error_reload, 24351292Sobrien hesiod_isup, /* is Hesiod up or not? */ 24438494Sobrien hesiod_search, 24538494Sobrien error_mtime, 24682794Sobrien MAPC_INC 24738494Sobrien }, 24838494Sobrien#endif /* HAVE_MAP_HESIOD */ 24938494Sobrien#ifdef HAVE_MAP_LDAP 25038494Sobrien { 25138494Sobrien "ldap", 25238494Sobrien amu_ldap_init, 25338494Sobrien error_reload, 25438494Sobrien NULL, /* isup function */ 25538494Sobrien amu_ldap_search, 25638494Sobrien amu_ldap_mtime, 25782794Sobrien MAPC_INC 25838494Sobrien }, 25938494Sobrien#endif /* HAVE_MAP_LDAP */ 26038494Sobrien#ifdef HAVE_MAP_UNION 26138494Sobrien { 26238494Sobrien "union", 26338494Sobrien union_init, 26438494Sobrien union_reload, 26538494Sobrien NULL, /* isup function */ 26638494Sobrien union_search, 26738494Sobrien error_mtime, 26838494Sobrien MAPC_ALL 26938494Sobrien }, 27038494Sobrien#endif /* HAVE_MAP_UNION */ 27138494Sobrien#ifdef HAVE_MAP_NISPLUS 27238494Sobrien { 27338494Sobrien "nisplus", 27438494Sobrien nisplus_init, 27538494Sobrien nisplus_reload, 27638494Sobrien NULL, /* isup function */ 27738494Sobrien nisplus_search, 27838494Sobrien nisplus_mtime, 27938494Sobrien MAPC_INC 28038494Sobrien }, 28138494Sobrien#endif /* HAVE_MAP_NISPLUS */ 28238494Sobrien#ifdef HAVE_MAP_NIS 28338494Sobrien { 28438494Sobrien "nis", 28538494Sobrien nis_init, 28638494Sobrien nis_reload, 28738494Sobrien nis_isup, /* is NIS up or not? */ 28838494Sobrien nis_search, 28938494Sobrien nis_mtime, 29038494Sobrien MAPC_ALL 29138494Sobrien }, 29238494Sobrien#endif /* HAVE_MAP_NIS */ 29338494Sobrien#ifdef HAVE_MAP_NDBM 29438494Sobrien { 29538494Sobrien "ndbm", 29638494Sobrien ndbm_init, 29738494Sobrien error_reload, 29838494Sobrien NULL, /* isup function */ 29938494Sobrien ndbm_search, 30038494Sobrien ndbm_mtime, 30182794Sobrien MAPC_INC 30238494Sobrien }, 30338494Sobrien#endif /* HAVE_MAP_NDBM */ 30438494Sobrien#ifdef HAVE_MAP_FILE 30538494Sobrien { 30638494Sobrien "file", 307174294Sobrien file_init_or_mtime, 30838494Sobrien file_reload, 30938494Sobrien NULL, /* isup function */ 31038494Sobrien file_search, 311174294Sobrien file_init_or_mtime, 31238494Sobrien MAPC_ALL 31338494Sobrien }, 31438494Sobrien#endif /* HAVE_MAP_FILE */ 315174294Sobrien#ifdef HAVE_MAP_EXEC 31638494Sobrien { 317174294Sobrien "exec", 318174294Sobrien exec_init, 319174294Sobrien error_reload, 320174294Sobrien NULL, /* isup function */ 321174294Sobrien exec_search, 322174294Sobrien error_mtime, 323174294Sobrien MAPC_INC 324174294Sobrien }, 325174294Sobrien#endif /* HAVE_MAP_EXEC */ 326174294Sobrien { 32738494Sobrien "error", 32838494Sobrien error_init, 32938494Sobrien error_reload, 33038494Sobrien NULL, /* isup function */ 33138494Sobrien error_search, 33238494Sobrien error_mtime, 33338494Sobrien MAPC_NONE 33438494Sobrien }, 33538494Sobrien}; 33638494Sobrien 33738494Sobrien 33838494Sobrien/* 33938494Sobrien * Hash function 34038494Sobrien */ 34138494Sobrienstatic u_int 34238494Sobrienkvhash_of(char *key) 34338494Sobrien{ 34438494Sobrien u_int i, j; 34538494Sobrien 34638494Sobrien for (i = 0; (j = *key++); i += j) ; 34738494Sobrien 34838494Sobrien return i % NKVHASH; 34938494Sobrien} 35038494Sobrien 35138494Sobrien 35238494Sobrienvoid 353174294Sobrienmapc_showtypes(char *buf, size_t l) 35438494Sobrien{ 355174294Sobrien map_type *mt=NULL, *lastmt; 356174294Sobrien int linesize = 0, i; 35738494Sobrien 358174294Sobrien i = sizeof(maptypes) / sizeof(maptypes[0]); 359174294Sobrien lastmt = maptypes + i; 36038494Sobrien buf[0] = '\0'; 361174294Sobrien for (mt = maptypes; mt < lastmt; mt++) { 362174294Sobrien xstrlcat(buf, mt->name, l); 363174294Sobrien if (mt == (lastmt-1)) 364174294Sobrien break; /* if last one, don't do xstrlcat's that follows */ 365174294Sobrien linesize += strlen(mt->name); 366174294Sobrien if (--i > 0) { 367174294Sobrien xstrlcat(buf, ", ", l); 368174294Sobrien linesize += 2; 369174294Sobrien } 370174294Sobrien if (linesize > 54) { 371174294Sobrien linesize = 0; 372174294Sobrien xstrlcat(buf, "\n\t\t ", l); 373174294Sobrien } 37438494Sobrien } 37538494Sobrien} 37638494Sobrien 37738494Sobrien 37838494Sobrien/* 37941142Sobrien * Check if a map of a certain type exists. 38041142Sobrien * Return 1 (true) if exists, 0 (false) if not. 38141142Sobrien */ 38241142Sobrienint 38341142Sobrienmapc_type_exists(const char *type) 38441142Sobrien{ 38541142Sobrien map_type *mt; 38641142Sobrien 38741142Sobrien if (!type) 38841142Sobrien return 0; 38941142Sobrien for (mt = maptypes; 39041142Sobrien mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); 39141142Sobrien mt++) { 39241142Sobrien if (STREQ(type, mt->name)) 39341142Sobrien return 1; 39441142Sobrien } 39541142Sobrien return 0; /* not found anywhere */ 39641142Sobrien} 39741142Sobrien 39841142Sobrien 39941142Sobrien/* 40038494Sobrien * Add key and val to the map m. 40138494Sobrien * key and val are assumed to be safe copies 40238494Sobrien */ 40341142Sobrienvoid 40441142Sobrienmapc_add_kv(mnt_map *m, char *key, char *val) 40538494Sobrien{ 40638494Sobrien kv **h; 40738494Sobrien kv *n; 40838494Sobrien int hash = kvhash_of(key); 40938494Sobrien#ifdef HAVE_REGEXEC 41038494Sobrien regex_t re; 41138494Sobrien#endif /* HAVE_REGEXEC */ 41238494Sobrien 41338494Sobrien dlog("add_kv: %s -> %s", key, val); 41438494Sobrien 41538494Sobrien#ifdef HAVE_REGEXEC 41638494Sobrien if (MAPC_ISRE(m)) { 41738494Sobrien char pattern[MAXPATHLEN]; 41838494Sobrien int retval; 41938494Sobrien 42038494Sobrien /* 42138494Sobrien * Make sure the string is bound to the start and end 42238494Sobrien */ 423174294Sobrien xsnprintf(pattern, sizeof(pattern), "^%s$", key); 42438494Sobrien retval = regcomp(&re, pattern, REG_ICASE); 42538494Sobrien if (retval != 0) { 42638494Sobrien char errstr[256]; 42738494Sobrien 42838494Sobrien /* XXX: this code was recently ported, and must be tested -Erez */ 42938494Sobrien errstr[0] = '\0'; 43038494Sobrien regerror(retval, &re, errstr, 256); 43138494Sobrien plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr); 43238494Sobrien return; 43338494Sobrien } 43438494Sobrien } 43538494Sobrien#endif /* HAVE_REGEXEC */ 43638494Sobrien 43738494Sobrien h = &m->kvhash[hash]; 43838494Sobrien n = ALLOC(struct kv); 43938494Sobrien n->key = key; 44038494Sobrien#ifdef HAVE_REGEXEC 44138494Sobrien memcpy(&n->re, &re, sizeof(regex_t)); 44238494Sobrien#endif /* HAVE_REGEXEC */ 44338494Sobrien n->val = val; 44438494Sobrien n->next = *h; 44538494Sobrien *h = n; 44638494Sobrien} 44738494Sobrien 44838494Sobrien 44938494Sobrienstatic void 45038494Sobrienmapc_repl_kv(mnt_map *m, char *key, char *val) 45138494Sobrien{ 45238494Sobrien kv *k; 45338494Sobrien 45438494Sobrien /* 45538494Sobrien * Compute the hash table offset 45638494Sobrien */ 45738494Sobrien k = m->kvhash[kvhash_of(key)]; 45838494Sobrien 45938494Sobrien /* 46038494Sobrien * Scan the linked list for the key 46138494Sobrien */ 46238494Sobrien while (k && !FSTREQ(k->key, key)) 46338494Sobrien k = k->next; 46438494Sobrien 46538494Sobrien if (k) { 46638494Sobrien XFREE(k->val); 46738494Sobrien k->val = val; 46838494Sobrien } else { 46938494Sobrien mapc_add_kv(m, key, val); 47038494Sobrien } 47138494Sobrien} 47238494Sobrien 47338494Sobrien 47438494Sobrien/* 47538494Sobrien * Search a map for a key. 47638494Sobrien * Calls map specific search routine. 47738494Sobrien * While map is out of date, keep re-syncing. 47838494Sobrien */ 47938494Sobrienstatic int 48038494Sobriensearch_map(mnt_map *m, char *key, char **valp) 48138494Sobrien{ 48238494Sobrien int rc; 48338494Sobrien 48438494Sobrien do { 48538494Sobrien rc = (*m->search) (m, m->map_name, key, valp, &m->modify); 48638494Sobrien if (rc < 0) { 48738494Sobrien plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name); 48838494Sobrien mapc_sync(m); 48938494Sobrien } 49038494Sobrien } while (rc < 0); 49138494Sobrien 49238494Sobrien return rc; 49338494Sobrien} 49438494Sobrien 49538494Sobrien 49638494Sobrien/* 49738494Sobrien * Do a wildcard lookup in the map and 49838494Sobrien * save the result. 49938494Sobrien */ 50038494Sobrienstatic void 50138494Sobrienmapc_find_wildcard(mnt_map *m) 50238494Sobrien{ 50338494Sobrien /* 50438494Sobrien * Attempt to find the wildcard entry 50538494Sobrien */ 50638494Sobrien int rc = search_map(m, wildcard, &m->wildcard); 50738494Sobrien 50838494Sobrien if (rc != 0) 50938494Sobrien m->wildcard = 0; 51038494Sobrien} 51138494Sobrien 51238494Sobrien 51338494Sobrien/* 51452894Sobrien * Do a map reload. 51552894Sobrien * Attempt to reload without losing current data by switching the hashes 51652894Sobrien * round. 517174294Sobrien * If reloading was needed and succeeded, return 1; else return 0. 51838494Sobrien */ 519174294Sobrienstatic int 52038494Sobrienmapc_reload_map(mnt_map *m) 52138494Sobrien{ 522174294Sobrien int error, ret = 0; 52352894Sobrien kv *maphash[NKVHASH], *tmphash[NKVHASH]; 52482794Sobrien time_t t; 52538494Sobrien 52682794Sobrien error = (*m->mtime) (m, m->map_name, &t); 52782794Sobrien if (error) { 52882794Sobrien t = m->modify; 52982794Sobrien } 53082794Sobrien 53152894Sobrien /* 53252894Sobrien * skip reloading maps that have not been modified, unless 53352894Sobrien * amq -f was used (do_mapc_reload is 0) 53452894Sobrien */ 53552894Sobrien if (m->reloads != 0 && do_mapc_reload != 0) { 53682794Sobrien if (t <= m->modify) { 53752894Sobrien plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name); 53852894Sobrien dlog("map %s last load time is %d, last modify time is %d", 53952894Sobrien m->map_name, (int) m->modify, (int) t); 540174294Sobrien return ret; 54152894Sobrien } 54252894Sobrien } 54352894Sobrien 54452894Sobrien /* copy the old hash and zero the map */ 54552894Sobrien memcpy((voidp) maphash, (voidp) m->kvhash, sizeof(m->kvhash)); 54652894Sobrien memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); 54752894Sobrien 54838494Sobrien dlog("calling map reload on %s", m->map_name); 54938494Sobrien error = (*m->reload) (m, m->map_name, mapc_add_kv); 55052894Sobrien if (error) { 55152894Sobrien if (m->reloads == 0) 55252894Sobrien plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name); 55352894Sobrien else 55452894Sobrien plog(XLOG_ERROR, "reload of map %s failed - using old values", 55552894Sobrien m->map_name); 55652894Sobrien mapc_clear(m); 55752894Sobrien memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash)); 55852894Sobrien } else { 55952894Sobrien if (m->reloads++ == 0) 56052894Sobrien plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name); 56152894Sobrien else 56252894Sobrien plog(XLOG_INFO, "reload #%d of map %s succeeded", 56352894Sobrien m->reloads, m->map_name); 56452894Sobrien memcpy((voidp) tmphash, (voidp) m->kvhash, sizeof(m->kvhash)); 56552894Sobrien memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash)); 56652894Sobrien mapc_clear(m); 56752894Sobrien memcpy((voidp) m->kvhash, (voidp) tmphash, sizeof(m->kvhash)); 56882794Sobrien m->modify = t; 569174294Sobrien ret = 1; 57052894Sobrien } 57138494Sobrien m->wildcard = 0; 57238494Sobrien 57338494Sobrien dlog("calling mapc_search for wildcard"); 57438494Sobrien error = mapc_search(m, wildcard, &m->wildcard); 57538494Sobrien if (error) 57638494Sobrien m->wildcard = 0; 577174294Sobrien return ret; 57838494Sobrien} 57938494Sobrien 58038494Sobrien 58138494Sobrien/* 58238494Sobrien * Create a new map 58338494Sobrien */ 58438494Sobrienstatic mnt_map * 58538494Sobrienmapc_create(char *map, char *opt, const char *type) 58638494Sobrien{ 58738494Sobrien mnt_map *m = ALLOC(struct mnt_map); 58838494Sobrien map_type *mt; 589174294Sobrien time_t modify = 0; 59038494Sobrien int alloc = 0; 59138494Sobrien 59238494Sobrien cmdoption(opt, mapc_opt, &alloc); 59338494Sobrien 59438494Sobrien /* 59538494Sobrien * If using a configuration file, and the map_type is defined, then look 59638494Sobrien * for it, in the maptypes array. If found, initialize the map using that 59738494Sobrien * map_type. If not found, return error. If no map_type was defined, 59838494Sobrien * default to cycling through all maptypes. 59938494Sobrien */ 60038494Sobrien if (use_conf_file && type) { 60138494Sobrien /* find what type of map this one is */ 60238494Sobrien for (mt = maptypes; 60338494Sobrien mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); 60438494Sobrien mt++) { 60538494Sobrien if (STREQ(type, mt->name)) { 60682794Sobrien plog(XLOG_INFO, "initializing amd.conf map %s of type %s", map, type); 60738494Sobrien if ((*mt->init) (m, map, &modify) == 0) { 60838494Sobrien break; 60938494Sobrien } else { 61038494Sobrien plog(XLOG_ERROR, "failed to initialize map %s", map); 61138494Sobrien error_init(m, map, &modify); 61238494Sobrien break; 61338494Sobrien } 61438494Sobrien } 61538494Sobrien } /* end of "for (mt =" loop */ 61638494Sobrien 61738494Sobrien } else { /* cycle through all known maptypes */ 61838494Sobrien 61938494Sobrien /* 62038494Sobrien * not using amd conf file or using it by w/o specifying map type 62138494Sobrien */ 62238494Sobrien for (mt = maptypes; 62338494Sobrien mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); 62438494Sobrien mt++) { 62538494Sobrien dlog("trying to initialize map %s of type %s ...", map, mt->name); 62638494Sobrien if ((*mt->init) (m, map, &modify) == 0) { 62738494Sobrien break; 62838494Sobrien } 62938494Sobrien } 63038494Sobrien } /* end of "if (use_conf_file && (colpos = strchr ..." statement */ 63138494Sobrien 63238494Sobrien /* assert: mt in maptypes */ 63338494Sobrien 63438494Sobrien m->flags = alloc & ~MAPC_CACHE_MASK; 63538494Sobrien alloc &= MAPC_CACHE_MASK; 63638494Sobrien 63738494Sobrien if (alloc == MAPC_DFLT) 63838494Sobrien alloc = mt->def_alloc; 63938494Sobrien 64038494Sobrien switch (alloc) { 64138494Sobrien default: 64238494Sobrien plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt); 64338494Sobrien alloc = MAPC_INC; 64442629Sobrien /* fall-through... */ 64538494Sobrien case MAPC_NONE: 64638494Sobrien case MAPC_INC: 64738494Sobrien case MAPC_ROOT: 64838494Sobrien break; 64938494Sobrien 65038494Sobrien case MAPC_ALL: 65138494Sobrien /* 65238494Sobrien * If there is no support for reload and it was requested 65338494Sobrien * then back off to incremental instead. 65438494Sobrien */ 65538494Sobrien if (mt->reload == error_reload) { 65638494Sobrien plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name); 65738494Sobrien alloc = MAPC_INC; 65838494Sobrien } 65938494Sobrien break; 66038494Sobrien 66138494Sobrien#ifdef HAVE_REGEXEC 66238494Sobrien case MAPC_RE: 66338494Sobrien if (mt->reload == error_reload) { 66438494Sobrien plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name); 66538494Sobrien mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1]; 66638494Sobrien /* assert: mt->name == "error" */ 66738494Sobrien } 66838494Sobrien break; 66938494Sobrien#endif /* HAVE_REGEXEC */ 67038494Sobrien } 67138494Sobrien 67238494Sobrien dlog("Map for %s coming from maptype %s", map, mt->name); 67338494Sobrien 67438494Sobrien m->alloc = alloc; 67538494Sobrien m->reload = mt->reload; 67638494Sobrien m->isup = mt->isup; 67738494Sobrien m->modify = modify; 67838494Sobrien m->search = alloc >= MAPC_ALL ? error_search : mt->search; 67938494Sobrien m->mtime = mt->mtime; 68038494Sobrien memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); 68138494Sobrien m->map_name = strdup(map); 68238494Sobrien m->refc = 1; 68338494Sobrien m->wildcard = 0; 68452894Sobrien m->reloads = 0; 685174294Sobrien /* Unfortunately with current code structure, this cannot be initialized here */ 686174294Sobrien m->cfm = NULL; 68738494Sobrien 68838494Sobrien /* 68938494Sobrien * synchronize cache with reality 69038494Sobrien */ 69138494Sobrien mapc_sync(m); 69238494Sobrien 69338494Sobrien return m; 69438494Sobrien} 69538494Sobrien 69638494Sobrien 69738494Sobrien/* 69838494Sobrien * Free the cached data in a map 69938494Sobrien */ 70038494Sobrienstatic void 70138494Sobrienmapc_clear(mnt_map *m) 70238494Sobrien{ 70338494Sobrien int i; 70438494Sobrien 70538494Sobrien /* 70638494Sobrien * For each of the hash slots, chain 70738494Sobrien * along free'ing the data. 70838494Sobrien */ 70938494Sobrien for (i = 0; i < NKVHASH; i++) { 71038494Sobrien kv *k = m->kvhash[i]; 71138494Sobrien while (k) { 71238494Sobrien kv *n = k->next; 71338494Sobrien XFREE(k->key); 71438494Sobrien if (k->val) 71538494Sobrien XFREE(k->val); 71638494Sobrien XFREE(k); 71738494Sobrien k = n; 71838494Sobrien } 71938494Sobrien } 72038494Sobrien 72138494Sobrien /* 72238494Sobrien * Zero the hash slots 72338494Sobrien */ 72438494Sobrien memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); 72538494Sobrien 72638494Sobrien /* 72738494Sobrien * Free the wildcard if it exists 72838494Sobrien */ 72938494Sobrien if (m->wildcard) { 73038494Sobrien XFREE(m->wildcard); 73138494Sobrien m->wildcard = 0; 73238494Sobrien } 73338494Sobrien} 73438494Sobrien 73538494Sobrien 73638494Sobrien/* 73738494Sobrien * Find a map, or create one if it does not exist 73838494Sobrien */ 73938494Sobrienmnt_map * 74038494Sobrienmapc_find(char *map, char *opt, const char *maptype) 74138494Sobrien{ 74238494Sobrien mnt_map *m; 74338494Sobrien 74438494Sobrien /* 74538494Sobrien * Search the list of known maps to see if 74638494Sobrien * it has already been loaded. If it is found 74738494Sobrien * then return a duplicate reference to it. 74838494Sobrien * Otherwise make a new map as required and 74938494Sobrien * add it to the list of maps 75038494Sobrien */ 75138494Sobrien ITER(m, mnt_map, &map_list_head) 752174294Sobrien if (STREQ(m->map_name, map)) 75338494Sobrien return mapc_dup(m); 75438494Sobrien m = mapc_create(map, opt, maptype); 75538494Sobrien ins_que(&m->hdr, &map_list_head); 75638494Sobrien 75738494Sobrien return m; 75838494Sobrien} 75938494Sobrien 76038494Sobrien 76138494Sobrien/* 76238494Sobrien * Free a map. 76338494Sobrien */ 76438494Sobrienvoid 765174294Sobrienmapc_free(opaque_t arg) 76638494Sobrien{ 767174294Sobrien mnt_map *m = (mnt_map *) arg; 76838494Sobrien 76938494Sobrien /* 77038494Sobrien * Decrement the reference count. 77138494Sobrien * If the reference count hits zero 77238494Sobrien * then throw the map away. 77338494Sobrien */ 77438494Sobrien if (m && --m->refc == 0) { 77538494Sobrien mapc_clear(m); 77638494Sobrien XFREE(m->map_name); 77738494Sobrien rem_que(&m->hdr); 77838494Sobrien XFREE(m); 77938494Sobrien } 78038494Sobrien} 78138494Sobrien 78238494Sobrien 78338494Sobrien/* 78438494Sobrien * Search the map for the key. Put a safe (malloc'ed) copy in *pval or 78538494Sobrien * return an error code 78638494Sobrien */ 78738494Sobrienstatic int 78838494Sobrienmapc_meta_search(mnt_map *m, char *key, char **pval, int recurse) 78938494Sobrien{ 79038494Sobrien int error = 0; 79138494Sobrien kv *k = 0; 79238494Sobrien 79338494Sobrien /* 79438494Sobrien * Firewall 79538494Sobrien */ 79638494Sobrien if (!m) { 79738494Sobrien plog(XLOG_ERROR, "Null map request for %s", key); 79838494Sobrien return ENOENT; 79938494Sobrien } 80082794Sobrien 80138494Sobrien if (m->flags & MAPC_SYNC) { 80238494Sobrien /* 80338494Sobrien * Get modify time... 80438494Sobrien */ 80538494Sobrien time_t t; 80638494Sobrien error = (*m->mtime) (m, m->map_name, &t); 80738494Sobrien if (error || t > m->modify) { 80838494Sobrien plog(XLOG_INFO, "Map %s is out of date", m->map_name); 80938494Sobrien mapc_sync(m); 81038494Sobrien } 81138494Sobrien } 81238494Sobrien 81338494Sobrien if (!MAPC_ISRE(m)) { 81438494Sobrien /* 81538494Sobrien * Compute the hash table offset 81638494Sobrien */ 81738494Sobrien k = m->kvhash[kvhash_of(key)]; 81838494Sobrien 81938494Sobrien /* 82038494Sobrien * Scan the linked list for the key 82138494Sobrien */ 82238494Sobrien while (k && !FSTREQ(k->key, key)) 82338494Sobrien k = k->next; 82438494Sobrien 82538494Sobrien } 82638494Sobrien 82738494Sobrien#ifdef HAVE_REGEXEC 82838494Sobrien else if (recurse == MREC_FULL) { 82938494Sobrien /* 83038494Sobrien * Try for an RE match against the entire map. 83138494Sobrien * Note that this will be done in a "random" 83238494Sobrien * order. 83338494Sobrien */ 83438494Sobrien int i; 83538494Sobrien 83638494Sobrien for (i = 0; i < NKVHASH; i++) { 83738494Sobrien k = m->kvhash[i]; 83838494Sobrien while (k) { 83938494Sobrien int retval; 84038494Sobrien 84138494Sobrien /* XXX: this code was recently ported, and must be tested -Erez */ 84238494Sobrien retval = regexec(&k->re, key, 0, 0, 0); 84338494Sobrien if (retval == 0) { /* succeeded */ 84438494Sobrien break; 84538494Sobrien } else { /* failed to match, log error */ 84638494Sobrien char errstr[256]; 84738494Sobrien 84838494Sobrien errstr[0] = '\0'; 84938494Sobrien regerror(retval, &k->re, errstr, 256); 85038494Sobrien plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s", 85138494Sobrien key, k->key, errstr); 85238494Sobrien } 85338494Sobrien k = k->next; 85438494Sobrien } 85538494Sobrien if (k) 85638494Sobrien break; 85738494Sobrien } 85838494Sobrien } 85938494Sobrien#endif /* HAVE_REGEXEC */ 86038494Sobrien 86138494Sobrien /* 86238494Sobrien * If found then take a copy 86338494Sobrien */ 86438494Sobrien if (k) { 86538494Sobrien if (k->val) 86638494Sobrien *pval = strdup(k->val); 86738494Sobrien else 86838494Sobrien error = ENOENT; 86938494Sobrien } else if (m->alloc >= MAPC_ALL) { 87038494Sobrien /* 87138494Sobrien * If the entire map is cached then this 87238494Sobrien * key does not exist. 87338494Sobrien */ 87438494Sobrien error = ENOENT; 87538494Sobrien } else { 87638494Sobrien /* 87738494Sobrien * Otherwise search the map. If we are 87838494Sobrien * in incremental mode then add the key 87938494Sobrien * to the cache. 88038494Sobrien */ 88138494Sobrien error = search_map(m, key, pval); 88238494Sobrien if (!error && m->alloc == MAPC_INC) 88338494Sobrien mapc_add_kv(m, strdup(key), strdup(*pval)); 88438494Sobrien } 88538494Sobrien 88638494Sobrien /* 88738494Sobrien * If an error, and a wildcard exists, 88838494Sobrien * and the key is not internal then 88938494Sobrien * return a copy of the wildcard. 89038494Sobrien */ 89138494Sobrien if (error > 0) { 89238494Sobrien if (recurse == MREC_FULL && !MAPC_ISRE(m)) { 89338494Sobrien char wildname[MAXPATHLEN]; 89438494Sobrien char *subp; 89538494Sobrien if (*key == '/') 89638494Sobrien return error; 89738494Sobrien /* 89838494Sobrien * Keep chopping sub-directories from the RHS 89938494Sobrien * and replacing with "/ *" and repeat the lookup. 90038494Sobrien * For example: 90138494Sobrien * "src/gnu/gcc" -> "src / gnu / *" -> "src / *" 90238494Sobrien */ 903174294Sobrien xstrlcpy(wildname, key, sizeof(wildname)); 90438494Sobrien while (error && (subp = strrchr(wildname, '/'))) { 905174294Sobrien /* 906174294Sobrien * sizeof space left in subp is sizeof wildname minus what's left 907174294Sobrien * after the strchr above returned a pointer inside wildname into 908174294Sobrien * subp. 909174294Sobrien */ 910174294Sobrien xstrlcpy(subp, "/*", sizeof(wildname) - (subp - wildname)); 91138494Sobrien dlog("mapc recurses on %s", wildname); 91238494Sobrien error = mapc_meta_search(m, wildname, pval, MREC_PART); 91338494Sobrien if (error) 91438494Sobrien *subp = 0; 91538494Sobrien } 91638494Sobrien 91738494Sobrien if (error > 0 && m->wildcard) { 91838494Sobrien *pval = strdup(m->wildcard); 91938494Sobrien error = 0; 92038494Sobrien } 92138494Sobrien } 92238494Sobrien } 92338494Sobrien return error; 92438494Sobrien} 92538494Sobrien 92638494Sobrien 92738494Sobrienint 92838494Sobrienmapc_search(mnt_map *m, char *key, char **pval) 92938494Sobrien{ 93038494Sobrien return mapc_meta_search(m, key, pval, MREC_FULL); 93138494Sobrien} 93238494Sobrien 93338494Sobrien 93438494Sobrien/* 93538494Sobrien * Get map cache in sync with physical representation 93638494Sobrien */ 93738494Sobrienstatic void 93838494Sobrienmapc_sync(mnt_map *m) 93938494Sobrien{ 940174294Sobrien int need_mtime_update = 0; 94138494Sobrien 942174294Sobrien if (m->alloc == MAPC_ROOT) 943174294Sobrien return; /* nothing to do */ 944174294Sobrien 945174294Sobrien /* do not clear map if map service is down */ 946174294Sobrien if (m->isup) { 947174294Sobrien if (!((*m->isup)(m, m->map_name))) { 948174294Sobrien plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name); 949174294Sobrien return; 95038494Sobrien } 951174294Sobrien } 95238494Sobrien 953174294Sobrien if (m->alloc >= MAPC_ALL) { 954174294Sobrien /* mapc_reload_map() always works */ 955174294Sobrien need_mtime_update = mapc_reload_map(m); 956174294Sobrien } else { 957174294Sobrien mapc_clear(m); 958174294Sobrien /* 959174294Sobrien * Attempt to find the wildcard entry 960174294Sobrien */ 961174294Sobrien mapc_find_wildcard(m); 962174294Sobrien need_mtime_update = 1; /* because mapc_clear always works */ 963174294Sobrien } 964174294Sobrien 965174294Sobrien /* 966174294Sobrien * To be safe, update the mtime of the mnt_map's own node, so that the 967174294Sobrien * kernel will flush all of its cached entries. 968174294Sobrien */ 969174294Sobrien if (need_mtime_update && m->cfm) { 970174294Sobrien am_node *mp = find_ap(m->cfm->cfm_dir); 971174294Sobrien if (mp) { 972174294Sobrien clocktime(&mp->am_fattr.na_mtime); 97352894Sobrien } else { 974174294Sobrien plog(XLOG_ERROR, "cannot find map %s to update its mtime", 975174294Sobrien m->cfm->cfm_dir); 97652894Sobrien } 97738494Sobrien } 97838494Sobrien} 97938494Sobrien 98038494Sobrien 98138494Sobrien/* 98238494Sobrien * Reload all the maps 98338494Sobrien * Called when Amd gets hit by a SIGHUP. 98438494Sobrien */ 98538494Sobrienvoid 98638494Sobrienmapc_reload(void) 98738494Sobrien{ 98838494Sobrien mnt_map *m; 98938494Sobrien 99038494Sobrien /* 99138494Sobrien * For all the maps, 99238494Sobrien * Throw away the existing information. 99338494Sobrien * Do a reload 99438494Sobrien * Find the wildcard 99538494Sobrien */ 99638494Sobrien ITER(m, mnt_map, &map_list_head) 99738494Sobrien mapc_sync(m); 99838494Sobrien} 99938494Sobrien 100038494Sobrien 100138494Sobrien/* 100238494Sobrien * Root map. 100338494Sobrien * The root map is used to bootstrap amd. 100438494Sobrien * All the require top-level mounts are added 100538494Sobrien * into the root map and then the map is iterated 100638494Sobrien * and a lookup is done on all the mount points. 100738494Sobrien * This causes the top level mounts to be automounted. 100838494Sobrien */ 100938494Sobrienstatic int 101038494Sobrienroot_init(mnt_map *m, char *map, time_t *tp) 101138494Sobrien{ 1012174294Sobrien *tp = clocktime(NULL); 101338494Sobrien return STREQ(map, ROOT_MAP) ? 0 : ENOENT; 101438494Sobrien} 101538494Sobrien 101638494Sobrien 101738494Sobrien/* 101838494Sobrien * Add a new entry to the root map 101938494Sobrien * 102038494Sobrien * dir - directory (key) 102138494Sobrien * opts - mount options 102238494Sobrien * map - map name 102338494Sobrien * cfm - optional amd configuration file map section structure 102438494Sobrien */ 102538494Sobrienvoid 102638494Sobrienroot_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm) 102738494Sobrien{ 102838494Sobrien char str[MAXPATHLEN]; 102938494Sobrien 103038494Sobrien /* 103138494Sobrien * First make sure we have a root map to talk about... 103238494Sobrien */ 103338494Sobrien if (!root_map) 103438494Sobrien root_map = mapc_find(ROOT_MAP, "mapdefault", NULL); 103538494Sobrien 103638494Sobrien /* 103738494Sobrien * Then add the entry... 103838494Sobrien */ 103938494Sobrien 104038494Sobrien /* 104138494Sobrien * Here I plug in the code to process other amd.conf options like 104238494Sobrien * map_type, search_path, and flags (browsable_dirs, mount_type). 104338494Sobrien */ 104438494Sobrien 104538494Sobrien if (cfm) { 104638494Sobrien if (map) { 1047174294Sobrien xsnprintf(str, sizeof(str), 1048174294Sobrien "cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"", 1049174294Sobrien cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "nfs", 1050174294Sobrien get_full_path(map, cfm->cfm_search_path, cfm->cfm_type)); 105138494Sobrien if (opts && opts[0] != '\0') { 1052174294Sobrien xstrlcat(str, ";", sizeof(str)); 1053174294Sobrien xstrlcat(str, opts, sizeof(str)); 105438494Sobrien } 105538494Sobrien if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL) 1056174294Sobrien xstrlcat(str, ";opts:=rw,fullybrowsable", sizeof(str)); 105738494Sobrien if (cfm->cfm_flags & CFM_BROWSABLE_DIRS) 1058174294Sobrien xstrlcat(str, ";opts:=rw,browsable", sizeof(str)); 105938494Sobrien if (cfm->cfm_type) { 1060174294Sobrien xstrlcat(str, ";maptype:=", sizeof(str)); 1061174294Sobrien xstrlcat(str, cfm->cfm_type, sizeof(str)); 106238494Sobrien } 106338494Sobrien } else { 1064174294Sobrien xstrlcpy(str, opts, sizeof(str)); 106538494Sobrien } 106638494Sobrien } else { 106738494Sobrien if (map) 1068174294Sobrien xsnprintf(str, sizeof(str), 1069174294Sobrien "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s", 1070174294Sobrien map, opts ? opts : ""); 107138494Sobrien else 1072174294Sobrien xstrlcpy(str, opts, sizeof(str)); 107338494Sobrien } 107438494Sobrien mapc_repl_kv(root_map, strdup((char *)dir), strdup(str)); 107538494Sobrien} 107638494Sobrien 107738494Sobrien 107838494Sobrienint 1079174294Sobrienmapc_keyiter(mnt_map *m, key_fun *fn, opaque_t arg) 108038494Sobrien{ 108138494Sobrien int i; 108238494Sobrien int c = 0; 108338494Sobrien 108438494Sobrien for (i = 0; i < NKVHASH; i++) { 108538494Sobrien kv *k = m->kvhash[i]; 108638494Sobrien while (k) { 108738494Sobrien (*fn) (k->key, arg); 108838494Sobrien k = k->next; 108938494Sobrien c++; 109038494Sobrien } 109138494Sobrien } 109238494Sobrien 109338494Sobrien return c; 109438494Sobrien} 109538494Sobrien 109638494Sobrien 109738494Sobrien/* 109838494Sobrien * Iterate on the root map and call (*fn)() on the key of all the nodes. 1099174294Sobrien * Returns the number of entries in the root map. 110038494Sobrien */ 110138494Sobrienint 1102174294Sobrienroot_keyiter(key_fun *fn, opaque_t arg) 110338494Sobrien{ 110438494Sobrien if (root_map) { 110538494Sobrien int c = mapc_keyiter(root_map, fn, arg); 110638494Sobrien return c; 110738494Sobrien } 110838494Sobrien 110938494Sobrien return 0; 111038494Sobrien} 111138494Sobrien 111238494Sobrien 111338494Sobrien/* 111438494Sobrien * Error map 111538494Sobrien */ 111638494Sobrienstatic int 111738494Sobrienerror_init(mnt_map *m, char *map, time_t *tp) 111838494Sobrien{ 111938494Sobrien plog(XLOG_USER, "No source data for map %s", map); 112038494Sobrien *tp = 0; 112138494Sobrien 112238494Sobrien return 0; 112338494Sobrien} 112438494Sobrien 112538494Sobrien 112638494Sobrienstatic int 112738494Sobrienerror_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) 112838494Sobrien{ 112938494Sobrien return ENOENT; 113038494Sobrien} 113138494Sobrien 113238494Sobrien 113338494Sobrienstatic int 113438494Sobrienerror_reload(mnt_map *m, char *map, add_fn *fn) 113538494Sobrien{ 113638494Sobrien return ENOENT; 113738494Sobrien} 113838494Sobrien 113938494Sobrien 114038494Sobrienstatic int 114138494Sobrienerror_mtime(mnt_map *m, char *map, time_t *tp) 114238494Sobrien{ 114338494Sobrien *tp = 0; 114438494Sobrien 114538494Sobrien return 0; 114638494Sobrien} 114738494Sobrien 114838494Sobrien 114938494Sobrien/* 115038494Sobrien * Return absolute path of map, searched in a type-specific path. 115138494Sobrien * Note: uses a static buffer for returned data. 115238494Sobrien */ 115338494Sobrienstatic const char * 115438494Sobrienget_full_path(const char *map, const char *path, const char *type) 115538494Sobrien{ 115638494Sobrien char component[MAXPATHLEN], *str; 115738494Sobrien static char full_path[MAXPATHLEN]; 115838494Sobrien int len; 115938494Sobrien 116038494Sobrien /* for now, only file-type search paths are implemented */ 116138494Sobrien if (type && !STREQ(type, "file")) 116238494Sobrien return map; 116338494Sobrien 116438494Sobrien /* if null map, return it */ 116538494Sobrien if (!map) 116638494Sobrien return map; 116738494Sobrien 116838494Sobrien /* if map includes a '/', return it (absolute or relative path) */ 116938494Sobrien if (strchr(map, '/')) 117038494Sobrien return map; 117138494Sobrien 117238494Sobrien /* if path is empty, return map */ 117338494Sobrien if (!path) 117438494Sobrien return map; 117538494Sobrien 117638494Sobrien /* now break path into components, and search in each */ 1177174294Sobrien xstrlcpy(component, path, sizeof(component)); 117838494Sobrien 117938494Sobrien str = strtok(component, ":"); 118038494Sobrien do { 1181174294Sobrien xstrlcpy(full_path, str, sizeof(full_path)); 118238494Sobrien len = strlen(full_path); 118338494Sobrien if (full_path[len - 1] != '/') /* add trailing "/" if needed */ 1184174294Sobrien xstrlcat(full_path, "/", sizeof(full_path)); 1185174294Sobrien xstrlcat(full_path, map, sizeof(full_path)); 118638494Sobrien if (access(full_path, R_OK) == 0) 118738494Sobrien return full_path; 118838494Sobrien str = strtok(NULL, ":"); 118938494Sobrien } while (str); 119038494Sobrien 119138494Sobrien return map; /* if found nothing, return map */ 119238494Sobrien} 1193