4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1989 Jan-Simon Pendry
6 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1989 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/amd/mapc.c
52 #endif /* HAVE_CONFIG_H */
57 * Make a duplicate reference to an existing map
59 #define mapc_dup(m) ((m)->refc++, (m))
63 * default, none, incremental, all, regexp
64 * MAPC_RE implies MAPC_ALL and must be numerically
67 #define MAPC_DFLT 0x000
68 #define MAPC_NONE 0x001
69 #define MAPC_INC 0x002
70 #define MAPC_ROOT 0x004
71 #define MAPC_ALL 0x010
72 #define MAPC_CACHE_MASK 0x0ff
73 #define MAPC_SYNC 0x100
76 # define MAPC_RE 0x020
77 # define MAPC_ISRE(m) ((m)->alloc == MAPC_RE)
78 #else /* not HAVE_REGEXEC */
79 # define MAPC_ISRE(m) FALSE
80 #endif /* not HAVE_REGEXEC */
89 static struct opt_tab mapc_opt
[] =
92 {"default", MAPC_DFLT
},
94 {"mapdefault", MAPC_DFLT
},
99 #endif /* HAVE_REGEXEC */
107 static char wildcard
[] = "*";
112 typedef struct map_type map_type
;
114 char *name
; /* Name of this map type */
115 init_fn
*init
; /* Initialization */
116 reload_fn
*reload
; /* Reload or fill */
117 isup_fn
*isup
; /* Is service up or not? (1=up, 0=down) */
118 search_fn
*search
; /* Search for new entry */
119 mtime_fn
*mtime
; /* Find modify time */
120 int def_alloc
; /* Default allocation mode */
126 static mnt_map
*root_map
;
131 qelem map_list_head
= {&map_list_head
, &map_list_head
};
137 /* forward definitions */
138 static const char *get_full_path(const char *map
, const char *path
, const char *type
);
139 static int mapc_meta_search(mnt_map
*, char *, char **, int);
140 static void mapc_sync(mnt_map
*);
141 static void mapc_clear(mnt_map
*);
144 static int root_init(mnt_map
*, char *, time_t *);
147 static int error_init(mnt_map
*, char *, time_t *);
148 static int error_reload(mnt_map
*, char *, add_fn
*);
149 static int error_search(mnt_map
*, char *, char *, char **, time_t *);
150 static int error_mtime(mnt_map
*, char *, time_t *);
153 #ifdef HAVE_MAP_PASSWD
154 extern int passwd_init(mnt_map
*, char *, time_t *);
155 extern int passwd_search(mnt_map
*, char *, char *, char **, time_t *);
156 #endif /* HAVE_MAP_PASSWD */
159 #ifdef HAVE_MAP_HESIOD
160 extern int amu_hesiod_init(mnt_map
*, char *map
, time_t *tp
);
161 extern int hesiod_isup(mnt_map
*, char *);
162 extern int hesiod_search(mnt_map
*, char *, char *, char **, time_t *);
163 #endif /* HAVE_MAP_HESIOD */
167 extern int amu_ldap_init(mnt_map
*, char *map
, time_t *tp
);
168 extern int amu_ldap_search(mnt_map
*, char *, char *, char **, time_t *);
169 extern int amu_ldap_mtime(mnt_map
*, char *, time_t *);
170 #endif /* HAVE_MAP_LDAP */
173 #ifdef HAVE_MAP_UNION
174 extern int union_init(mnt_map
*, char *, time_t *);
175 extern int union_search(mnt_map
*, char *, char *, char **, time_t *);
176 extern int union_reload(mnt_map
*, char *, add_fn
*);
177 #endif /* HAVE_MAP_UNION */
179 /* Network Information Service PLUS (NIS+) */
180 #ifdef HAVE_MAP_NISPLUS
181 extern int nisplus_init(mnt_map
*, char *, time_t *);
182 extern int nisplus_reload(mnt_map
*, char *, add_fn
*);
183 extern int nisplus_search(mnt_map
*, char *, char *, char **, time_t *);
184 extern int nisplus_mtime(mnt_map
*, char *, time_t *);
185 #endif /* HAVE_MAP_NISPLUS */
187 /* Network Information Service (YP, Yellow Pages) */
189 extern int nis_init(mnt_map
*, char *, time_t *);
190 extern int nis_reload(mnt_map
*, char *, add_fn
*);
191 extern int nis_isup(mnt_map
*, char *);
192 extern int nis_search(mnt_map
*, char *, char *, char **, time_t *);
193 extern int nis_mtime(mnt_map
*, char *, time_t *);
194 #endif /* HAVE_MAP_NIS */
198 extern int ndbm_init(mnt_map
*, char *, time_t *);
199 extern int ndbm_search(mnt_map
*, char *, char *, char **, time_t *);
200 extern int ndbm_mtime(mnt_map
*, char *, time_t *);
201 #endif /* HAVE_MAP_NDBM */
205 extern int file_init_or_mtime(mnt_map
*, char *, time_t *);
206 extern int file_reload(mnt_map
*, char *, add_fn
*);
207 extern int file_search(mnt_map
*, char *, char *, char **, time_t *);
208 #endif /* HAVE_MAP_FILE */
210 /* EXECUTABLE MAPS */
212 extern int exec_init(mnt_map
*, char *, time_t *);
213 extern int exec_search(mnt_map
*, char *, char *, char **, time_t *);
214 #endif /* HAVE_MAP_EXEC */
216 /* Sun-syntax MAPS */
219 #endif /* HAVE_MAP_SUN */
221 /* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */
222 static map_type maptypes
[] =
228 NULL
, /* isup function */
233 #ifdef HAVE_MAP_PASSWD
238 NULL
, /* isup function */
243 #endif /* HAVE_MAP_PASSWD */
244 #ifdef HAVE_MAP_HESIOD
249 hesiod_isup
, /* is Hesiod up or not? */
254 #endif /* HAVE_MAP_HESIOD */
260 NULL
, /* isup function */
265 #endif /* HAVE_MAP_LDAP */
266 #ifdef HAVE_MAP_UNION
271 NULL
, /* isup function */
276 #endif /* HAVE_MAP_UNION */
277 #ifdef HAVE_MAP_NISPLUS
282 NULL
, /* isup function */
287 #endif /* HAVE_MAP_NISPLUS */
293 nis_isup
, /* is NIS up or not? */
298 #endif /* HAVE_MAP_NIS */
304 NULL
, /* isup function */
309 #endif /* HAVE_MAP_NDBM */
315 NULL
, /* isup function */
320 #endif /* HAVE_MAP_FILE */
326 NULL
, /* isup function */
331 #endif /* HAVE_MAP_EXEC */
338 NULL
, /* isup function */
343 #endif /* HAVE_MAP_SUN */
348 NULL
, /* isup function */
364 for (i
= 0; (j
= *key
++); i
+= j
) ;
371 mapc_showtypes(char *buf
, size_t l
)
373 map_type
*mt
=NULL
, *lastmt
;
376 i
= sizeof(maptypes
) / sizeof(maptypes
[0]);
377 lastmt
= maptypes
+ i
;
379 for (mt
= maptypes
; mt
< lastmt
; mt
++) {
380 xstrlcat(buf
, mt
->name
, l
);
381 if (mt
== (lastmt
-1))
382 break; /* if last one, don't do xstrlcat's that follows */
383 linesize
+= strlen(mt
->name
);
385 xstrlcat(buf
, ", ", l
);
390 xstrlcat(buf
, "\n\t\t ", l
);
397 * Check if a map of a certain type exists.
398 * Return 1 (true) if exists, 0 (false) if not.
401 mapc_type_exists(const char *type
)
408 mt
< maptypes
+ sizeof(maptypes
) / sizeof(maptypes
[0]);
410 if (STREQ(type
, mt
->name
))
413 return 0; /* not found anywhere */
418 * Add key and val to the map m.
419 * key and val are assumed to be safe copies
422 mapc_add_kv(mnt_map
*m
, char *key
, char *val
)
426 int hash
= kvhash_of(key
);
429 #endif /* HAVE_REGEXEC */
431 dlog("add_kv: %s -> %s", key
, val
);
433 if (val
!= NULL
&& strchr(val
, '\n') != NULL
) {
435 * If the entry value contains multiple lines we need to break
436 * them up and add them recursively. This is a workaround to
437 * support Sun style multi-mounts. Amd converts Sun style
438 * mulit-mounts to type:=auto. The problem is that Sun packs all
439 * the entries on one line. When Amd does the conversion it puts
440 * each type:=auto entry on the same line separated by '\n'.
445 * The first line should contain the first entry. The key for
446 * this entry is the key passed into this function.
448 if ((tok
= strtok(val
, "\n")) != NULL
) {
449 mapc_add_kv(m
, key
, strdup(tok
));
453 * For the rest of the entries we need to tokenize them by '\n'
454 * and separate the keys from there entries.
456 while ((tok
= strtok(NULL
, "\n")) != NULL
) {
459 for (entry
= key
; *entry
&& !isspace((unsigned char)*entry
); entry
++);
464 mapc_add_kv(m
, strdup(key
), strdup(entry
));
473 char pattern
[MAXPATHLEN
];
477 * Make sure the string is bound to the start and end
479 xsnprintf(pattern
, sizeof(pattern
), "^%s$", key
);
480 retval
= regcomp(&re
, pattern
, REG_ICASE
);
484 /* XXX: this code was recently ported, and must be tested -Erez */
486 regerror(retval
, &re
, errstr
, 256);
487 plog(XLOG_USER
, "error compiling RE \"%s\": %s", pattern
, errstr
);
491 #endif /* HAVE_REGEXEC */
493 h
= &m
->kvhash
[hash
];
494 n
= ALLOC(struct kv
);
497 memcpy(&n
->re
, &re
, sizeof(regex_t
));
498 #endif /* HAVE_REGEXEC */
506 mapc_repl_kv(mnt_map
*m
, char *key
, char *val
)
511 * Compute the hash table offset
513 k
= m
->kvhash
[kvhash_of(key
)];
516 * Scan the linked list for the key
518 while (k
&& !FSTREQ(k
->key
, key
))
525 mapc_add_kv(m
, key
, val
);
531 * Search a map for a key.
532 * Calls map specific search routine.
533 * While map is out of date, keep re-syncing.
536 search_map(mnt_map
*m
, char *key
, char **valp
)
541 rc
= (*m
->search
) (m
, m
->map_name
, key
, valp
, &m
->modify
);
543 plog(XLOG_MAP
, "Re-synchronizing cache for map %s", m
->map_name
);
553 * Do a wildcard lookup in the map and
557 mapc_find_wildcard(mnt_map
*m
)
560 * Attempt to find the wildcard entry
562 int rc
= search_map(m
, wildcard
, &m
->wildcard
);
571 * Attempt to reload without losing current data by switching the hashes
573 * If reloading was needed and succeeded, return 1; else return 0.
576 mapc_reload_map(mnt_map
*m
)
579 kv
*maphash
[NKVHASH
], *tmphash
[NKVHASH
];
582 error
= (*m
->mtime
) (m
, m
->map_name
, &t
);
588 * skip reloading maps that have not been modified, unless
589 * amq -f was used (do_mapc_reload is 0)
591 if (m
->reloads
!= 0 && do_mapc_reload
!= 0) {
592 if (t
<= m
->modify
) {
593 plog(XLOG_INFO
, "reload of map %s is not needed (in sync)", m
->map_name
);
594 dlog("map %s last load time is %d, last modify time is %d",
595 m
->map_name
, (int) m
->modify
, (int) t
);
600 /* copy the old hash and zero the map */
601 memcpy((voidp
) maphash
, (voidp
) m
->kvhash
, sizeof(m
->kvhash
));
602 memset((voidp
) m
->kvhash
, 0, sizeof(m
->kvhash
));
604 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 memcpy((voidp
) tmphash
, (voidp
) m
->kvhash
, sizeof(m
->kvhash
));
621 memcpy((voidp
) m
->kvhash
, (voidp
) maphash
, sizeof(m
->kvhash
));
623 memcpy((voidp
) m
->kvhash
, (voidp
) tmphash
, sizeof(m
->kvhash
));
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
;
691 alloc
&= MAPC_CACHE_MASK
;
693 if (alloc
== MAPC_DFLT
)
694 alloc
= mt
->def_alloc
;
698 plog(XLOG_USER
, "Ambiguous map cache type \"%s\"; using \"inc\"", opt
);
700 /* fall-through... */
708 * If there is no support for reload and it was requested
709 * then back off to incremental instead.
711 if (mt
->reload
== error_reload
) {
712 plog(XLOG_WARNING
, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt
->name
);
719 if (mt
->reload
== error_reload
) {
720 plog(XLOG_WARNING
, "Map type \"%s\" does not support cache type \"re\"", mt
->name
);
721 mt
= &maptypes
[sizeof(maptypes
) / sizeof(maptypes
[0]) - 1];
722 /* assert: mt->name == "error" */
725 #endif /* HAVE_REGEXEC */
728 dlog("Map for %s coming from maptype %s", map
, mt
->name
);
731 m
->reload
= mt
->reload
;
734 m
->search
= alloc
>= MAPC_ALL
? error_search
: mt
->search
;
735 m
->mtime
= mt
->mtime
;
736 memset((voidp
) m
->kvhash
, 0, sizeof(m
->kvhash
));
737 m
->map_name
= strdup(map
);
741 /* initialize per-map information (flags, etc.) */
742 m
->cfm
= find_cf_map(mntpt
);
745 * synchronize cache with reality
754 * Free the cached data in a map
757 mapc_clear(mnt_map
*m
)
762 * For each of the hash slots, chain
763 * along free'ing the data.
765 for (i
= 0; i
< NKVHASH
; i
++) {
766 kv
*k
= m
->kvhash
[i
];
778 * Zero the hash slots
780 memset((voidp
) m
->kvhash
, 0, sizeof(m
->kvhash
));
783 * Free the wildcard if it exists
791 * Find a map, or create one if it does not exist
794 mapc_find(char *map
, char *opt
, const char *maptype
, const char *mntpt
)
799 * Search the list of known maps to see if
800 * it has already been loaded. If it is found
801 * then return a duplicate reference to it.
802 * Otherwise make a new map as required and
803 * add it to the list of maps
805 ITER(m
, mnt_map
, &map_list_head
)
806 if (STREQ(m
->map_name
, map
))
808 m
= mapc_create(map
, opt
, maptype
, mntpt
);
809 ins_que(&m
->hdr
, &map_list_head
);
819 mapc_free(opaque_t arg
)
821 mnt_map
*m
= (mnt_map
*) arg
;
824 * Decrement the reference count.
825 * If the reference count hits zero
826 * then throw the map away.
828 if (m
&& --m
->refc
== 0) {
838 * Search the map for the key. Put a safe (malloc'ed) copy in *pval or
839 * return an error code
842 mapc_meta_search(mnt_map
*m
, char *key
, char **pval
, int recurse
)
851 plog(XLOG_ERROR
, "Null map request for %s", key
);
855 if (m
->flags
& MAPC_SYNC
) {
860 error
= (*m
->mtime
) (m
, m
->map_name
, &t
);
861 if (error
|| t
> m
->modify
) {
862 plog(XLOG_INFO
, "Map %s is out of date", m
->map_name
);
869 * Compute the hash table offset
871 k
= m
->kvhash
[kvhash_of(key
)];
874 * Scan the linked list for the key
876 while (k
&& !FSTREQ(k
->key
, key
))
882 else if (recurse
== MREC_FULL
) {
884 * Try for an RE match against the entire map.
885 * Note that this will be done in a "random"
890 for (i
= 0; i
< NKVHASH
; i
++) {
895 /* XXX: this code was recently ported, and must be tested -Erez */
896 retval
= regexec(&k
->re
, key
, 0, NULL
, 0);
897 if (retval
== 0) { /* succeeded */
899 } else { /* failed to match, log error */
903 regerror(retval
, &k
->re
, errstr
, 256);
904 plog(XLOG_USER
, "error matching RE \"%s\" against \"%s\": %s",
905 key
, k
->key
, errstr
);
913 #endif /* HAVE_REGEXEC */
916 * If found then take a copy
920 *pval
= strdup(k
->val
);
923 } else if (m
->alloc
>= MAPC_ALL
) {
925 * If the entire map is cached then this
926 * key does not exist.
931 * Otherwise search the map. If we are
932 * in incremental mode then add the key
935 error
= search_map(m
, key
, pval
);
936 if (!error
&& m
->alloc
== MAPC_INC
)
937 mapc_add_kv(m
, strdup(key
), strdup(*pval
));
941 * If an error, and a wildcard exists,
942 * and the key is not internal then
943 * return a copy of the wildcard.
946 if (recurse
== MREC_FULL
&& !MAPC_ISRE(m
)) {
947 char wildname
[MAXPATHLEN
];
952 * Keep chopping sub-directories from the RHS
953 * and replacing with "/ *" and repeat the lookup.
955 * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
957 xstrlcpy(wildname
, key
, sizeof(wildname
));
958 while (error
&& (subp
= strrchr(wildname
, '/'))) {
960 * sizeof space left in subp is sizeof wildname minus what's left
961 * after the strchr above returned a pointer inside wildname into
964 xstrlcpy(subp
, "/*", sizeof(wildname
) - (subp
- wildname
));
965 dlog("mapc recurses on %s", wildname
);
966 error
= mapc_meta_search(m
, wildname
, pval
, MREC_PART
);
971 if (error
> 0 && m
->wildcard
) {
972 *pval
= strdup(m
->wildcard
);
982 mapc_search(mnt_map
*m
, char *key
, char **pval
)
984 return mapc_meta_search(m
, key
, pval
, MREC_FULL
);
989 * Get map cache in sync with physical representation
992 mapc_sync(mnt_map
*m
)
994 int need_mtime_update
= 0;
996 if (m
->alloc
== MAPC_ROOT
)
997 return; /* nothing to do */
999 /* do not clear map if map service is down */
1001 if (!((*m
->isup
)(m
, m
->map_name
))) {
1002 plog(XLOG_ERROR
, "mapc_sync: map %s is down: not clearing map", m
->map_name
);
1007 if (m
->alloc
>= MAPC_ALL
) {
1008 /* mapc_reload_map() always works */
1009 need_mtime_update
= mapc_reload_map(m
);
1013 * Attempt to find the wildcard entry
1015 mapc_find_wildcard(m
);
1016 need_mtime_update
= 1; /* because mapc_clear always works */
1020 * To be safe, update the mtime of the mnt_map's own node, so that the
1021 * kernel will flush all of its cached entries.
1023 if (need_mtime_update
&& m
->cfm
) {
1024 am_node
*mp
= find_ap(m
->cfm
->cfm_dir
);
1026 clocktime(&mp
->am_fattr
.na_mtime
);
1028 plog(XLOG_ERROR
, "cannot find map %s to update its mtime",
1036 * Reload all the maps
1037 * Called when Amd gets hit by a SIGHUP.
1046 * Throw away the existing information.
1050 ITER(m
, mnt_map
, &map_list_head
)
1057 * The root map is used to bootstrap amd.
1058 * All the require top-level mounts are added
1059 * into the root map and then the map is iterated
1060 * and a lookup is done on all the mount points.
1061 * This causes the top level mounts to be automounted.
1064 root_init(mnt_map
*m
, char *map
, time_t *tp
)
1066 *tp
= clocktime(NULL
);
1067 return STREQ(map
, ROOT_MAP
) ? 0 : ENOENT
;
1072 * Add a new entry to the root map
1074 * dir - directory (key)
1075 * opts - mount options
1077 * cfm - optional amd configuration file map section structure
1080 root_newmap(const char *dir
, const char *opts
, const char *map
, const cf_map_t
*cfm
)
1082 char str
[MAXPATHLEN
];
1085 * First make sure we have a root map to talk about...
1088 root_map
= mapc_find(ROOT_MAP
, "mapdefault", NULL
, NULL
);
1091 * Then add the entry...
1095 * Here I plug in the code to process other amd.conf options like
1096 * map_type, search_path, and flags (browsable_dirs, mount_type).
1101 xsnprintf(str
, sizeof(str
),
1102 "cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"",
1103 cfm
->cfm_flags
& CFM_MOUNT_TYPE_AUTOFS
? "autofs" : "nfs",
1104 get_full_path(map
, cfm
->cfm_search_path
, cfm
->cfm_type
));
1105 if (opts
&& opts
[0] != '\0') {
1106 xstrlcat(str
, ";", sizeof(str
));
1107 xstrlcat(str
, opts
, sizeof(str
));
1109 if (cfm
->cfm_flags
& CFM_BROWSABLE_DIRS_FULL
)
1110 xstrlcat(str
, ";opts:=rw,fullybrowsable", sizeof(str
));
1111 if (cfm
->cfm_flags
& CFM_BROWSABLE_DIRS
)
1112 xstrlcat(str
, ";opts:=rw,browsable", sizeof(str
));
1113 if (cfm
->cfm_type
) {
1114 xstrlcat(str
, ";maptype:=", sizeof(str
));
1115 xstrlcat(str
, cfm
->cfm_type
, sizeof(str
));
1118 xstrlcpy(str
, opts
, sizeof(str
));
1122 xsnprintf(str
, sizeof(str
),
1123 "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1124 map
, opts
? opts
: "");
1126 xstrlcpy(str
, opts
, sizeof(str
));
1128 mapc_repl_kv(root_map
, strdup((char *)dir
), strdup(str
));
1133 mapc_keyiter(mnt_map
*m
, key_fun
*fn
, opaque_t arg
)
1138 for (i
= 0; i
< NKVHASH
; i
++) {
1139 kv
*k
= m
->kvhash
[i
];
1141 (*fn
) (k
->key
, arg
);
1152 * Iterate on the root map and call (*fn)() on the key of all the nodes.
1153 * Returns the number of entries in the root map.
1156 root_keyiter(key_fun
*fn
, opaque_t arg
)
1159 int c
= mapc_keyiter(root_map
, fn
, arg
);
1171 error_init(mnt_map
*m
, char *map
, time_t *tp
)
1173 plog(XLOG_USER
, "No source data for map %s", map
);
1181 error_search(mnt_map
*m
, char *map
, char *key
, char **pval
, time_t *tp
)
1188 error_reload(mnt_map
*m
, char *map
, add_fn
*fn
)
1195 error_mtime(mnt_map
*m
, char *map
, time_t *tp
)
1204 * Return absolute path of map, searched in a type-specific path.
1205 * Note: uses a static buffer for returned data.
1208 get_full_path(const char *map
, const char *path
, const char *type
)
1210 char component
[MAXPATHLEN
], *str
;
1211 static char full_path
[MAXPATHLEN
];
1214 /* for now, only file-type search paths are implemented */
1215 if (type
&& !STREQ(type
, "file"))
1218 /* if null map, return it */
1222 /* if map includes a '/', return it (absolute or relative path) */
1223 if (strchr(map
, '/'))
1226 /* if path is empty, return map */
1230 /* now break path into components, and search in each */
1231 xstrlcpy(component
, path
, sizeof(component
));
1233 str
= strtok(component
, ":");
1235 xstrlcpy(full_path
, str
, sizeof(full_path
));
1236 len
= strlen(full_path
);
1237 if (full_path
[len
- 1] != '/') /* add trailing "/" if needed */
1238 xstrlcat(full_path
, "/", sizeof(full_path
));
1239 xstrlcat(full_path
, map
, sizeof(full_path
));
1240 if (access(full_path
, R_OK
) == 0)
1242 str
= strtok(NULL
, ":");
1245 return map
; /* if found nothing, return map */