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