138494Sobrien/*
2310490Scy * Copyright (c) 1997-2014 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.
19310490Scy * 3. Neither the name of the University nor the names of its contributors
2038494Sobrien *    may be used to endorse or promote products derived from this software
2138494Sobrien *    without specific prior written permission.
2238494Sobrien *
2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2438494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2538494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2638494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2738494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2838494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2938494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3038494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3138494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3238494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3338494Sobrien * SUCH DAMAGE.
3438494Sobrien *
3538494Sobrien *
36174294Sobrien * File: am-utils/amd/mapc.c
3738494Sobrien *
3838494Sobrien */
3938494Sobrien
4038494Sobrien/*
4138494Sobrien * Mount map cache
4238494Sobrien */
4338494Sobrien
4438494Sobrien#ifdef HAVE_CONFIG_H
4538494Sobrien# include <config.h>
4638494Sobrien#endif /* HAVE_CONFIG_H */
4738494Sobrien#include <am_defs.h>
4838494Sobrien#include <amd.h>
4938494Sobrien
5038494Sobrien/*
5138494Sobrien * Make a duplicate reference to an existing map
5238494Sobrien */
5338494Sobrien#define mapc_dup(m) ((m)->refc++, (m))
5438494Sobrien
5538494Sobrien/*
5638494Sobrien * Map cache types
5738494Sobrien * default, none, incremental, all, regexp
5838494Sobrien * MAPC_RE implies MAPC_ALL and must be numerically
5938494Sobrien * greater.
6038494Sobrien */
6138494Sobrien#define	MAPC_DFLT	0x000
6238494Sobrien#define	MAPC_NONE	0x001
6338494Sobrien#define	MAPC_INC	0x002
6438494Sobrien#define	MAPC_ROOT	0x004
6538494Sobrien#define	MAPC_ALL	0x010
6638494Sobrien#define	MAPC_CACHE_MASK	0x0ff
6738494Sobrien#define	MAPC_SYNC	0x100
6838494Sobrien
6938494Sobrien#ifdef HAVE_REGEXEC
7038494Sobrien# define	MAPC_RE		0x020
7138494Sobrien# define	MAPC_ISRE(m)	((m)->alloc == MAPC_RE)
7238494Sobrien#else /* not HAVE_REGEXEC */
7338494Sobrien# define	MAPC_ISRE(m)	FALSE
7438494Sobrien#endif /* not HAVE_REGEXEC */
7538494Sobrien
7638494Sobrien/*
7738494Sobrien * Lookup recursion
7838494Sobrien */
7938494Sobrien#define	MREC_FULL	2
8038494Sobrien#define	MREC_PART	1
8138494Sobrien#define	MREC_NONE	0
8238494Sobrien
8338494Sobrienstatic struct opt_tab mapc_opt[] =
8438494Sobrien{
8538494Sobrien  {"all", MAPC_ALL},
8638494Sobrien  {"default", MAPC_DFLT},
8738494Sobrien  {"inc", MAPC_INC},
8838494Sobrien  {"mapdefault", MAPC_DFLT},
8938494Sobrien  {"none", MAPC_NONE},
9038494Sobrien#ifdef HAVE_REGEXEC
9138494Sobrien  {"re", MAPC_RE},
9238494Sobrien  {"regexp", MAPC_RE},
9338494Sobrien#endif /* HAVE_REGEXEC */
9438494Sobrien  {"sync", MAPC_SYNC},
95310490Scy  {NULL, 0}
9638494Sobrien};
9738494Sobrien
9838494Sobrien/*
9938494Sobrien * Wildcard key
10038494Sobrien */
10138494Sobrienstatic char wildcard[] = "*";
10238494Sobrien
10338494Sobrien/*
10438494Sobrien * Map type
10538494Sobrien */
10638494Sobrientypedef struct map_type map_type;
10738494Sobrienstruct map_type {
10838494Sobrien  char *name;			/* Name of this map type */
10942629Sobrien  init_fn *init;		/* Initialization */
11038494Sobrien  reload_fn *reload;		/* Reload or fill */
11138494Sobrien  isup_fn *isup;		/* Is service up or not? (1=up, 0=down) */
11238494Sobrien  search_fn *search;		/* Search for new entry */
11338494Sobrien  mtime_fn *mtime;		/* Find modify time */
11438494Sobrien  int def_alloc;		/* Default allocation mode */
11538494Sobrien};
11638494Sobrien
11738494Sobrien/*
11838494Sobrien * Map for root node
11938494Sobrien */
12038494Sobrienstatic mnt_map *root_map;
12138494Sobrien
12238494Sobrien/*
12338494Sobrien * List of known maps
12438494Sobrien */
12538494Sobrienqelem map_list_head = {&map_list_head, &map_list_head};
12638494Sobrien
12738494Sobrien/*
12838494Sobrien * Configuration
12938494Sobrien */
13038494Sobrien
13138494Sobrien/* forward definitions */
13238494Sobrienstatic const char *get_full_path(const char *map, const char *path, const char *type);
13338494Sobrienstatic int mapc_meta_search(mnt_map *, char *, char **, int);
13438494Sobrienstatic void mapc_sync(mnt_map *);
13552894Sobrienstatic void mapc_clear(mnt_map *);
136310490Scystatic void mapc_clear_kvhash(kv **);
13738494Sobrien
13838494Sobrien/* ROOT MAP */
13938494Sobrienstatic int root_init(mnt_map *, char *, time_t *);
14038494Sobrien
14138494Sobrien/* ERROR MAP */
14238494Sobrienstatic int error_init(mnt_map *, char *, time_t *);
14338494Sobrienstatic int error_reload(mnt_map *, char *, add_fn *);
14438494Sobrienstatic int error_search(mnt_map *, char *, char *, char **, time_t *);
14538494Sobrienstatic int error_mtime(mnt_map *, char *, time_t *);
14638494Sobrien
14738494Sobrien/* PASSWD MAPS */
14838494Sobrien#ifdef HAVE_MAP_PASSWD
14938494Sobrienextern int passwd_init(mnt_map *, char *, time_t *);
15038494Sobrienextern int passwd_search(mnt_map *, char *, char *, char **, time_t *);
15138494Sobrien#endif /* HAVE_MAP_PASSWD */
15238494Sobrien
15338494Sobrien/* HESIOD MAPS */
15438494Sobrien#ifdef HAVE_MAP_HESIOD
15538494Sobrienextern int amu_hesiod_init(mnt_map *, char *map, time_t *tp);
15651292Sobrienextern int hesiod_isup(mnt_map *, char *);
15738494Sobrienextern int hesiod_search(mnt_map *, char *, char *, char **, time_t *);
15838494Sobrien#endif /* HAVE_MAP_HESIOD */
15938494Sobrien
16038494Sobrien/* LDAP MAPS */
16138494Sobrien#ifdef HAVE_MAP_LDAP
16238494Sobrienextern int amu_ldap_init(mnt_map *, char *map, time_t *tp);
16338494Sobrienextern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *);
16438494Sobrienextern int amu_ldap_mtime(mnt_map *, char *, time_t *);
16538494Sobrien#endif /* HAVE_MAP_LDAP */
16638494Sobrien
16738494Sobrien/* UNION MAPS */
16838494Sobrien#ifdef HAVE_MAP_UNION
16938494Sobrienextern int union_init(mnt_map *, char *, time_t *);
17038494Sobrienextern int union_search(mnt_map *, char *, char *, char **, time_t *);
17138494Sobrienextern int union_reload(mnt_map *, char *, add_fn *);
17238494Sobrien#endif /* HAVE_MAP_UNION */
17338494Sobrien
17438494Sobrien/* Network Information Service PLUS (NIS+) */
17538494Sobrien#ifdef HAVE_MAP_NISPLUS
17638494Sobrienextern int nisplus_init(mnt_map *, char *, time_t *);
17738494Sobrienextern int nisplus_reload(mnt_map *, char *, add_fn *);
17838494Sobrienextern int nisplus_search(mnt_map *, char *, char *, char **, time_t *);
17938494Sobrienextern int nisplus_mtime(mnt_map *, char *, time_t *);
18038494Sobrien#endif /* HAVE_MAP_NISPLUS */
18138494Sobrien
18238494Sobrien/* Network Information Service (YP, Yellow Pages) */
18338494Sobrien#ifdef HAVE_MAP_NIS
18438494Sobrienextern int nis_init(mnt_map *, char *, time_t *);
18538494Sobrienextern int nis_reload(mnt_map *, char *, add_fn *);
18638494Sobrienextern int nis_isup(mnt_map *, char *);
18738494Sobrienextern int nis_search(mnt_map *, char *, char *, char **, time_t *);
18838494Sobrienextern int nis_mtime(mnt_map *, char *, time_t *);
18938494Sobrien#endif /* HAVE_MAP_NIS */
19038494Sobrien
19138494Sobrien/* NDBM MAPS */
19238494Sobrien#ifdef HAVE_MAP_NDBM
19338494Sobrienextern int ndbm_init(mnt_map *, char *, time_t *);
19438494Sobrienextern int ndbm_search(mnt_map *, char *, char *, char **, time_t *);
19538494Sobrienextern int ndbm_mtime(mnt_map *, char *, time_t *);
19638494Sobrien#endif /* HAVE_MAP_NDBM */
19738494Sobrien
19838494Sobrien/* FILE MAPS */
19938494Sobrien#ifdef HAVE_MAP_FILE
200174294Sobrienextern int file_init_or_mtime(mnt_map *, char *, time_t *);
20138494Sobrienextern int file_reload(mnt_map *, char *, add_fn *);
20238494Sobrienextern int file_search(mnt_map *, char *, char *, char **, time_t *);
20338494Sobrien#endif /* HAVE_MAP_FILE */
20438494Sobrien
205310490Scy/* EXECUTABLE MAPS */
206310490Scy#ifdef HAVE_MAP_EXEC
207310490Scyextern int exec_init(mnt_map *, char *, time_t *);
208310490Scyextern int exec_search(mnt_map *, char *, char *, char **, time_t *);
209310490Scy#endif /* HAVE_MAP_EXEC */
21038494Sobrien
211310490Scy/* Sun-syntax MAPS */
212310490Scy#ifdef HAVE_MAP_SUN
213310490Scy/* XXX: fill in */
214310490Scy#endif /* HAVE_MAP_SUN */
215310490Scy
21638494Sobrien/* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */
21738494Sobrienstatic map_type maptypes[] =
21838494Sobrien{
21938494Sobrien  {
22038494Sobrien    "root",
22138494Sobrien    root_init,
22238494Sobrien    error_reload,
22338494Sobrien    NULL,			/* isup function */
22438494Sobrien    error_search,
22538494Sobrien    error_mtime,
22638494Sobrien    MAPC_ROOT
22738494Sobrien  },
22838494Sobrien#ifdef HAVE_MAP_PASSWD
22938494Sobrien  {
23038494Sobrien    "passwd",
23138494Sobrien    passwd_init,
23238494Sobrien    error_reload,
23338494Sobrien    NULL,			/* isup function */
23438494Sobrien    passwd_search,
23538494Sobrien    error_mtime,
23682794Sobrien    MAPC_INC
23738494Sobrien  },
23838494Sobrien#endif /* HAVE_MAP_PASSWD */
23938494Sobrien#ifdef HAVE_MAP_HESIOD
24038494Sobrien  {
24138494Sobrien    "hesiod",
24238494Sobrien    amu_hesiod_init,
24338494Sobrien    error_reload,
24451292Sobrien    hesiod_isup,		/* is Hesiod up or not? */
24538494Sobrien    hesiod_search,
24638494Sobrien    error_mtime,
24782794Sobrien    MAPC_INC
24838494Sobrien  },
24938494Sobrien#endif /* HAVE_MAP_HESIOD */
25038494Sobrien#ifdef HAVE_MAP_LDAP
25138494Sobrien  {
25238494Sobrien    "ldap",
25338494Sobrien    amu_ldap_init,
25438494Sobrien    error_reload,
25538494Sobrien    NULL,			/* isup function */
25638494Sobrien    amu_ldap_search,
25738494Sobrien    amu_ldap_mtime,
25882794Sobrien    MAPC_INC
25938494Sobrien  },
26038494Sobrien#endif /* HAVE_MAP_LDAP */
26138494Sobrien#ifdef HAVE_MAP_UNION
26238494Sobrien  {
26338494Sobrien    "union",
26438494Sobrien    union_init,
26538494Sobrien    union_reload,
26638494Sobrien    NULL,			/* isup function */
26738494Sobrien    union_search,
26838494Sobrien    error_mtime,
26938494Sobrien    MAPC_ALL
27038494Sobrien  },
27138494Sobrien#endif /* HAVE_MAP_UNION */
27238494Sobrien#ifdef HAVE_MAP_NISPLUS
27338494Sobrien  {
27438494Sobrien    "nisplus",
27538494Sobrien    nisplus_init,
27638494Sobrien    nisplus_reload,
27738494Sobrien    NULL,			/* isup function */
27838494Sobrien    nisplus_search,
27938494Sobrien    nisplus_mtime,
28038494Sobrien    MAPC_INC
28138494Sobrien  },
28238494Sobrien#endif /* HAVE_MAP_NISPLUS */
28338494Sobrien#ifdef HAVE_MAP_NIS
28438494Sobrien  {
28538494Sobrien    "nis",
28638494Sobrien    nis_init,
28738494Sobrien    nis_reload,
28838494Sobrien    nis_isup,			/* is NIS up or not? */
28938494Sobrien    nis_search,
29038494Sobrien    nis_mtime,
29138494Sobrien    MAPC_ALL
29238494Sobrien  },
29338494Sobrien#endif /* HAVE_MAP_NIS */
29438494Sobrien#ifdef HAVE_MAP_NDBM
29538494Sobrien  {
29638494Sobrien    "ndbm",
29738494Sobrien    ndbm_init,
29838494Sobrien    error_reload,
29938494Sobrien    NULL,			/* isup function */
30038494Sobrien    ndbm_search,
30138494Sobrien    ndbm_mtime,
30282794Sobrien    MAPC_INC
30338494Sobrien  },
30438494Sobrien#endif /* HAVE_MAP_NDBM */
30538494Sobrien#ifdef HAVE_MAP_FILE
30638494Sobrien  {
30738494Sobrien    "file",
308174294Sobrien    file_init_or_mtime,
30938494Sobrien    file_reload,
31038494Sobrien    NULL,			/* isup function */
31138494Sobrien    file_search,
312174294Sobrien    file_init_or_mtime,
31338494Sobrien    MAPC_ALL
31438494Sobrien  },
31538494Sobrien#endif /* HAVE_MAP_FILE */
316174294Sobrien#ifdef HAVE_MAP_EXEC
31738494Sobrien  {
318174294Sobrien    "exec",
319174294Sobrien    exec_init,
320174294Sobrien    error_reload,
321174294Sobrien    NULL,			/* isup function */
322174294Sobrien    exec_search,
323174294Sobrien    error_mtime,
324174294Sobrien    MAPC_INC
325174294Sobrien  },
326174294Sobrien#endif /* HAVE_MAP_EXEC */
327310490Scy#ifdef notyet /* probe function needs to be there or SEGV */
328310490Scy#ifdef HAVE_MAP_SUN
329174294Sobrien  {
330310490Scy    /* XXX: fill in */
331310490Scy    "sun",
332310490Scy    NULL,
333310490Scy    NULL,
334310490Scy    NULL,			/* isup function */
335310490Scy    NULL,
336310490Scy    NULL,
337310490Scy    0
338310490Scy  },
339310490Scy#endif /* HAVE_MAP_SUN */
340310490Scy#endif
341310490Scy  {
34238494Sobrien    "error",
34338494Sobrien    error_init,
34438494Sobrien    error_reload,
34538494Sobrien    NULL,			/* isup function */
34638494Sobrien    error_search,
34738494Sobrien    error_mtime,
34838494Sobrien    MAPC_NONE
34938494Sobrien  },
35038494Sobrien};
35138494Sobrien
35238494Sobrien
35338494Sobrien/*
35438494Sobrien * Hash function
35538494Sobrien */
35638494Sobrienstatic u_int
35738494Sobrienkvhash_of(char *key)
35838494Sobrien{
35938494Sobrien  u_int i, j;
36038494Sobrien
36138494Sobrien  for (i = 0; (j = *key++); i += j) ;
36238494Sobrien
36338494Sobrien  return i % NKVHASH;
36438494Sobrien}
36538494Sobrien
36638494Sobrien
36738494Sobrienvoid
368174294Sobrienmapc_showtypes(char *buf, size_t l)
36938494Sobrien{
370174294Sobrien  map_type *mt=NULL, *lastmt;
371174294Sobrien  int linesize = 0, i;
37238494Sobrien
373174294Sobrien  i = sizeof(maptypes) / sizeof(maptypes[0]);
374174294Sobrien  lastmt = maptypes + i;
37538494Sobrien  buf[0] = '\0';
376174294Sobrien  for (mt = maptypes; mt < lastmt; mt++) {
377174294Sobrien    xstrlcat(buf, mt->name, l);
378174294Sobrien    if (mt == (lastmt-1))
379174294Sobrien      break;	      /* if last one, don't do xstrlcat's that follows */
380174294Sobrien    linesize += strlen(mt->name);
381174294Sobrien    if (--i > 0) {
382174294Sobrien      xstrlcat(buf, ", ", l);
383174294Sobrien      linesize += 2;
384174294Sobrien    }
385174294Sobrien    if (linesize > 54) {
386174294Sobrien      linesize = 0;
387174294Sobrien      xstrlcat(buf, "\n\t\t ", l);
388174294Sobrien    }
38938494Sobrien  }
39038494Sobrien}
39138494Sobrien
39238494Sobrien
39338494Sobrien/*
39441142Sobrien * Check if a map of a certain type exists.
39541142Sobrien * Return 1 (true) if exists, 0 (false) if not.
39641142Sobrien */
39741142Sobrienint
39841142Sobrienmapc_type_exists(const char *type)
39941142Sobrien{
40041142Sobrien  map_type *mt;
40141142Sobrien
40241142Sobrien  if (!type)
40341142Sobrien    return 0;
40441142Sobrien  for (mt = maptypes;
40541142Sobrien       mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
40641142Sobrien       mt++) {
40741142Sobrien    if (STREQ(type, mt->name))
40841142Sobrien      return 1;
40941142Sobrien  }
41041142Sobrien  return 0;			/* not found anywhere */
41141142Sobrien}
41241142Sobrien
41341142Sobrien
41441142Sobrien/*
41538494Sobrien * Add key and val to the map m.
41638494Sobrien * key and val are assumed to be safe copies
41738494Sobrien */
41841142Sobrienvoid
41941142Sobrienmapc_add_kv(mnt_map *m, char *key, char *val)
42038494Sobrien{
42138494Sobrien  kv **h;
42238494Sobrien  kv *n;
42338494Sobrien  int hash = kvhash_of(key);
42438494Sobrien#ifdef HAVE_REGEXEC
42538494Sobrien  regex_t re;
42638494Sobrien#endif /* HAVE_REGEXEC */
42738494Sobrien
42838494Sobrien  dlog("add_kv: %s -> %s", key, val);
42938494Sobrien
430310490Scy  if (val != NULL && strchr(val, '\n') != NULL) {
431310490Scy    /*
432310490Scy     * If the entry value contains multiple lines we need to break
433310490Scy     * them up and add them recursively.  This is a workaround to
434310490Scy     * support Sun style multi-mounts.  Amd converts Sun style
435310490Scy     * mulit-mounts to type:=auto.  The problem is that Sun packs all
436310490Scy     * the entries on one line.  When Amd does the conversion it puts
437310490Scy     * each type:=auto entry on the same line separated by '\n'.
438310490Scy     */
439310490Scy    char *entry, *tok;
440310490Scy
441310490Scy    /*
442310490Scy     * The first line should contain the first entry.  The key for
443310490Scy     * this entry is the key passed into this function.
444310490Scy     */
445310490Scy    if ((tok = strtok(val, "\n")) != NULL) {
446310490Scy      mapc_add_kv(m, key, xstrdup(tok));
447310490Scy    }
448310490Scy
449310490Scy    /*
450310490Scy     * For the rest of the entries we need to tokenize them by '\n'
451310490Scy     * and separate the keys from there entries.
452310490Scy     */
453310490Scy    while ((tok = strtok(NULL, "\n")) != NULL) {
454310490Scy      key = tok;
455310490Scy      /* find the entry */
456310490Scy      for (entry = key; *entry && !isspace((unsigned char)*entry); entry++);
457310490Scy      if (*entry) {
458310490Scy	*entry++ = '\0';
459310490Scy      }
460310490Scy
461310490Scy      mapc_add_kv(m, xstrdup(key), xstrdup(entry));
462310490Scy    }
463310490Scy
464310490Scy    XFREE(val);
465310490Scy    return;
466310490Scy  }
467310490Scy
46838494Sobrien#ifdef HAVE_REGEXEC
46938494Sobrien  if (MAPC_ISRE(m)) {
47038494Sobrien    char pattern[MAXPATHLEN];
47138494Sobrien    int retval;
47238494Sobrien
47338494Sobrien    /*
47438494Sobrien     * Make sure the string is bound to the start and end
47538494Sobrien     */
476174294Sobrien    xsnprintf(pattern, sizeof(pattern), "^%s$", key);
47738494Sobrien    retval = regcomp(&re, pattern, REG_ICASE);
47838494Sobrien    if (retval != 0) {
47938494Sobrien      char errstr[256];
48038494Sobrien
48138494Sobrien      /* XXX: this code was recently ported, and must be tested -Erez */
48238494Sobrien      errstr[0] = '\0';
48338494Sobrien      regerror(retval, &re, errstr, 256);
48438494Sobrien      plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr);
48538494Sobrien      return;
48638494Sobrien    }
487310490Scy  } else
488310490Scy    memset(&re, 0, sizeof(re));
48938494Sobrien#endif /* HAVE_REGEXEC */
49038494Sobrien
49138494Sobrien  h = &m->kvhash[hash];
49238494Sobrien  n = ALLOC(struct kv);
49338494Sobrien  n->key = key;
49438494Sobrien#ifdef HAVE_REGEXEC
49538494Sobrien  memcpy(&n->re, &re, sizeof(regex_t));
49638494Sobrien#endif /* HAVE_REGEXEC */
49738494Sobrien  n->val = val;
49838494Sobrien  n->next = *h;
49938494Sobrien  *h = n;
500310490Scy  m->nentries++;
50138494Sobrien}
50238494Sobrien
50338494Sobrien
50438494Sobrienstatic void
50538494Sobrienmapc_repl_kv(mnt_map *m, char *key, char *val)
50638494Sobrien{
50738494Sobrien  kv *k;
50838494Sobrien
50938494Sobrien  /*
51038494Sobrien   * Compute the hash table offset
51138494Sobrien   */
51238494Sobrien  k = m->kvhash[kvhash_of(key)];
51338494Sobrien
51438494Sobrien  /*
51538494Sobrien   * Scan the linked list for the key
51638494Sobrien   */
51738494Sobrien  while (k && !FSTREQ(k->key, key))
51838494Sobrien    k = k->next;
51938494Sobrien
52038494Sobrien  if (k) {
52138494Sobrien    XFREE(k->val);
52238494Sobrien    k->val = val;
52338494Sobrien  } else {
52438494Sobrien    mapc_add_kv(m, key, val);
52538494Sobrien  }
52638494Sobrien}
52738494Sobrien
52838494Sobrien
52938494Sobrien/*
53038494Sobrien * Search a map for a key.
53138494Sobrien * Calls map specific search routine.
53238494Sobrien * While map is out of date, keep re-syncing.
53338494Sobrien */
53438494Sobrienstatic int
53538494Sobriensearch_map(mnt_map *m, char *key, char **valp)
53638494Sobrien{
53738494Sobrien  int rc;
53838494Sobrien
53938494Sobrien  do {
54038494Sobrien    rc = (*m->search) (m, m->map_name, key, valp, &m->modify);
54138494Sobrien    if (rc < 0) {
54238494Sobrien      plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
54338494Sobrien      mapc_sync(m);
54438494Sobrien    }
54538494Sobrien  } while (rc < 0);
54638494Sobrien
54738494Sobrien  return rc;
54838494Sobrien}
54938494Sobrien
55038494Sobrien
55138494Sobrien/*
55238494Sobrien * Do a wildcard lookup in the map and
55338494Sobrien * save the result.
55438494Sobrien */
55538494Sobrienstatic void
55638494Sobrienmapc_find_wildcard(mnt_map *m)
55738494Sobrien{
55838494Sobrien  /*
55938494Sobrien   * Attempt to find the wildcard entry
56038494Sobrien   */
56138494Sobrien  int rc = search_map(m, wildcard, &m->wildcard);
56238494Sobrien
56338494Sobrien  if (rc != 0)
564310490Scy    m->wildcard = NULL;
56538494Sobrien}
56638494Sobrien
56738494Sobrien
56838494Sobrien/*
56952894Sobrien * Do a map reload.
57052894Sobrien * Attempt to reload without losing current data by switching the hashes
57152894Sobrien * round.
572174294Sobrien * If reloading was needed and succeeded, return 1; else return 0.
57338494Sobrien */
574174294Sobrienstatic int
57538494Sobrienmapc_reload_map(mnt_map *m)
57638494Sobrien{
577174294Sobrien  int error, ret = 0;
578310490Scy  kv *maphash[NKVHASH];
57982794Sobrien  time_t t;
58038494Sobrien
58182794Sobrien  error = (*m->mtime) (m, m->map_name, &t);
58282794Sobrien  if (error) {
58382794Sobrien    t = m->modify;
58482794Sobrien  }
58582794Sobrien
58652894Sobrien  /*
58752894Sobrien   * skip reloading maps that have not been modified, unless
58852894Sobrien   * amq -f was used (do_mapc_reload is 0)
58952894Sobrien   */
59052894Sobrien  if (m->reloads != 0 && do_mapc_reload != 0) {
59182794Sobrien    if (t <= m->modify) {
59252894Sobrien      plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name);
59352894Sobrien      dlog("map %s last load time is %d, last modify time is %d",
59452894Sobrien	   m->map_name, (int) m->modify, (int) t);
595174294Sobrien      return ret;
59652894Sobrien    }
59752894Sobrien  }
59852894Sobrien
59952894Sobrien  /* copy the old hash and zero the map */
60052894Sobrien  memcpy((voidp) maphash, (voidp) m->kvhash, sizeof(m->kvhash));
60152894Sobrien  memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
60252894Sobrien
60338494Sobrien  dlog("calling map reload on %s", m->map_name);
604310490Scy  m->nentries = 0;
60538494Sobrien  error = (*m->reload) (m, m->map_name, mapc_add_kv);
60652894Sobrien  if (error) {
60752894Sobrien    if (m->reloads == 0)
60852894Sobrien      plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name);
60952894Sobrien    else
61052894Sobrien      plog(XLOG_ERROR, "reload of map %s failed - using old values",
61152894Sobrien	   m->map_name);
61252894Sobrien    mapc_clear(m);
61352894Sobrien    memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash));
61452894Sobrien  } else {
61552894Sobrien    if (m->reloads++ == 0)
61652894Sobrien      plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name);
61752894Sobrien    else
61852894Sobrien      plog(XLOG_INFO, "reload #%d of map %s succeeded",
61952894Sobrien	   m->reloads, m->map_name);
620310490Scy    mapc_clear_kvhash(maphash);
621310490Scy    if (m->wildcard) {
622310490Scy       XFREE(m->wildcard);
623310490Scy       m->wildcard = NULL;
624310490Scy    }
62582794Sobrien    m->modify = t;
626174294Sobrien    ret = 1;
62752894Sobrien  }
62838494Sobrien
62938494Sobrien  dlog("calling mapc_search for wildcard");
63038494Sobrien  error = mapc_search(m, wildcard, &m->wildcard);
63138494Sobrien  if (error)
632310490Scy    m->wildcard = NULL;
633174294Sobrien  return ret;
63438494Sobrien}
63538494Sobrien
63638494Sobrien
63738494Sobrien/*
63838494Sobrien * Create a new map
63938494Sobrien */
64038494Sobrienstatic mnt_map *
641310490Scymapc_create(char *map, char *opt, const char *type, const char *mntpt)
64238494Sobrien{
64338494Sobrien  mnt_map *m = ALLOC(struct mnt_map);
64438494Sobrien  map_type *mt;
645174294Sobrien  time_t modify = 0;
646310490Scy  u_int alloc = 0;
64738494Sobrien
64838494Sobrien  cmdoption(opt, mapc_opt, &alloc);
64938494Sobrien
65038494Sobrien  /*
65138494Sobrien   * If using a configuration file, and the map_type is defined, then look
65238494Sobrien   * for it, in the maptypes array.  If found, initialize the map using that
65338494Sobrien   * map_type.  If not found, return error.  If no map_type was defined,
65438494Sobrien   * default to cycling through all maptypes.
65538494Sobrien   */
65638494Sobrien  if (use_conf_file && type) {
65738494Sobrien    /* find what type of map this one is */
65838494Sobrien    for (mt = maptypes;
65938494Sobrien	 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
66038494Sobrien	 mt++) {
66138494Sobrien      if (STREQ(type, mt->name)) {
66282794Sobrien	plog(XLOG_INFO, "initializing amd.conf map %s of type %s", map, type);
66338494Sobrien	if ((*mt->init) (m, map, &modify) == 0) {
66438494Sobrien	  break;
66538494Sobrien	} else {
66638494Sobrien	  plog(XLOG_ERROR, "failed to initialize map %s", map);
66738494Sobrien	  error_init(m, map, &modify);
66838494Sobrien	  break;
66938494Sobrien	}
67038494Sobrien      }
67138494Sobrien    } /* end of "for (mt =" loop */
67238494Sobrien
67338494Sobrien  } else {			/* cycle through all known maptypes */
67438494Sobrien
67538494Sobrien    /*
67638494Sobrien     * not using amd conf file or using it by w/o specifying map type
67738494Sobrien     */
67838494Sobrien    for (mt = maptypes;
67938494Sobrien	 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
68038494Sobrien	 mt++) {
68138494Sobrien      dlog("trying to initialize map %s of type %s ...", map, mt->name);
68238494Sobrien      if ((*mt->init) (m, map, &modify) == 0) {
68338494Sobrien	break;
68438494Sobrien      }
68538494Sobrien    }
68638494Sobrien  } /* end of "if (use_conf_file && (colpos = strchr ..." statement */
68738494Sobrien
68838494Sobrien  /* assert: mt in maptypes */
68938494Sobrien
69038494Sobrien  m->flags = alloc & ~MAPC_CACHE_MASK;
691310490Scy  m->nentries = 0;
69238494Sobrien  alloc &= MAPC_CACHE_MASK;
69338494Sobrien
69438494Sobrien  if (alloc == MAPC_DFLT)
69538494Sobrien    alloc = mt->def_alloc;
69638494Sobrien
69738494Sobrien  switch (alloc) {
69838494Sobrien  default:
69938494Sobrien    plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
70038494Sobrien    alloc = MAPC_INC;
70142629Sobrien    /* fall-through... */
70238494Sobrien  case MAPC_NONE:
70338494Sobrien  case MAPC_INC:
70438494Sobrien  case MAPC_ROOT:
70538494Sobrien    break;
70638494Sobrien
70738494Sobrien  case MAPC_ALL:
70838494Sobrien    /*
70938494Sobrien     * If there is no support for reload and it was requested
71038494Sobrien     * then back off to incremental instead.
71138494Sobrien     */
71238494Sobrien    if (mt->reload == error_reload) {
71338494Sobrien      plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name);
71438494Sobrien      alloc = MAPC_INC;
71538494Sobrien    }
71638494Sobrien    break;
71738494Sobrien
71838494Sobrien#ifdef HAVE_REGEXEC
71938494Sobrien  case MAPC_RE:
72038494Sobrien    if (mt->reload == error_reload) {
72138494Sobrien      plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name);
72238494Sobrien      mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1];
72338494Sobrien      /* assert: mt->name == "error" */
72438494Sobrien    }
72538494Sobrien    break;
72638494Sobrien#endif /* HAVE_REGEXEC */
72738494Sobrien  }
72838494Sobrien
72938494Sobrien  dlog("Map for %s coming from maptype %s", map, mt->name);
73038494Sobrien
73138494Sobrien  m->alloc = alloc;
73238494Sobrien  m->reload = mt->reload;
73338494Sobrien  m->isup = mt->isup;
73438494Sobrien  m->modify = modify;
73538494Sobrien  m->search = alloc >= MAPC_ALL ? error_search : mt->search;
73638494Sobrien  m->mtime = mt->mtime;
73738494Sobrien  memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
738310490Scy  m->map_name = xstrdup(map);
73938494Sobrien  m->refc = 1;
740310490Scy  m->wildcard = NULL;
74152894Sobrien  m->reloads = 0;
742310490Scy  /* initialize per-map information (flags, etc.) */
743310490Scy  m->cfm = find_cf_map(mntpt);
74438494Sobrien
74538494Sobrien  /*
74638494Sobrien   * synchronize cache with reality
74738494Sobrien   */
74838494Sobrien  mapc_sync(m);
74938494Sobrien
75038494Sobrien  return m;
75138494Sobrien}
75238494Sobrien
75338494Sobrien
75438494Sobrien/*
755310490Scy * Free the cached data in a map hash
75638494Sobrien */
75738494Sobrienstatic void
758310490Scymapc_clear_kvhash(kv **kvhash)
75938494Sobrien{
76038494Sobrien  int i;
76138494Sobrien
76238494Sobrien  /*
76338494Sobrien   * For each of the hash slots, chain
76438494Sobrien   * along free'ing the data.
76538494Sobrien   */
76638494Sobrien  for (i = 0; i < NKVHASH; i++) {
767310490Scy    kv *k = kvhash[i];
76838494Sobrien    while (k) {
76938494Sobrien      kv *n = k->next;
77038494Sobrien      XFREE(k->key);
771310490Scy      XFREE(k->val);
77238494Sobrien      XFREE(k);
77338494Sobrien      k = n;
77438494Sobrien    }
77538494Sobrien  }
776310490Scy}
77738494Sobrien
778310490Scy
779310490Scy/*
780310490Scy * Free the cached data in a map
781310490Scy */
782310490Scystatic void
783310490Scymapc_clear(mnt_map *m)
784310490Scy{
785310490Scy  mapc_clear_kvhash(m->kvhash);
786310490Scy
78738494Sobrien  /*
78838494Sobrien   * Zero the hash slots
78938494Sobrien   */
79038494Sobrien  memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
79138494Sobrien
79238494Sobrien  /*
79338494Sobrien   * Free the wildcard if it exists
79438494Sobrien   */
795310490Scy  XFREE(m->wildcard);
796310490Scy  m->wildcard = NULL;
797310490Scy
798310490Scy  m->nentries = 0;
79938494Sobrien}
80038494Sobrien
80138494Sobrien
80238494Sobrien/*
80338494Sobrien * Find a map, or create one if it does not exist
80438494Sobrien */
80538494Sobrienmnt_map *
806310490Scymapc_find(char *map, char *opt, const char *maptype, const char *mntpt)
80738494Sobrien{
80838494Sobrien  mnt_map *m;
80938494Sobrien
81038494Sobrien  /*
81138494Sobrien   * Search the list of known maps to see if
81238494Sobrien   * it has already been loaded.  If it is found
81338494Sobrien   * then return a duplicate reference to it.
81438494Sobrien   * Otherwise make a new map as required and
81538494Sobrien   * add it to the list of maps
81638494Sobrien   */
81738494Sobrien  ITER(m, mnt_map, &map_list_head)
818174294Sobrien    if (STREQ(m->map_name, map))
81938494Sobrien      return mapc_dup(m);
820310490Scy  m = mapc_create(map, opt, maptype, mntpt);
82138494Sobrien  ins_que(&m->hdr, &map_list_head);
82238494Sobrien
82338494Sobrien  return m;
82438494Sobrien}
82538494Sobrien
82638494Sobrien
82738494Sobrien/*
82838494Sobrien * Free a map.
82938494Sobrien */
83038494Sobrienvoid
831174294Sobrienmapc_free(opaque_t arg)
83238494Sobrien{
833174294Sobrien  mnt_map *m = (mnt_map *) arg;
83438494Sobrien
83538494Sobrien  /*
83638494Sobrien   * Decrement the reference count.
83738494Sobrien   * If the reference count hits zero
83838494Sobrien   * then throw the map away.
83938494Sobrien   */
84038494Sobrien  if (m && --m->refc == 0) {
84138494Sobrien    mapc_clear(m);
84238494Sobrien    XFREE(m->map_name);
84338494Sobrien    rem_que(&m->hdr);
84438494Sobrien    XFREE(m);
84538494Sobrien  }
84638494Sobrien}
84738494Sobrien
84838494Sobrien
84938494Sobrien/*
85038494Sobrien * Search the map for the key.  Put a safe (malloc'ed) copy in *pval or
85138494Sobrien * return an error code
85238494Sobrien */
85338494Sobrienstatic int
85438494Sobrienmapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
85538494Sobrien{
85638494Sobrien  int error = 0;
857310490Scy  kv *k = NULL;
85838494Sobrien
85938494Sobrien  /*
86038494Sobrien   * Firewall
86138494Sobrien   */
86238494Sobrien  if (!m) {
86338494Sobrien    plog(XLOG_ERROR, "Null map request for %s", key);
86438494Sobrien    return ENOENT;
86538494Sobrien  }
86682794Sobrien
86738494Sobrien  if (m->flags & MAPC_SYNC) {
86838494Sobrien    /*
86938494Sobrien     * Get modify time...
87038494Sobrien     */
87138494Sobrien    time_t t;
87238494Sobrien    error = (*m->mtime) (m, m->map_name, &t);
87338494Sobrien    if (error || t > m->modify) {
87438494Sobrien      plog(XLOG_INFO, "Map %s is out of date", m->map_name);
87538494Sobrien      mapc_sync(m);
87638494Sobrien    }
87738494Sobrien  }
87838494Sobrien
87938494Sobrien  if (!MAPC_ISRE(m)) {
88038494Sobrien    /*
88138494Sobrien     * Compute the hash table offset
88238494Sobrien     */
88338494Sobrien    k = m->kvhash[kvhash_of(key)];
88438494Sobrien
88538494Sobrien    /*
88638494Sobrien     * Scan the linked list for the key
88738494Sobrien     */
88838494Sobrien    while (k && !FSTREQ(k->key, key))
88938494Sobrien      k = k->next;
89038494Sobrien
89138494Sobrien  }
89238494Sobrien
89338494Sobrien#ifdef HAVE_REGEXEC
89438494Sobrien  else if (recurse == MREC_FULL) {
89538494Sobrien    /*
89638494Sobrien     * Try for an RE match against the entire map.
89738494Sobrien     * Note that this will be done in a "random"
89838494Sobrien     * order.
89938494Sobrien     */
90038494Sobrien    int i;
90138494Sobrien
90238494Sobrien    for (i = 0; i < NKVHASH; i++) {
90338494Sobrien      k = m->kvhash[i];
90438494Sobrien      while (k) {
90538494Sobrien	int retval;
90638494Sobrien
90738494Sobrien	/* XXX: this code was recently ported, and must be tested -Erez */
908310490Scy	retval = regexec(&k->re, key, 0, NULL, 0);
90938494Sobrien	if (retval == 0) {	/* succeeded */
91038494Sobrien	  break;
91138494Sobrien	} else {		/* failed to match, log error */
91238494Sobrien	  char errstr[256];
91338494Sobrien
91438494Sobrien	  errstr[0] = '\0';
91538494Sobrien	  regerror(retval, &k->re, errstr, 256);
91638494Sobrien	  plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s",
91738494Sobrien	       key, k->key, errstr);
91838494Sobrien	}
91938494Sobrien	k = k->next;
92038494Sobrien      }
92138494Sobrien      if (k)
92238494Sobrien	break;
92338494Sobrien    }
92438494Sobrien  }
92538494Sobrien#endif /* HAVE_REGEXEC */
92638494Sobrien
92738494Sobrien  /*
92838494Sobrien   * If found then take a copy
92938494Sobrien   */
93038494Sobrien  if (k) {
93138494Sobrien    if (k->val)
932310490Scy      *pval = xstrdup(k->val);
93338494Sobrien    else
93438494Sobrien      error = ENOENT;
93538494Sobrien  } else if (m->alloc >= MAPC_ALL) {
93638494Sobrien    /*
93738494Sobrien     * If the entire map is cached then this
93838494Sobrien     * key does not exist.
93938494Sobrien     */
94038494Sobrien    error = ENOENT;
94138494Sobrien  } else {
94238494Sobrien    /*
94338494Sobrien     * Otherwise search the map.  If we are
94438494Sobrien     * in incremental mode then add the key
94538494Sobrien     * to the cache.
94638494Sobrien     */
94738494Sobrien    error = search_map(m, key, pval);
94838494Sobrien    if (!error && m->alloc == MAPC_INC)
949310490Scy      mapc_add_kv(m, xstrdup(key), xstrdup(*pval));
95038494Sobrien  }
95138494Sobrien
95238494Sobrien  /*
95338494Sobrien   * If an error, and a wildcard exists,
95438494Sobrien   * and the key is not internal then
95538494Sobrien   * return a copy of the wildcard.
95638494Sobrien   */
95738494Sobrien  if (error > 0) {
95838494Sobrien    if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
95938494Sobrien      char wildname[MAXPATHLEN];
96038494Sobrien      char *subp;
96138494Sobrien      if (*key == '/')
96238494Sobrien	return error;
96338494Sobrien      /*
96438494Sobrien       * Keep chopping sub-directories from the RHS
96538494Sobrien       * and replacing with "/ *" and repeat the lookup.
96638494Sobrien       * For example:
96738494Sobrien       * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
96838494Sobrien       */
969174294Sobrien      xstrlcpy(wildname, key, sizeof(wildname));
97038494Sobrien      while (error && (subp = strrchr(wildname, '/'))) {
971174294Sobrien	/*
972174294Sobrien	 * sizeof space left in subp is sizeof wildname minus what's left
973174294Sobrien	 * after the strchr above returned a pointer inside wildname into
974174294Sobrien	 * subp.
975174294Sobrien	 */
976174294Sobrien	xstrlcpy(subp, "/*", sizeof(wildname) - (subp - wildname));
97738494Sobrien	dlog("mapc recurses on %s", wildname);
97838494Sobrien	error = mapc_meta_search(m, wildname, pval, MREC_PART);
97938494Sobrien	if (error)
980310490Scy	  *subp = '\0';
98138494Sobrien      }
98238494Sobrien
98338494Sobrien      if (error > 0 && m->wildcard) {
984310490Scy	*pval = xstrdup(m->wildcard);
98538494Sobrien	error = 0;
98638494Sobrien      }
98738494Sobrien    }
98838494Sobrien  }
98938494Sobrien  return error;
99038494Sobrien}
99138494Sobrien
99238494Sobrien
99338494Sobrienint
99438494Sobrienmapc_search(mnt_map *m, char *key, char **pval)
99538494Sobrien{
99638494Sobrien  return mapc_meta_search(m, key, pval, MREC_FULL);
99738494Sobrien}
99838494Sobrien
99938494Sobrien
100038494Sobrien/*
100138494Sobrien * Get map cache in sync with physical representation
100238494Sobrien */
100338494Sobrienstatic void
100438494Sobrienmapc_sync(mnt_map *m)
100538494Sobrien{
1006174294Sobrien  int need_mtime_update = 0;
100738494Sobrien
1008174294Sobrien  if (m->alloc == MAPC_ROOT)
1009174294Sobrien    return;			/* nothing to do */
1010174294Sobrien
1011174294Sobrien  /* do not clear map if map service is down */
1012174294Sobrien  if (m->isup) {
1013174294Sobrien    if (!((*m->isup)(m, m->map_name))) {
1014174294Sobrien      plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
1015174294Sobrien      return;
101638494Sobrien    }
1017174294Sobrien  }
101838494Sobrien
1019174294Sobrien  if (m->alloc >= MAPC_ALL) {
1020174294Sobrien    /* mapc_reload_map() always works */
1021174294Sobrien    need_mtime_update = mapc_reload_map(m);
1022174294Sobrien  } else {
1023174294Sobrien    mapc_clear(m);
1024174294Sobrien    /*
1025174294Sobrien     * Attempt to find the wildcard entry
1026174294Sobrien     */
1027174294Sobrien    mapc_find_wildcard(m);
1028174294Sobrien    need_mtime_update = 1;	/* because mapc_clear always works */
1029174294Sobrien  }
1030174294Sobrien
1031174294Sobrien  /*
1032174294Sobrien   * To be safe, update the mtime of the mnt_map's own node, so that the
1033174294Sobrien   * kernel will flush all of its cached entries.
1034174294Sobrien   */
1035174294Sobrien  if (need_mtime_update && m->cfm) {
1036174294Sobrien    am_node *mp = find_ap(m->cfm->cfm_dir);
1037174294Sobrien    if (mp) {
1038174294Sobrien      clocktime(&mp->am_fattr.na_mtime);
103952894Sobrien    } else {
1040174294Sobrien      plog(XLOG_ERROR, "cannot find map %s to update its mtime",
1041174294Sobrien	   m->cfm->cfm_dir);
104252894Sobrien    }
104338494Sobrien  }
104438494Sobrien}
104538494Sobrien
104638494Sobrien
104738494Sobrien/*
104838494Sobrien * Reload all the maps
104938494Sobrien * Called when Amd gets hit by a SIGHUP.
105038494Sobrien */
105138494Sobrienvoid
105238494Sobrienmapc_reload(void)
105338494Sobrien{
105438494Sobrien  mnt_map *m;
105538494Sobrien
105638494Sobrien  /*
105738494Sobrien   * For all the maps,
105838494Sobrien   * Throw away the existing information.
105938494Sobrien   * Do a reload
106038494Sobrien   * Find the wildcard
106138494Sobrien   */
106238494Sobrien  ITER(m, mnt_map, &map_list_head)
106338494Sobrien    mapc_sync(m);
106438494Sobrien}
106538494Sobrien
106638494Sobrien
106738494Sobrien/*
106838494Sobrien * Root map.
106938494Sobrien * The root map is used to bootstrap amd.
107038494Sobrien * All the require top-level mounts are added
107138494Sobrien * into the root map and then the map is iterated
107238494Sobrien * and a lookup is done on all the mount points.
107338494Sobrien * This causes the top level mounts to be automounted.
107438494Sobrien */
107538494Sobrienstatic int
107638494Sobrienroot_init(mnt_map *m, char *map, time_t *tp)
107738494Sobrien{
1078174294Sobrien  *tp = clocktime(NULL);
107938494Sobrien  return STREQ(map, ROOT_MAP) ? 0 : ENOENT;
108038494Sobrien}
108138494Sobrien
108238494Sobrien
108338494Sobrien/*
108438494Sobrien * Add a new entry to the root map
108538494Sobrien *
108638494Sobrien * dir - directory (key)
108738494Sobrien * opts - mount options
108838494Sobrien * map - map name
108938494Sobrien * cfm - optional amd configuration file map section structure
109038494Sobrien */
109138494Sobrienvoid
109238494Sobrienroot_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm)
109338494Sobrien{
109438494Sobrien  char str[MAXPATHLEN];
109538494Sobrien
109638494Sobrien  /*
109738494Sobrien   * First make sure we have a root map to talk about...
109838494Sobrien   */
109938494Sobrien  if (!root_map)
1100310490Scy    root_map = mapc_find(ROOT_MAP, "mapdefault", NULL, NULL);
110138494Sobrien
110238494Sobrien  /*
110338494Sobrien   * Then add the entry...
110438494Sobrien   */
110538494Sobrien
110638494Sobrien  /*
110738494Sobrien   * Here I plug in the code to process other amd.conf options like
110838494Sobrien   * map_type, search_path, and flags (browsable_dirs, mount_type).
110938494Sobrien   */
111038494Sobrien
111138494Sobrien  if (cfm) {
111238494Sobrien    if (map) {
1113174294Sobrien      xsnprintf(str, sizeof(str),
1114174294Sobrien		"cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"",
1115174294Sobrien		cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "nfs",
1116174294Sobrien		get_full_path(map, cfm->cfm_search_path, cfm->cfm_type));
111738494Sobrien      if (opts && opts[0] != '\0') {
1118174294Sobrien	xstrlcat(str, ";", sizeof(str));
1119174294Sobrien	xstrlcat(str, opts, sizeof(str));
112038494Sobrien      }
112138494Sobrien      if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL)
1122174294Sobrien	xstrlcat(str, ";opts:=rw,fullybrowsable", sizeof(str));
112338494Sobrien      if (cfm->cfm_flags & CFM_BROWSABLE_DIRS)
1124174294Sobrien	xstrlcat(str, ";opts:=rw,browsable", sizeof(str));
112538494Sobrien      if (cfm->cfm_type) {
1126174294Sobrien	xstrlcat(str, ";maptype:=", sizeof(str));
1127174294Sobrien	xstrlcat(str, cfm->cfm_type, sizeof(str));
112838494Sobrien      }
112938494Sobrien    } else {
1130174294Sobrien      xstrlcpy(str, opts, sizeof(str));
113138494Sobrien    }
113238494Sobrien  } else {
113338494Sobrien    if (map)
1134174294Sobrien      xsnprintf(str, sizeof(str),
1135174294Sobrien		"cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1136174294Sobrien		map, opts ? opts : "");
113738494Sobrien    else
1138174294Sobrien      xstrlcpy(str, opts, sizeof(str));
113938494Sobrien  }
1140310490Scy  mapc_repl_kv(root_map, xstrdup(dir), xstrdup(str));
114138494Sobrien}
114238494Sobrien
114338494Sobrien
114438494Sobrienint
1145174294Sobrienmapc_keyiter(mnt_map *m, key_fun *fn, opaque_t arg)
114638494Sobrien{
114738494Sobrien  int i;
114838494Sobrien  int c = 0;
114938494Sobrien
115038494Sobrien  for (i = 0; i < NKVHASH; i++) {
115138494Sobrien    kv *k = m->kvhash[i];
115238494Sobrien    while (k) {
115338494Sobrien      (*fn) (k->key, arg);
115438494Sobrien      k = k->next;
115538494Sobrien      c++;
115638494Sobrien    }
115738494Sobrien  }
115838494Sobrien
115938494Sobrien  return c;
116038494Sobrien}
116138494Sobrien
116238494Sobrien
116338494Sobrien/*
116438494Sobrien * Iterate on the root map and call (*fn)() on the key of all the nodes.
1165174294Sobrien * Returns the number of entries in the root map.
116638494Sobrien */
116738494Sobrienint
1168174294Sobrienroot_keyiter(key_fun *fn, opaque_t arg)
116938494Sobrien{
117038494Sobrien  if (root_map) {
117138494Sobrien    int c = mapc_keyiter(root_map, fn, arg);
117238494Sobrien    return c;
117338494Sobrien  }
117438494Sobrien
117538494Sobrien  return 0;
117638494Sobrien}
117738494Sobrien
117838494Sobrien
117938494Sobrien/*
118038494Sobrien * Error map
118138494Sobrien */
118238494Sobrienstatic int
118338494Sobrienerror_init(mnt_map *m, char *map, time_t *tp)
118438494Sobrien{
118538494Sobrien  plog(XLOG_USER, "No source data for map %s", map);
118638494Sobrien  *tp = 0;
118738494Sobrien
118838494Sobrien  return 0;
118938494Sobrien}
119038494Sobrien
119138494Sobrien
119238494Sobrienstatic int
119338494Sobrienerror_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
119438494Sobrien{
119538494Sobrien  return ENOENT;
119638494Sobrien}
119738494Sobrien
119838494Sobrien
119938494Sobrienstatic int
120038494Sobrienerror_reload(mnt_map *m, char *map, add_fn *fn)
120138494Sobrien{
120238494Sobrien  return ENOENT;
120338494Sobrien}
120438494Sobrien
120538494Sobrien
120638494Sobrienstatic int
120738494Sobrienerror_mtime(mnt_map *m, char *map, time_t *tp)
120838494Sobrien{
120938494Sobrien  *tp = 0;
121038494Sobrien
121138494Sobrien  return 0;
121238494Sobrien}
121338494Sobrien
121438494Sobrien
121538494Sobrien/*
121638494Sobrien * Return absolute path of map, searched in a type-specific path.
121738494Sobrien * Note: uses a static buffer for returned data.
121838494Sobrien */
121938494Sobrienstatic const char *
122038494Sobrienget_full_path(const char *map, const char *path, const char *type)
122138494Sobrien{
122238494Sobrien  char component[MAXPATHLEN], *str;
122338494Sobrien  static char full_path[MAXPATHLEN];
122438494Sobrien  int len;
122538494Sobrien
122638494Sobrien  /* for now, only file-type search paths are implemented */
122738494Sobrien  if (type && !STREQ(type, "file"))
122838494Sobrien    return map;
122938494Sobrien
123038494Sobrien  /* if null map, return it */
123138494Sobrien  if (!map)
123238494Sobrien    return map;
123338494Sobrien
123438494Sobrien  /* if map includes a '/', return it (absolute or relative path) */
123538494Sobrien  if (strchr(map, '/'))
123638494Sobrien    return map;
123738494Sobrien
123838494Sobrien  /* if path is empty, return map */
123938494Sobrien  if (!path)
124038494Sobrien    return map;
124138494Sobrien
124238494Sobrien  /* now break path into components, and search in each */
1243174294Sobrien  xstrlcpy(component, path, sizeof(component));
124438494Sobrien
124538494Sobrien  str = strtok(component, ":");
124638494Sobrien  do {
1247174294Sobrien    xstrlcpy(full_path, str, sizeof(full_path));
124838494Sobrien    len = strlen(full_path);
124938494Sobrien    if (full_path[len - 1] != '/') /* add trailing "/" if needed */
1250174294Sobrien      xstrlcat(full_path, "/", sizeof(full_path));
1251174294Sobrien    xstrlcat(full_path, map, sizeof(full_path));
125238494Sobrien    if (access(full_path, R_OK) == 0)
125338494Sobrien      return full_path;
125438494Sobrien    str = strtok(NULL, ":");
125538494Sobrien  } while (str);
125638494Sobrien
125738494Sobrien  return map;			/* if found nothing, return map */
125838494Sobrien}
1259