2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1989 Jan-Simon Pendry
4 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1989 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * File: am-utils/amd/mapc.c
46 #endif /* HAVE_CONFIG_H */
51 * Make a duplicate reference to an existing map
53 #define mapc_dup(m) ((m)->refc++, (m))
57 * default, none, incremental, all, regexp
58 * MAPC_RE implies MAPC_ALL and must be numerically
61 #define MAPC_DFLT 0x000
62 #define MAPC_NONE 0x001
63 #define MAPC_INC 0x002
64 #define MAPC_ROOT 0x004
65 #define MAPC_ALL 0x010
66 #define MAPC_CACHE_MASK 0x0ff
67 #define MAPC_SYNC 0x100
70 # define MAPC_RE 0x020
71 # define MAPC_ISRE(m) ((m)->alloc == MAPC_RE)
72 #else /* not HAVE_REGEXEC */
73 # define MAPC_ISRE(m) FALSE
74 #endif /* not HAVE_REGEXEC */
83 static struct opt_tab mapc_opt[] =
86 {"default", MAPC_DFLT},
88 {"mapdefault", MAPC_DFLT},
93 #endif /* HAVE_REGEXEC */
101 static char wildcard[] = "*";
106 typedef struct map_type map_type;
108 char *name; /* Name of this map type */
109 init_fn *init; /* Initialization */
110 reload_fn *reload; /* Reload or fill */
111 isup_fn *isup; /* Is service up or not? (1=up, 0=down) */
112 search_fn *search; /* Search for new entry */
113 mtime_fn *mtime; /* Find modify time */
114 int def_alloc; /* Default allocation mode */
120 static mnt_map *root_map;
125 qelem map_list_head = {&map_list_head, &map_list_head};
131 /* forward definitions */
132 static const char *get_full_path(const char *map, const char *path, const char *type);
133 static int mapc_meta_search(mnt_map *, char *, char **, int);
134 static void mapc_sync(mnt_map *);
135 static void mapc_clear(mnt_map *);
136 static void mapc_clear_kvhash(kv **);
139 static int root_init(mnt_map *, char *, time_t *);
142 static int error_init(mnt_map *, char *, time_t *);
143 static int error_reload(mnt_map *, char *, add_fn *);
144 static int error_search(mnt_map *, char *, char *, char **, time_t *);
145 static int error_mtime(mnt_map *, char *, time_t *);
148 #ifdef HAVE_MAP_PASSWD
149 extern int passwd_init(mnt_map *, char *, time_t *);
150 extern int passwd_search(mnt_map *, char *, char *, char **, time_t *);
151 #endif /* HAVE_MAP_PASSWD */
154 #ifdef HAVE_MAP_HESIOD
155 extern int amu_hesiod_init(mnt_map *, char *map, time_t *tp);
156 extern int hesiod_isup(mnt_map *, char *);
157 extern int hesiod_search(mnt_map *, char *, char *, char **, time_t *);
158 #endif /* HAVE_MAP_HESIOD */
162 extern int amu_ldap_init(mnt_map *, char *map, time_t *tp);
163 extern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *);
164 extern int amu_ldap_mtime(mnt_map *, char *, time_t *);
165 #endif /* HAVE_MAP_LDAP */
168 #ifdef HAVE_MAP_UNION
169 extern int union_init(mnt_map *, char *, time_t *);
170 extern int union_search(mnt_map *, char *, char *, char **, time_t *);
171 extern int union_reload(mnt_map *, char *, add_fn *);
172 #endif /* HAVE_MAP_UNION */
174 /* Network Information Service PLUS (NIS+) */
175 #ifdef HAVE_MAP_NISPLUS
176 extern int nisplus_init(mnt_map *, char *, time_t *);
177 extern int nisplus_reload(mnt_map *, char *, add_fn *);
178 extern int nisplus_search(mnt_map *, char *, char *, char **, time_t *);
179 extern int nisplus_mtime(mnt_map *, char *, time_t *);
180 #endif /* HAVE_MAP_NISPLUS */
182 /* Network Information Service (YP, Yellow Pages) */
184 extern int nis_init(mnt_map *, char *, time_t *);
185 extern int nis_reload(mnt_map *, char *, add_fn *);
186 extern int nis_isup(mnt_map *, char *);
187 extern int nis_search(mnt_map *, char *, char *, char **, time_t *);
188 extern int nis_mtime(mnt_map *, char *, time_t *);
189 #endif /* HAVE_MAP_NIS */
193 extern int ndbm_init(mnt_map *, char *, time_t *);
194 extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *);
195 extern int ndbm_mtime(mnt_map *, char *, time_t *);
196 #endif /* HAVE_MAP_NDBM */
200 extern int file_init_or_mtime(mnt_map *, char *, time_t *);
201 extern int file_reload(mnt_map *, char *, add_fn *);
202 extern int file_search(mnt_map *, char *, char *, char **, time_t *);
203 #endif /* HAVE_MAP_FILE */
205 /* EXECUTABLE MAPS */
207 extern int exec_init(mnt_map *, char *, time_t *);
208 extern int exec_search(mnt_map *, char *, char *, char **, time_t *);
209 #endif /* HAVE_MAP_EXEC */
211 /* Sun-syntax MAPS */
214 #endif /* HAVE_MAP_SUN */
216 /* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */
217 static map_type maptypes[] =
223 NULL, /* isup function */
228 #ifdef HAVE_MAP_PASSWD
233 NULL, /* isup function */
238 #endif /* HAVE_MAP_PASSWD */
239 #ifdef HAVE_MAP_HESIOD
244 hesiod_isup, /* is Hesiod up or not? */
249 #endif /* HAVE_MAP_HESIOD */
255 NULL, /* isup function */
260 #endif /* HAVE_MAP_LDAP */
261 #ifdef HAVE_MAP_UNION
266 NULL, /* isup function */
271 #endif /* HAVE_MAP_UNION */
272 #ifdef HAVE_MAP_NISPLUS
277 NULL, /* isup function */
282 #endif /* HAVE_MAP_NISPLUS */
288 nis_isup, /* is NIS up or not? */
293 #endif /* HAVE_MAP_NIS */
299 NULL, /* isup function */
304 #endif /* HAVE_MAP_NDBM */
310 NULL, /* isup function */
315 #endif /* HAVE_MAP_FILE */
321 NULL, /* isup function */
326 #endif /* HAVE_MAP_EXEC */
327 #ifdef notyet /* probe function needs to be there or SEGV */
334 NULL, /* isup function */
339 #endif /* HAVE_MAP_SUN */
345 NULL, /* isup function */
361 for (i = 0; (j = *key++); i += j) ;
368 mapc_showtypes(char *buf, size_t l)
370 map_type *mt=NULL, *lastmt;
373 i = sizeof(maptypes) / sizeof(maptypes[0]);
374 lastmt = maptypes + i;
376 for (mt = maptypes; mt < lastmt; mt++) {
377 xstrlcat(buf, mt->name, l);
378 if (mt == (lastmt-1))
379 break; /* if last one, don't do xstrlcat's that follows */
380 linesize += strlen(mt->name);
382 xstrlcat(buf, ", ", l);
387 xstrlcat(buf, "\n\t\t ", l);
394 * Check if a map of a certain type exists.
395 * Return 1 (true) if exists, 0 (false) if not.
398 mapc_type_exists(const char *type)
405 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
407 if (STREQ(type, mt->name))
410 return 0; /* not found anywhere */
415 * Add key and val to the map m.
416 * key and val are assumed to be safe copies
419 mapc_add_kv(mnt_map *m, char *key, char *val)
423 int hash = kvhash_of(key);
426 #endif /* HAVE_REGEXEC */
428 dlog("add_kv: %s -> %s", key, val);
430 if (val != NULL && strchr(val, '\n') != NULL) {
432 * If the entry value contains multiple lines we need to break
433 * them up and add them recursively. This is a workaround to
434 * support Sun style multi-mounts. Amd converts Sun style
435 * mulit-mounts to type:=auto. The problem is that Sun packs all
436 * the entries on one line. When Amd does the conversion it puts
437 * each type:=auto entry on the same line separated by '\n'.
442 * The first line should contain the first entry. The key for
443 * this entry is the key passed into this function.
445 if ((tok = strtok(val, "\n")) != NULL) {
446 mapc_add_kv(m, key, xstrdup(tok));
450 * For the rest of the entries we need to tokenize them by '\n'
451 * and separate the keys from there entries.
453 while ((tok = strtok(NULL, "\n")) != NULL) {
456 for (entry = key; *entry && !isspace((unsigned char)*entry); entry++);
461 mapc_add_kv(m, xstrdup(key), xstrdup(entry));
470 char pattern[MAXPATHLEN];
474 * Make sure the string is bound to the start and end
476 xsnprintf(pattern, sizeof(pattern), "^%s$", key);
477 retval = regcomp(&re, pattern, REG_ICASE);
481 /* XXX: this code was recently ported, and must be tested -Erez */
483 regerror(retval, &re, errstr, 256);
484 plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr);
488 memset(&re, 0, sizeof(re));
489 #endif /* HAVE_REGEXEC */
491 h = &m->kvhash[hash];
492 n = ALLOC(struct kv);
495 memcpy(&n->re, &re, sizeof(regex_t));
496 #endif /* HAVE_REGEXEC */
505 mapc_repl_kv(mnt_map *m, char *key, char *val)
510 * Compute the hash table offset
512 k = m->kvhash[kvhash_of(key)];
515 * Scan the linked list for the key
517 while (k && !FSTREQ(k->key, key))
524 mapc_add_kv(m, key, val);
530 * Search a map for a key.
531 * Calls map specific search routine.
532 * While map is out of date, keep re-syncing.
535 search_map(mnt_map *m, char *key, char **valp)
540 rc = (*m->search) (m, m->map_name, key, valp, &m->modify);
542 plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
552 * Do a wildcard lookup in the map and
556 mapc_find_wildcard(mnt_map *m)
559 * Attempt to find the wildcard entry
561 int rc = search_map(m, wildcard, &m->wildcard);
570 * Attempt to reload without losing current data by switching the hashes
572 * If reloading was needed and succeeded, return 1; else return 0.
575 mapc_reload_map(mnt_map *m)
578 kv *maphash[NKVHASH];
581 error = (*m->mtime) (m, m->map_name, &t);
587 * skip reloading maps that have not been modified, unless
588 * amq -f was used (do_mapc_reload is 0)
590 if (m->reloads != 0 && do_mapc_reload != 0) {
591 if (t <= m->modify) {
592 plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name);
593 dlog("map %s last load time is %d, last modify time is %d",
594 m->map_name, (int) m->modify, (int) t);
599 /* copy the old hash and zero the map */
600 memcpy((voidp) maphash, (voidp) m->kvhash, sizeof(m->kvhash));
601 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
603 dlog("calling map reload on %s", m->map_name);
605 error = (*m->reload) (m, m->map_name, mapc_add_kv);
608 plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name);
610 plog(XLOG_ERROR, "reload of map %s failed - using old values",
613 memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash));
615 if (m->reloads++ == 0)
616 plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name);
618 plog(XLOG_INFO, "reload #%d of map %s succeeded",
619 m->reloads, m->map_name);
620 mapc_clear_kvhash(maphash);
629 dlog("calling mapc_search for wildcard");
630 error = mapc_search(m, wildcard, &m->wildcard);
641 mapc_create(char *map, char *opt, const char *type, const char *mntpt)
643 mnt_map *m = ALLOC(struct mnt_map);
648 cmdoption(opt, mapc_opt, &alloc);
651 * If using a configuration file, and the map_type is defined, then look
652 * for it, in the maptypes array. If found, initialize the map using that
653 * map_type. If not found, return error. If no map_type was defined,
654 * default to cycling through all maptypes.
656 if (use_conf_file && type) {
657 /* find what type of map this one is */
659 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
661 if (STREQ(type, mt->name)) {
662 plog(XLOG_INFO, "initializing amd.conf map %s of type %s", map, type);
663 if ((*mt->init) (m, map, &modify) == 0) {
666 plog(XLOG_ERROR, "failed to initialize map %s", map);
667 error_init(m, map, &modify);
671 } /* end of "for (mt =" loop */
673 } else { /* cycle through all known maptypes */
676 * not using amd conf file or using it by w/o specifying map type
679 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
681 dlog("trying to initialize map %s of type %s ...", map, mt->name);
682 if ((*mt->init) (m, map, &modify) == 0) {
686 } /* end of "if (use_conf_file && (colpos = strchr ..." statement */
688 /* assert: mt in maptypes */
690 m->flags = alloc & ~MAPC_CACHE_MASK;
692 alloc &= MAPC_CACHE_MASK;
694 if (alloc == MAPC_DFLT)
695 alloc = mt->def_alloc;
699 plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
701 /* fall-through... */
709 * If there is no support for reload and it was requested
710 * then back off to incremental instead.
712 if (mt->reload == error_reload) {
713 plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name);
720 if (mt->reload == error_reload) {
721 plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name);
722 mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1];
723 /* assert: mt->name == "error" */
726 #endif /* HAVE_REGEXEC */
729 dlog("Map for %s coming from maptype %s", map, mt->name);
732 m->reload = mt->reload;
735 m->search = alloc >= MAPC_ALL ? error_search : mt->search;
736 m->mtime = mt->mtime;
737 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
738 m->map_name = xstrdup(map);
742 /* initialize per-map information (flags, etc.) */
743 m->cfm = find_cf_map(mntpt);
746 * synchronize cache with reality
755 * Free the cached data in a map hash
758 mapc_clear_kvhash(kv **kvhash)
763 * For each of the hash slots, chain
764 * along free'ing the data.
766 for (i = 0; i < NKVHASH; i++) {
780 * Free the cached data in a map
783 mapc_clear(mnt_map *m)
785 mapc_clear_kvhash(m->kvhash);
788 * Zero the hash slots
790 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
793 * Free the wildcard if it exists
803 * Find a map, or create one if it does not exist
806 mapc_find(char *map, char *opt, const char *maptype, const char *mntpt)
811 * Search the list of known maps to see if
812 * it has already been loaded. If it is found
813 * then return a duplicate reference to it.
814 * Otherwise make a new map as required and
815 * add it to the list of maps
817 ITER(m, mnt_map, &map_list_head)
818 if (STREQ(m->map_name, map))
820 m = mapc_create(map, opt, maptype, mntpt);
821 ins_que(&m->hdr, &map_list_head);
831 mapc_free(opaque_t arg)
833 mnt_map *m = (mnt_map *) arg;
836 * Decrement the reference count.
837 * If the reference count hits zero
838 * then throw the map away.
840 if (m && --m->refc == 0) {
850 * Search the map for the key. Put a safe (malloc'ed) copy in *pval or
851 * return an error code
854 mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
863 plog(XLOG_ERROR, "Null map request for %s", key);
867 if (m->flags & MAPC_SYNC) {
872 error = (*m->mtime) (m, m->map_name, &t);
873 if (error || t > m->modify) {
874 plog(XLOG_INFO, "Map %s is out of date", m->map_name);
881 * Compute the hash table offset
883 k = m->kvhash[kvhash_of(key)];
886 * Scan the linked list for the key
888 while (k && !FSTREQ(k->key, key))
894 else if (recurse == MREC_FULL) {
896 * Try for an RE match against the entire map.
897 * Note that this will be done in a "random"
902 for (i = 0; i < NKVHASH; i++) {
907 /* XXX: this code was recently ported, and must be tested -Erez */
908 retval = regexec(&k->re, key, 0, NULL, 0);
909 if (retval == 0) { /* succeeded */
911 } else { /* failed to match, log error */
915 regerror(retval, &k->re, errstr, 256);
916 plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s",
917 key, k->key, errstr);
925 #endif /* HAVE_REGEXEC */
928 * If found then take a copy
932 *pval = xstrdup(k->val);
935 } else if (m->alloc >= MAPC_ALL) {
937 * If the entire map is cached then this
938 * key does not exist.
943 * Otherwise search the map. If we are
944 * in incremental mode then add the key
947 error = search_map(m, key, pval);
948 if (!error && m->alloc == MAPC_INC)
949 mapc_add_kv(m, xstrdup(key), xstrdup(*pval));
953 * If an error, and a wildcard exists,
954 * and the key is not internal then
955 * return a copy of the wildcard.
958 if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
959 char wildname[MAXPATHLEN];
964 * Keep chopping sub-directories from the RHS
965 * and replacing with "/ *" and repeat the lookup.
967 * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
969 xstrlcpy(wildname, key, sizeof(wildname));
970 while (error && (subp = strrchr(wildname, '/'))) {
972 * sizeof space left in subp is sizeof wildname minus what's left
973 * after the strchr above returned a pointer inside wildname into
976 xstrlcpy(subp, "/*", sizeof(wildname) - (subp - wildname));
977 dlog("mapc recurses on %s", wildname);
978 error = mapc_meta_search(m, wildname, pval, MREC_PART);
983 if (error > 0 && m->wildcard) {
984 *pval = xstrdup(m->wildcard);
994 mapc_search(mnt_map *m, char *key, char **pval)
996 return mapc_meta_search(m, key, pval, MREC_FULL);
1001 * Get map cache in sync with physical representation
1004 mapc_sync(mnt_map *m)
1006 int need_mtime_update = 0;
1008 if (m->alloc == MAPC_ROOT)
1009 return; /* nothing to do */
1011 /* do not clear map if map service is down */
1013 if (!((*m->isup)(m, m->map_name))) {
1014 plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
1019 if (m->alloc >= MAPC_ALL) {
1020 /* mapc_reload_map() always works */
1021 need_mtime_update = mapc_reload_map(m);
1025 * Attempt to find the wildcard entry
1027 mapc_find_wildcard(m);
1028 need_mtime_update = 1; /* because mapc_clear always works */
1032 * To be safe, update the mtime of the mnt_map's own node, so that the
1033 * kernel will flush all of its cached entries.
1035 if (need_mtime_update && m->cfm) {
1036 am_node *mp = find_ap(m->cfm->cfm_dir);
1038 clocktime(&mp->am_fattr.na_mtime);
1040 plog(XLOG_ERROR, "cannot find map %s to update its mtime",
1048 * Reload all the maps
1049 * Called when Amd gets hit by a SIGHUP.
1058 * Throw away the existing information.
1062 ITER(m, mnt_map, &map_list_head)
1069 * The root map is used to bootstrap amd.
1070 * All the require top-level mounts are added
1071 * into the root map and then the map is iterated
1072 * and a lookup is done on all the mount points.
1073 * This causes the top level mounts to be automounted.
1076 root_init(mnt_map *m, char *map, time_t *tp)
1078 *tp = clocktime(NULL);
1079 return STREQ(map, ROOT_MAP) ? 0 : ENOENT;
1084 * Add a new entry to the root map
1086 * dir - directory (key)
1087 * opts - mount options
1089 * cfm - optional amd configuration file map section structure
1092 root_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm)
1094 char str[MAXPATHLEN];
1097 * First make sure we have a root map to talk about...
1100 root_map = mapc_find(ROOT_MAP, "mapdefault", NULL, NULL);
1103 * Then add the entry...
1107 * Here I plug in the code to process other amd.conf options like
1108 * map_type, search_path, and flags (browsable_dirs, mount_type).
1113 xsnprintf(str, sizeof(str),
1114 "cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"",
1115 cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "nfs",
1116 get_full_path(map, cfm->cfm_search_path, cfm->cfm_type));
1117 if (opts && opts[0] != '\0') {
1118 xstrlcat(str, ";", sizeof(str));
1119 xstrlcat(str, opts, sizeof(str));
1121 if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL)
1122 xstrlcat(str, ";opts:=rw,fullybrowsable", sizeof(str));
1123 if (cfm->cfm_flags & CFM_BROWSABLE_DIRS)
1124 xstrlcat(str, ";opts:=rw,browsable", sizeof(str));
1125 if (cfm->cfm_type) {
1126 xstrlcat(str, ";maptype:=", sizeof(str));
1127 xstrlcat(str, cfm->cfm_type, sizeof(str));
1130 xstrlcpy(str, opts, sizeof(str));
1134 xsnprintf(str, sizeof(str),
1135 "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1136 map, opts ? opts : "");
1138 xstrlcpy(str, opts, sizeof(str));
1140 mapc_repl_kv(root_map, xstrdup(dir), xstrdup(str));
1145 mapc_keyiter(mnt_map *m, key_fun *fn, opaque_t arg)
1150 for (i = 0; i < NKVHASH; i++) {
1151 kv *k = m->kvhash[i];
1153 (*fn) (k->key, arg);
1164 * Iterate on the root map and call (*fn)() on the key of all the nodes.
1165 * Returns the number of entries in the root map.
1168 root_keyiter(key_fun *fn, opaque_t arg)
1171 int c = mapc_keyiter(root_map, fn, arg);
1183 error_init(mnt_map *m, char *map, time_t *tp)
1185 plog(XLOG_USER, "No source data for map %s", map);
1193 error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
1200 error_reload(mnt_map *m, char *map, add_fn *fn)
1207 error_mtime(mnt_map *m, char *map, time_t *tp)
1216 * Return absolute path of map, searched in a type-specific path.
1217 * Note: uses a static buffer for returned data.
1220 get_full_path(const char *map, const char *path, const char *type)
1222 char component[MAXPATHLEN], *str;
1223 static char full_path[MAXPATHLEN];
1226 /* for now, only file-type search paths are implemented */
1227 if (type && !STREQ(type, "file"))
1230 /* if null map, return it */
1234 /* if map includes a '/', return it (absolute or relative path) */
1235 if (strchr(map, '/'))
1238 /* if path is empty, return map */
1242 /* now break path into components, and search in each */
1243 xstrlcpy(component, path, sizeof(component));
1245 str = strtok(component, ":");
1247 xstrlcpy(full_path, str, sizeof(full_path));
1248 len = strlen(full_path);
1249 if (full_path[len - 1] != '/') /* add trailing "/" if needed */
1250 xstrlcat(full_path, "/", sizeof(full_path));
1251 xstrlcat(full_path, map, sizeof(full_path));
1252 if (access(full_path, R_OK) == 0)
1254 str = strtok(NULL, ":");
1257 return map; /* if found nothing, return map */