diff options
author | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
commit | 663d5a0f32ed8dfc091ffb6153161591ac6ba563 (patch) | |
tree | 60b090a6cbdb64326bb128ea49a231d08eb2680e /contrib/amd/amd/mapc.c | |
download | FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.zip FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.tar.gz |
Virgin import of AMD (am-utils) v6.0a16
Diffstat (limited to 'contrib/amd/amd/mapc.c')
-rw-r--r-- | contrib/amd/amd/mapc.c | 1205 |
1 files changed, 1205 insertions, 0 deletions
diff --git a/contrib/amd/amd/mapc.c b/contrib/amd/amd/mapc.c new file mode 100644 index 0000000..de95e13 --- /dev/null +++ b/contrib/amd/amd/mapc.c @@ -0,0 +1,1205 @@ +/* + * Copyright (c) 1997-1998 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * %W% (Berkeley) %G% + * + * $Id: mapc.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Mount map cache + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> +#include <amd.h> + +/* + * 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 + +#define MAX_CHAIN 2048 + +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}, + {0, 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; /* Initialisation */ + 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 *); + +/* 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_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(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 *); +extern int file_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_FILE */ + + +/* 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_ALL + }, +#endif /* HAVE_MAP_PASSWD */ +#ifdef HAVE_MAP_HESIOD + { + "hesiod", + amu_hesiod_init, + error_reload, + NULL, /* isup function */ + hesiod_search, + error_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_HESIOD */ +#ifdef HAVE_MAP_LDAP + { + "ldap", + amu_ldap_init, + error_reload, + NULL, /* isup function */ + amu_ldap_search, + amu_ldap_mtime, + MAPC_ALL + }, +#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_ALL + }, +#endif /* HAVE_MAP_NDBM */ +#ifdef HAVE_MAP_FILE + { + "file", + file_init, + file_reload, + NULL, /* isup function */ + file_search, + file_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_FILE */ + { + "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) +{ + map_type *mt; + char *sep = ""; + + buf[0] = '\0'; + for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) { + strcat(buf, sep); + strcat(buf, mt->name); + sep = ", "; + } +} + + +/* + * 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 */ + +#ifdef DEBUG + dlog("add_kv: %s -> %s", key, val); +#endif /* DEBUG */ + +#ifdef HAVE_REGEXEC + if (MAPC_ISRE(m)) { + char pattern[MAXPATHLEN]; + int retval; + + /* + * Make sure the string is bound to the start and end + */ + sprintf(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; + } + } +#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; +} + + +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 = 0; +} + + +/* + * Do a map reload + */ +static int +mapc_reload_map(mnt_map *m) +{ + int error; + +#ifdef DEBUG + dlog("calling map reload on %s", m->map_name); +#endif /* DEBUG */ + error = (*m->reload) (m, m->map_name, mapc_add_kv); + if (error) + return error; + m->wildcard = 0; + +#ifdef DEBUG + dlog("calling mapc_search for wildcard"); +#endif /* DEBUG */ + error = mapc_search(m, wildcard, &m->wildcard); + if (error) + m->wildcard = 0; + + return 0; +} + + +/* + * Create a new map + */ +static mnt_map * +mapc_create(char *map, char *opt, const char *type) +{ + mnt_map *m = ALLOC(struct mnt_map); + map_type *mt; + time_t modify; + 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++) { +#ifdef DEBUG + dlog("trying to initialize map %s of type %s ...", map, mt->name); +#endif /* DEBUG */ + 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; + 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; + /* fallthrough... */ + 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 */ + } + +#ifdef DEBUG + dlog("Map for %s coming from maptype %s", map, mt->name); +#endif /* DEBUG */ + + 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 = strdup(map); + m->refc = 1; + m->wildcard = 0; + + /* + * synchronize cache with reality + */ + mapc_sync(m); + + return m; +} + + +/* + * Free the cached data in a map + */ +static void +mapc_clear(mnt_map *m) +{ + int i; + + /* + * For each of the hash slots, chain + * along free'ing the data. + */ + for (i = 0; i < NKVHASH; i++) { + kv *k = m->kvhash[i]; + while (k) { + kv *n = k->next; + XFREE(k->key); + if (k->val) + XFREE(k->val); + XFREE(k); + k = n; + } + } + + /* + * Zero the hash slots + */ + memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); + + /* + * Free the wildcard if it exists + */ + if (m->wildcard) { + XFREE(m->wildcard); + m->wildcard = 0; + } +} + + +/* + * Find a map, or create one if it does not exist + */ +mnt_map * +mapc_find(char *map, char *opt, const char *maptype) +{ + 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); + ins_que(&m->hdr, &map_list_head); + + return m; +} + + +/* + * Free a map. + */ +void +mapc_free(voidp v) +{ + mnt_map *m = v; + + /* + * 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 = 0; + + /* + * 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) { + m->modify = t; + 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, 0, 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 = strdup(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, strdup(key), strdup(*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 / *" + */ + strcpy(wildname, key); + while (error && (subp = strrchr(wildname, '/'))) { + strcpy(subp, "/*"); +#ifdef DEBUG + dlog("mapc recurses on %s", wildname); +#endif /* DEBUG */ + error = mapc_meta_search(m, wildname, pval, MREC_PART); + if (error) + *subp = 0; + } + + if (error > 0 && m->wildcard) { + *pval = strdup(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) +{ + if (m->alloc != MAPC_ROOT) { + + /* 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; + } + } + + mapc_clear(m); + + if (m->alloc >= MAPC_ALL) + if (mapc_reload_map(m)) + m->alloc = MAPC_INC; + /* + * Attempt to find the wildcard entry + */ + if (m->alloc < MAPC_ALL) + mapc_find_wildcard(m); + } +} + + +/* + * 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(); + 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); + + /* + * 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) { + sprintf(str, "cache:=mapdefault;type:=%s;fs:=\"%s\"", + cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "toplvl", + get_full_path(map, cfm->cfm_search_path, cfm->cfm_type)); + if (opts && opts[0] != '\0') { + strcat(str, ";"); + strcat(str, opts); + } + if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL) + strcat(str, ";opts:=rw,fullybrowsable"); + if (cfm->cfm_flags & CFM_BROWSABLE_DIRS) + strcat(str, ";opts:=rw,browsable"); + if (cfm->cfm_type) { + strcat(str, ";maptype:="); + strcat(str, cfm->cfm_type); + } + } else { + strcpy(str, opts); + } + } else { + if (map) + sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s", + map, opts ? opts : ""); + else + strcpy(str, opts); + } + mapc_repl_kv(root_map, strdup((char *)dir), strdup(str)); +} + + +int +mapc_keyiter(mnt_map *m, void (*fn) (char *, voidp), voidp 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. + * Finally throw away the root map. + */ +int +root_keyiter(void (*fn)(char *, voidp), voidp arg) +{ + if (root_map) { + int c = mapc_keyiter(root_map, fn, arg); + return c; + } + + return 0; +} + + +/* + * Was: NEW_TOPLVL_READDIR + * Search a chain for an entry with some name. + * -Erez Zadok <ezk@cs.columbia.edu> + */ +static int +key_already_in_chain(char *keyname, const nfsentry *chain) +{ + const nfsentry *tmpchain = chain; + + while (tmpchain) { + if (keyname && tmpchain->ne_name && STREQ(keyname, tmpchain->ne_name)) + return 1; + tmpchain = tmpchain->ne_nextentry; + } + + return 0; +} + + +/* + * Create a chain of entries which are not linked. + * -Erez Zadok <ezk@cs.columbia.edu> + */ +nfsentry * +make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable) +{ + static u_int last_cookie = ~(u_int) 0 - 1; + static nfsentry chain[MAX_CHAIN]; + static int max_entries = MAX_CHAIN; + char *key; + int num_entries = 0, preflen = 0, i; + nfsentry *retval = (nfsentry *) NULL; + mntfs *mf; + mnt_map *mmp; + + if (!mp) { + plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)"); + return retval; + } + mf = mp->am_mnt; + if (!mf) { + plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt is (NULL)"); + return retval; + } + mmp = (mnt_map *) mf->mf_private; + if (!mmp) { + plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt->mf_private is (NULL)"); + return retval; + } + + /* iterate over keys */ + for (i = 0; i < NKVHASH; i++) { + kv *k; + for (k = mmp->kvhash[i]; k ; k = k->next) { + + /* + * Skip unwanted entries which are either not real entries or + * very difficult to interpret (wildcards...) This test needs + * lots of improvement. Any takers? + */ + key = k->key; + if (!key) + continue; + + /* Skip '*' */ + if (!fully_browsable && strchr(key, '*')) + continue; + + /* + * If the map has a prefix-string then check if the key starts with + * this * string, and if it does, skip over this prefix. + */ + if (preflen) { + if (!NSTREQ(key, mp->am_pref, preflen)) + continue; + key += preflen; + } + + /* no more '/' are allowed, unless browsable_dirs=full was used */ + if (!fully_browsable && strchr(key, '/')) + continue; + + /* no duplicates allowed */ + if (key_already_in_chain(key, current_chain)) + continue; + + /* fill in a cell and link the entry */ + if (num_entries >= max_entries) { + /* out of space */ + plog(XLOG_DEBUG, "make_entry_chain: no more space in chain"); + if (num_entries > 0) { + chain[num_entries - 1].ne_nextentry = 0; + retval = &chain[0]; + } + return retval; + } + + /* we have space. put entry in next cell */ + --last_cookie; + chain[num_entries].ne_fileid = (u_int) last_cookie; + *(u_int *) chain[num_entries].ne_cookie = + (u_int) last_cookie; + chain[num_entries].ne_name = key; + if (num_entries < max_entries - 1) { /* link to next one */ + chain[num_entries].ne_nextentry = &chain[num_entries + 1]; + } + ++num_entries; + } /* end of "while (k)" */ + } /* end of "for (i ... NKVHASH ..." */ + + /* terminate chain */ + if (num_entries > 0) { + chain[num_entries - 1].ne_nextentry = 0; + retval = &chain[0]; + } + + return retval; +} + + +/* + * 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 */ + strcpy(component, path); + + str = strtok(component, ":"); + do { + strcpy(full_path, str); + len = strlen(full_path); + if (full_path[len - 1] != '/') /* add trailing "/" if needed */ + strcat(full_path, "/"); + strcat(full_path, map); + if (access(full_path, R_OK) == 0) + return full_path; + str = strtok(NULL, ":"); + } while (str); + + return map; /* if found nothing, return map */ +} |