/* $NetBSD: mapc.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $ */ /* * Copyright (c) 1997-2014 Erez Zadok * Copyright (c) 1989 Jan-Simon Pendry * Copyright (c) 1989 Imperial College of Science, Technology & Medicine * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry at Imperial College, London. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * File: am-utils/amd/mapc.c * */ /* * Mount map cache */ #ifdef HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include /* * Make a duplicate reference to an existing map */ #define mapc_dup(m) ((m)->refc++, (m)) /* * Map cache types * default, none, incremental, all, regexp * MAPC_RE implies MAPC_ALL and must be numerically * greater. */ #define MAPC_DFLT 0x000 #define MAPC_NONE 0x001 #define MAPC_INC 0x002 #define MAPC_ROOT 0x004 #define MAPC_ALL 0x010 #define MAPC_CACHE_MASK 0x0ff #define MAPC_SYNC 0x100 #ifdef HAVE_REGEXEC # define MAPC_RE 0x020 # define MAPC_ISRE(m) ((m)->alloc == MAPC_RE) #else /* not HAVE_REGEXEC */ # define MAPC_ISRE(m) FALSE #endif /* not HAVE_REGEXEC */ /* * Lookup recursion */ #define MREC_FULL 2 #define MREC_PART 1 #define MREC_NONE 0 static struct opt_tab mapc_opt[] = { {"all", MAPC_ALL}, {"default", MAPC_DFLT}, {"inc", MAPC_INC}, {"mapdefault", MAPC_DFLT}, {"none", MAPC_NONE}, #ifdef HAVE_REGEXEC {"re", MAPC_RE}, {"regexp", MAPC_RE}, #endif /* HAVE_REGEXEC */ {"sync", MAPC_SYNC}, {NULL, 0} }; /* * Wildcard key */ static char wildcard[] = "*"; /* * Map type */ typedef struct map_type map_type; struct map_type { char *name; /* Name of this map type */ init_fn *init; /* Initialization */ reload_fn *reload; /* Reload or fill */ isup_fn *isup; /* Is service up or not? (1=up, 0=down) */ search_fn *search; /* Search for new entry */ mtime_fn *mtime; /* Find modify time */ int def_alloc; /* Default allocation mode */ }; /* * Map for root node */ static mnt_map *root_map; /* * List of known maps */ qelem map_list_head = {&map_list_head, &map_list_head}; /* * Configuration */ /* forward definitions */ static const char *get_full_path(const char *map, const char *path, const char *type); static int mapc_meta_search(mnt_map *, char *, char **, int); static void mapc_sync(mnt_map *); static void mapc_clear(mnt_map *); static void mapc_clear_kvhash(kv **); /* ROOT MAP */ static int root_init(mnt_map *, char *, time_t *); /* ERROR MAP */ static int error_init(mnt_map *, char *, time_t *); static int error_reload(mnt_map *, char *, add_fn *); static int error_search(mnt_map *, char *, char *, char **, time_t *); static int error_mtime(mnt_map *, char *, time_t *); /* PASSWD MAPS */ #ifdef HAVE_MAP_PASSWD extern int passwd_init(mnt_map *, char *, time_t *); extern int passwd_search(mnt_map *, char *, char *, char **, time_t *); #endif /* HAVE_MAP_PASSWD */ /* HESIOD MAPS */ #ifdef HAVE_MAP_HESIOD extern int amu_hesiod_init(mnt_map *, char *map, time_t *tp); extern int hesiod_isup(mnt_map *, char *); extern int hesiod_search(mnt_map *, char *, char *, char **, time_t *); #endif /* HAVE_MAP_HESIOD */ /* LDAP MAPS */ #ifdef HAVE_MAP_LDAP extern int amu_ldap_init(mnt_map *, char *map, time_t *tp); extern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *); extern int amu_ldap_mtime(mnt_map *, char *, time_t *); #endif /* HAVE_MAP_LDAP */ /* UNION MAPS */ #ifdef HAVE_MAP_UNION extern int union_init(mnt_map *, char *, time_t *); extern int union_search(mnt_map *, char *, char *, char **, time_t *); extern int union_reload(mnt_map *, char *, add_fn *); #endif /* HAVE_MAP_UNION */ /* Network Information Service PLUS (NIS+) */ #ifdef HAVE_MAP_NISPLUS extern int nisplus_init(mnt_map *, char *, time_t *); extern int nisplus_reload(mnt_map *, char *, add_fn *); extern int nisplus_search(mnt_map *, char *, char *, char **, time_t *); extern int nisplus_mtime(mnt_map *, char *, time_t *); #endif /* HAVE_MAP_NISPLUS */ /* Network Information Service (YP, Yellow Pages) */ #ifdef HAVE_MAP_NIS extern int nis_init(mnt_map *, char *, time_t *); extern int nis_reload(mnt_map *, char *, add_fn *); extern int nis_isup(mnt_map *, char *); extern int nis_search(mnt_map *, char *, char *, char **, time_t *); extern int nis_mtime(mnt_map *, char *, time_t *); #endif /* HAVE_MAP_NIS */ /* NDBM MAPS */ #ifdef HAVE_MAP_NDBM extern int ndbm_init(mnt_map *, char *, time_t *); extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *); extern int ndbm_mtime(mnt_map *, char *, time_t *); #endif /* HAVE_MAP_NDBM */ /* FILE MAPS */ #ifdef HAVE_MAP_FILE extern int file_init_or_mtime(mnt_map *, char *, time_t *); extern int file_reload(mnt_map *, char *, add_fn *); extern int file_search(mnt_map *, char *, char *, char **, time_t *); #endif /* HAVE_MAP_FILE */ /* EXECUTABLE MAPS */ #ifdef HAVE_MAP_EXEC extern int exec_init(mnt_map *, char *, time_t *); extern int exec_search(mnt_map *, char *, char *, char **, time_t *); #endif /* HAVE_MAP_EXEC */ /* Sun-syntax MAPS */ #ifdef HAVE_MAP_SUN /* XXX: fill in */ #endif /* HAVE_MAP_SUN */ /* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */ static map_type maptypes[] = { { "root", root_init, error_reload, NULL, /* isup function */ error_search, error_mtime, MAPC_ROOT }, #ifdef HAVE_MAP_PASSWD { "passwd", passwd_init, error_reload, NULL, /* isup function */ passwd_search, error_mtime, MAPC_INC }, #endif /* HAVE_MAP_PASSWD */ #ifdef HAVE_MAP_HESIOD { "hesiod", amu_hesiod_init, error_reload, hesiod_isup, /* is Hesiod up or not? */ hesiod_search, error_mtime, MAPC_INC }, #endif /* HAVE_MAP_HESIOD */ #ifdef HAVE_MAP_LDAP { "ldap", amu_ldap_init, error_reload, NULL, /* isup function */ amu_ldap_search, amu_ldap_mtime, MAPC_INC }, #endif /* HAVE_MAP_LDAP */ #ifdef HAVE_MAP_UNION { "union", union_init, union_reload, NULL, /* isup function */ union_search, error_mtime, MAPC_ALL }, #endif /* HAVE_MAP_UNION */ #ifdef HAVE_MAP_NISPLUS { "nisplus", nisplus_init, nisplus_reload, NULL, /* isup function */ nisplus_search, nisplus_mtime, MAPC_INC }, #endif /* HAVE_MAP_NISPLUS */ #ifdef HAVE_MAP_NIS { "nis", nis_init, nis_reload, nis_isup, /* is NIS up or not? */ nis_search, nis_mtime, MAPC_ALL }, #endif /* HAVE_MAP_NIS */ #ifdef HAVE_MAP_NDBM { "ndbm", ndbm_init, error_reload, NULL, /* isup function */ ndbm_search, ndbm_mtime, MAPC_INC }, #endif /* HAVE_MAP_NDBM */ #ifdef HAVE_MAP_FILE { "file", file_init_or_mtime, file_reload, NULL, /* isup function */ file_search, file_init_or_mtime, MAPC_ALL }, #endif /* HAVE_MAP_FILE */ #ifdef HAVE_MAP_EXEC { "exec", exec_init, error_reload, NULL, /* isup function */ exec_search, error_mtime, MAPC_INC }, #endif /* HAVE_MAP_EXEC */ #ifdef notyet /* probe function needs to be there or SEGV */ #ifdef HAVE_MAP_SUN { /* XXX: fill in */ "sun", NULL, NULL, NULL, /* isup function */ NULL, NULL, 0 }, #endif /* HAVE_MAP_SUN */ #endif { "error", error_init, error_reload, NULL, /* isup function */ error_search, error_mtime, MAPC_NONE }, }; /* * Hash function */ static u_int kvhash_of(char *key) { u_int i, j; for (i = 0; (j = *key++); i += j) ; return i % NKVHASH; } void mapc_showtypes(char *buf, size_t l) { map_type *mt=NULL, *lastmt; int linesize = 0, i; i = sizeof(maptypes) / sizeof(maptypes[0]); lastmt = maptypes + i; buf[0] = '\0'; for (mt = maptypes; mt < lastmt; mt++) { xstrlcat(buf, mt->name, l); if (mt == (lastmt-1)) break; /* if last one, don't do xstrlcat's that follows */ linesize += strlen(mt->name); if (--i > 0) { xstrlcat(buf, ", ", l); linesize += 2; } if (linesize > 54) { linesize = 0; xstrlcat(buf, "\n\t\t ", l); } } } /* * Check if a map of a certain type exists. * Return 1 (true) if exists, 0 (false) if not. */ int mapc_type_exists(const char *type) { map_type *mt; if (!type) return 0; for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) { if (STREQ(type, mt->name)) return 1; } return 0; /* not found anywhere */ } /* * Add key and val to the map m. * key and val are assumed to be safe copies */ void mapc_add_kv(mnt_map *m, char *key, char *val) { kv **h; kv *n; int hash = kvhash_of(key); #ifdef HAVE_REGEXEC regex_t re; #endif /* HAVE_REGEXEC */ dlog("add_kv: %s -> %s", key, val); if (val != NULL && strchr(val, '\n') != NULL) { /* * If the entry value contains multiple lines we need to break * them up and add them recursively. This is a workaround to * support Sun style multi-mounts. Amd converts Sun style * mulit-mounts to type:=auto. The problem is that Sun packs all * the entries on one line. When Amd does the conversion it puts * each type:=auto entry on the same line separated by '\n'. */ char *entry, *tok; /* * The first line should contain the first entry. The key for * this entry is the key passed into this function. */ if ((tok = strtok(val, "\n")) != NULL) { mapc_add_kv(m, key, xstrdup(tok)); } /* * For the rest of the entries we need to tokenize them by '\n' * and separate the keys from there entries. */ while ((tok = strtok(NULL, "\n")) != NULL) { key = tok; /* find the entry */ for (entry = key; *entry && !isspace((unsigned char)*entry); entry++); if (*entry) { *entry++ = '\0'; } mapc_add_kv(m, xstrdup(key), xstrdup(entry)); } XFREE(val); return; } #ifdef HAVE_REGEXEC if (MAPC_ISRE(m)) { char pattern[MAXPATHLEN]; int retval; /* * Make sure the string is bound to the start and end */ xsnprintf(pattern, sizeof(pattern), "^%s$", key); retval = regcomp(&re, pattern, REG_ICASE); if (retval != 0) { char errstr[256]; /* XXX: this code was recently ported, and must be tested -Erez */ errstr[0] = '\0'; regerror(retval, &re, errstr, 256); plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr); return; } } else memset(&re, 0, sizeof(re)); #endif /* HAVE_REGEXEC */ h = &m->kvhash[hash]; n = ALLOC(struct kv); n->key = key; #ifdef HAVE_REGEXEC memcpy(&n->re, &re, sizeof(regex_t)); #endif /* HAVE_REGEXEC */ n->val = val; n->next = *h; *h = n; m->nentries++; } static void mapc_repl_kv(mnt_map *m, char *key, char *val) { kv *k; /* * Compute the hash table offset */ k = m->kvhash[kvhash_of(key)]; /* * Scan the linked list for the key */ while (k && !FSTREQ(k->key, key)) k = k->next; if (k) { XFREE(k->val); k->val = val; } else { mapc_add_kv(m, key, val); } } /* * Search a map for a key. * Calls map specific search routine. * While map is out of date, keep re-syncing. */ static int search_map(mnt_map *m, char *key, char **valp) { int rc; do { rc = (*m->search) (m, m->map_name, key, valp, &m->modify); if (rc < 0) { plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name); mapc_sync(m); } } while (rc < 0); return rc; } /* * Do a wildcard lookup in the map and * save the result. */ static void mapc_find_wildcard(mnt_map *m) { /* * Attempt to find the wildcard entry */ int rc = search_map(m, wildcard, &m->wildcard); if (rc != 0) m->wildcard = NULL; } /* * Do a map reload. * Attempt to reload without losing current data by switching the hashes * round. * If reloading was needed and succeeded, return 1; else return 0. */ static int mapc_reload_map(mnt_map *m) { int error, ret = 0; kv *maphash[NKVHASH]; time_t t; error = (*m->mtime) (m, m->map_name, &t); if (error) { t = m->modify; } /* * skip reloading maps that have not been modified, unless * amq -f was used (do_mapc_reload is 0) */ if (m->reloads != 0 && do_mapc_reload != 0) { if (t <= m->modify) { plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name); dlog("map %s last load time is %d, last modify time is %d", m->map_name, (int) m->modify, (int) t); return ret; } } /* copy the old hash and zero the map */ memcpy((voidp) maphash, (voidp) m->kvhash, sizeof(m->kvhash)); memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); dlog("calling map reload on %s", m->map_name); m->nentries = 0; error = (*m->reload) (m, m->map_name, mapc_add_kv); if (error) { if (m->reloads == 0) plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name); else plog(XLOG_ERROR, "reload of map %s failed - using old values", m->map_name); mapc_clear(m); memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash)); } else { if (m->reloads++ == 0) plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name); else plog(XLOG_INFO, "reload #%d of map %s succeeded", m->reloads, m->map_name); mapc_clear_kvhash(maphash); if (m->wildcard) { XFREE(m->wildcard); m->wildcard = NULL; } m->modify = t; ret = 1; } dlog("calling mapc_search for wildcard"); error = mapc_search(m, wildcard, &m->wildcard); if (error) m->wildcard = NULL; return ret; } /* * Create a new map */ static mnt_map * mapc_create(char *map, char *opt, const char *type, const char *mntpt) { mnt_map *m = ALLOC(struct mnt_map); map_type *mt; time_t modify = 0; u_int alloc = 0; cmdoption(opt, mapc_opt, &alloc); /* * If using a configuration file, and the map_type is defined, then look * for it, in the maptypes array. If found, initialize the map using that * map_type. If not found, return error. If no map_type was defined, * default to cycling through all maptypes. */ if (use_conf_file && type) { /* find what type of map this one is */ for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) { if (STREQ(type, mt->name)) { plog(XLOG_INFO, "initializing amd.conf map %s of type %s", map, type); if ((*mt->init) (m, map, &modify) == 0) { break; } else { plog(XLOG_ERROR, "failed to initialize map %s", map); error_init(m, map, &modify); break; } } } /* end of "for (mt =" loop */ } else { /* cycle through all known maptypes */ /* * not using amd conf file or using it by w/o specifying map type */ for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) { dlog("trying to initialize map %s of type %s ...", map, mt->name); if ((*mt->init) (m, map, &modify) == 0) { break; } } } /* end of "if (use_conf_file && (colpos = strchr ..." statement */ /* assert: mt in maptypes */ m->flags = alloc & ~MAPC_CACHE_MASK; m->nentries = 0; alloc &= MAPC_CACHE_MASK; if (alloc == MAPC_DFLT) alloc = mt->def_alloc; switch (alloc) { default: plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt); alloc = MAPC_INC; /* fall-through... */ case MAPC_NONE: case MAPC_INC: case MAPC_ROOT: break; case MAPC_ALL: /* * If there is no support for reload and it was requested * then back off to incremental instead. */ if (mt->reload == error_reload) { plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name); alloc = MAPC_INC; } break; #ifdef HAVE_REGEXEC case MAPC_RE: if (mt->reload == error_reload) { plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name); mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1]; /* assert: mt->name == "error" */ } break; #endif /* HAVE_REGEXEC */ } dlog("Map for %s coming from maptype %s", map, mt->name); m->alloc = alloc; m->reload = mt->reload; m->isup = mt->isup; m->modify = modify; m->search = alloc >= MAPC_ALL ? error_search : mt->search; m->mtime = mt->mtime; memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); m->map_name = xstrdup(map); m->refc = 1; m->wildcard = NULL; m->reloads = 0; /* initialize per-map information (flags, etc.) */ m->cfm = find_cf_map(mntpt); /* * synchronize cache with reality */ mapc_sync(m); return m; } /* * Free the cached data in a map hash */ static void mapc_clear_kvhash(kv **kvhash) { int i; /* * For each of the hash slots, chain * along free'ing the data. */ for (i = 0; i < NKVHASH; i++) { kv *k = kvhash[i]; while (k) { kv *n = k->next; XFREE(k->key); XFREE(k->val); XFREE(k); k = n; } } } /* * Free the cached data in a map */ static void mapc_clear(mnt_map *m) { mapc_clear_kvhash(m->kvhash); /* * Zero the hash slots */ memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); /* * Free the wildcard if it exists */ XFREE(m->wildcard); m->wildcard = NULL; m->nentries = 0; } /* * Find a map, or create one if it does not exist */ mnt_map * mapc_find(char *map, char *opt, const char *maptype, const char *mntpt) { mnt_map *m; /* * Search the list of known maps to see if * it has already been loaded. If it is found * then return a duplicate reference to it. * Otherwise make a new map as required and * add it to the list of maps */ ITER(m, mnt_map, &map_list_head) if (STREQ(m->map_name, map)) return mapc_dup(m); m = mapc_create(map, opt, maptype, mntpt); ins_que(&m->hdr, &map_list_head); return m; } /* * Free a map. */ void mapc_free(opaque_t arg) { mnt_map *m = (mnt_map *) arg; /* * Decrement the reference count. * If the reference count hits zero * then throw the map away. */ if (m && --m->refc == 0) { mapc_clear(m); XFREE(m->map_name); rem_que(&m->hdr); XFREE(m); } } /* * Search the map for the key. Put a safe (malloc'ed) copy in *pval or * return an error code */ static int mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse) { int error = 0; kv *k = NULL; /* * Firewall */ if (!m) { plog(XLOG_ERROR, "Null map request for %s", key); return ENOENT; } if (m->flags & MAPC_SYNC) { /* * Get modify time... */ time_t t; error = (*m->mtime) (m, m->map_name, &t); if (error || t > m->modify) { plog(XLOG_INFO, "Map %s is out of date", m->map_name); mapc_sync(m); } } if (!MAPC_ISRE(m)) { /* * Compute the hash table offset */ k = m->kvhash[kvhash_of(key)]; /* * Scan the linked list for the key */ while (k && !FSTREQ(k->key, key)) k = k->next; } #ifdef HAVE_REGEXEC else if (recurse == MREC_FULL) { /* * Try for an RE match against the entire map. * Note that this will be done in a "random" * order. */ int i; for (i = 0; i < NKVHASH; i++) { k = m->kvhash[i]; while (k) { int retval; /* XXX: this code was recently ported, and must be tested -Erez */ retval = regexec(&k->re, key, 0, NULL, 0); if (retval == 0) { /* succeeded */ break; } else { /* failed to match, log error */ char errstr[256]; errstr[0] = '\0'; regerror(retval, &k->re, errstr, 256); plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s", key, k->key, errstr); } k = k->next; } if (k) break; } } #endif /* HAVE_REGEXEC */ /* * If found then take a copy */ if (k) { if (k->val) *pval = xstrdup(k->val); else error = ENOENT; } else if (m->alloc >= MAPC_ALL) { /* * If the entire map is cached then this * key does not exist. */ error = ENOENT; } else { /* * Otherwise search the map. If we are * in incremental mode then add the key * to the cache. */ error = search_map(m, key, pval); if (!error && m->alloc == MAPC_INC) mapc_add_kv(m, xstrdup(key), xstrdup(*pval)); } /* * If an error, and a wildcard exists, * and the key is not internal then * return a copy of the wildcard. */ if (error > 0) { if (recurse == MREC_FULL && !MAPC_ISRE(m)) { char wildname[MAXPATHLEN]; char *subp; if (*key == '/') return error; /* * Keep chopping sub-directories from the RHS * and replacing with "/ *" and repeat the lookup. * For example: * "src/gnu/gcc" -> "src / gnu / *" -> "src / *" */ xstrlcpy(wildname, key, sizeof(wildname)); while (error && (subp = strrchr(wildname, '/'))) { /* * sizeof space left in subp is sizeof wildname minus what's left * after the strchr above returned a pointer inside wildname into * subp. */ xstrlcpy(subp, "/*", sizeof(wildname) - (subp - wildname)); dlog("mapc recurses on %s", wildname); error = mapc_meta_search(m, wildname, pval, MREC_PART); if (error) *subp = '\0'; } if (error > 0 && m->wildcard) { *pval = xstrdup(m->wildcard); error = 0; } } } return error; } int mapc_search(mnt_map *m, char *key, char **pval) { return mapc_meta_search(m, key, pval, MREC_FULL); } /* * Get map cache in sync with physical representation */ static void mapc_sync(mnt_map *m) { int need_mtime_update = 0; if (m->alloc == MAPC_ROOT) return; /* nothing to do */ /* do not clear map if map service is down */ if (m->isup) { if (!((*m->isup)(m, m->map_name))) { plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name); return; } } if (m->alloc >= MAPC_ALL) { /* mapc_reload_map() always works */ need_mtime_update = mapc_reload_map(m); } else { mapc_clear(m); /* * Attempt to find the wildcard entry */ mapc_find_wildcard(m); need_mtime_update = 1; /* because mapc_clear always works */ } /* * To be safe, update the mtime of the mnt_map's own node, so that the * kernel will flush all of its cached entries. */ if (need_mtime_update && m->cfm) { am_node *mp = find_ap(m->cfm->cfm_dir); if (mp) { clocktime(&mp->am_fattr.na_mtime); } else { plog(XLOG_ERROR, "cannot find map %s to update its mtime", m->cfm->cfm_dir); } } } /* * Reload all the maps * Called when Amd gets hit by a SIGHUP. */ void mapc_reload(void) { mnt_map *m; /* * For all the maps, * Throw away the existing information. * Do a reload * Find the wildcard */ ITER(m, mnt_map, &map_list_head) mapc_sync(m); } /* * Root map. * The root map is used to bootstrap amd. * All the require top-level mounts are added * into the root map and then the map is iterated * and a lookup is done on all the mount points. * This causes the top level mounts to be automounted. */ static int root_init(mnt_map *m, char *map, time_t *tp) { *tp = clocktime(NULL); return STREQ(map, ROOT_MAP) ? 0 : ENOENT; } /* * Add a new entry to the root map * * dir - directory (key) * opts - mount options * map - map name * cfm - optional amd configuration file map section structure */ void root_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm) { char str[MAXPATHLEN]; /* * First make sure we have a root map to talk about... */ if (!root_map) root_map = mapc_find(ROOT_MAP, "mapdefault", NULL, NULL); /* * Then add the entry... */ /* * Here I plug in the code to process other amd.conf options like * map_type, search_path, and flags (browsable_dirs, mount_type). */ if (cfm) { if (map) { xsnprintf(str, sizeof(str), "cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"", cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "nfs", get_full_path(map, cfm->cfm_search_path, cfm->cfm_type)); if (opts && opts[0] != '\0') { xstrlcat(str, ";", sizeof(str)); xstrlcat(str, opts, sizeof(str)); } if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL) xstrlcat(str, ";opts:=rw,fullybrowsable", sizeof(str)); if (cfm->cfm_flags & CFM_BROWSABLE_DIRS) xstrlcat(str, ";opts:=rw,browsable", sizeof(str)); if (cfm->cfm_type) { xstrlcat(str, ";maptype:=", sizeof(str)); xstrlcat(str, cfm->cfm_type, sizeof(str)); } } else { xstrlcpy(str, opts, sizeof(str)); } } else { if (map) xsnprintf(str, sizeof(str), "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s", map, opts ? opts : ""); else xstrlcpy(str, opts, sizeof(str)); } mapc_repl_kv(root_map, xstrdup(dir), xstrdup(str)); } int mapc_keyiter(mnt_map *m, key_fun *fn, opaque_t arg) { int i; int c = 0; for (i = 0; i < NKVHASH; i++) { kv *k = m->kvhash[i]; while (k) { (*fn) (k->key, arg); k = k->next; c++; } } return c; } /* * Iterate on the root map and call (*fn)() on the key of all the nodes. * Returns the number of entries in the root map. */ int root_keyiter(key_fun *fn, opaque_t arg) { if (root_map) { int c = mapc_keyiter(root_map, fn, arg); return c; } return 0; } /* * Error map */ static int error_init(mnt_map *m, char *map, time_t *tp) { plog(XLOG_USER, "No source data for map %s", map); *tp = 0; return 0; } static int error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) { return ENOENT; } static int error_reload(mnt_map *m, char *map, add_fn *fn) { return ENOENT; } static int error_mtime(mnt_map *m, char *map, time_t *tp) { *tp = 0; return 0; } /* * Return absolute path of map, searched in a type-specific path. * Note: uses a static buffer for returned data. */ static const char * get_full_path(const char *map, const char *path, const char *type) { char component[MAXPATHLEN], *str; static char full_path[MAXPATHLEN]; int len; /* for now, only file-type search paths are implemented */ if (type && !STREQ(type, "file")) return map; /* if null map, return it */ if (!map) return map; /* if map includes a '/', return it (absolute or relative path) */ if (strchr(map, '/')) return map; /* if path is empty, return map */ if (!path) return map; /* now break path into components, and search in each */ xstrlcpy(component, path, sizeof(component)); str = strtok(component, ":"); do { xstrlcpy(full_path, str, sizeof(full_path)); len = strlen(full_path); if (full_path[len - 1] != '/') /* add trailing "/" if needed */ xstrlcat(full_path, "/", sizeof(full_path)); xstrlcat(full_path, map, sizeof(full_path)); if (access(full_path, R_OK) == 0) return full_path; str = strtok(NULL, ":"); } while (str); return map; /* if found nothing, return map */ }