2 * Copyright (c) 1997-1999 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. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * $Id: mapc.c,v 1.5 1999/09/30 21:01:31 ezk Exp $
51 #endif /* HAVE_CONFIG_H */
56 * Make a duplicate reference to an existing map
58 #define mapc_dup(m) ((m)->refc++, (m))
62 * default, none, incremental, all, regexp
63 * MAPC_RE implies MAPC_ALL and must be numerically
66 #define MAPC_DFLT 0x000
67 #define MAPC_NONE 0x001
68 #define MAPC_INC 0x002
69 #define MAPC_ROOT 0x004
70 #define MAPC_ALL 0x010
71 #define MAPC_CACHE_MASK 0x0ff
72 #define MAPC_SYNC 0x100
75 # define MAPC_RE 0x020
76 # define MAPC_ISRE(m) ((m)->alloc == MAPC_RE)
77 #else /* not HAVE_REGEXEC */
78 # define MAPC_ISRE(m) FALSE
79 #endif /* not HAVE_REGEXEC */
88 #define MAX_CHAIN 2048
90 static struct opt_tab mapc_opt
[] =
93 {"default", MAPC_DFLT
},
95 {"mapdefault", MAPC_DFLT
},
100 #endif /* HAVE_REGEXEC */
108 static char wildcard
[] = "*";
113 typedef struct map_type map_type
;
115 char *name
; /* Name of this map type */
116 init_fn
*init
; /* Initialization */
117 reload_fn
*reload
; /* Reload or fill */
118 isup_fn
*isup
; /* Is service up or not? (1=up, 0=down) */
119 search_fn
*search
; /* Search for new entry */
120 mtime_fn
*mtime
; /* Find modify time */
121 int def_alloc
; /* Default allocation mode */
127 static mnt_map
*root_map
;
132 qelem map_list_head
= {&map_list_head
, &map_list_head
};
138 /* forward definitions */
139 static const char *get_full_path(const char *map
, const char *path
, const char *type
);
140 static int mapc_meta_search(mnt_map
*, char *, char **, int);
141 static void mapc_sync(mnt_map
*);
142 static void mapc_clear(mnt_map
*);
145 static int root_init(mnt_map
*, char *, time_t *);
148 static int error_init(mnt_map
*, char *, time_t *);
149 static int error_reload(mnt_map
*, char *, add_fn
*);
150 static int error_search(mnt_map
*, char *, char *, char **, time_t *);
151 static int error_mtime(mnt_map
*, char *, time_t *);
154 #ifdef HAVE_MAP_PASSWD
155 extern int passwd_init(mnt_map
*, char *, time_t *);
156 extern int passwd_search(mnt_map
*, char *, char *, char **, time_t *);
157 #endif /* HAVE_MAP_PASSWD */
160 #ifdef HAVE_MAP_HESIOD
161 extern int amu_hesiod_init(mnt_map
*, char *map
, time_t *tp
);
162 extern int hesiod_isup(mnt_map
*, char *);
163 extern int hesiod_search(mnt_map
*, char *, char *, char **, time_t *);
164 #endif /* HAVE_MAP_HESIOD */
168 extern int amu_ldap_init(mnt_map
*, char *map
, time_t *tp
);
169 extern int amu_ldap_search(mnt_map
*, char *, char *, char **, time_t *);
170 extern int amu_ldap_mtime(mnt_map
*, char *, time_t *);
171 #endif /* HAVE_MAP_LDAP */
174 #ifdef HAVE_MAP_UNION
175 extern int union_init(mnt_map
*, char *, time_t *);
176 extern int union_search(mnt_map
*, char *, char *, char **, time_t *);
177 extern int union_reload(mnt_map
*, char *, add_fn
*);
178 #endif /* HAVE_MAP_UNION */
180 /* Network Information Service PLUS (NIS+) */
181 #ifdef HAVE_MAP_NISPLUS
182 extern int nisplus_init(mnt_map
*, char *, time_t *);
183 extern int nisplus_reload(mnt_map
*, char *, add_fn
*);
184 extern int nisplus_search(mnt_map
*, char *, char *, char **, time_t *);
185 extern int nisplus_mtime(mnt_map
*, char *, time_t *);
186 #endif /* HAVE_MAP_NISPLUS */
188 /* Network Information Service (YP, Yellow Pages) */
190 extern int nis_init(mnt_map
*, char *, time_t *);
191 extern int nis_reload(mnt_map
*, char *, add_fn
*);
192 extern int nis_isup(mnt_map
*, char *);
193 extern int nis_search(mnt_map
*, char *, char *, char **, time_t *);
194 extern int nis_mtime(mnt_map
*, char *, time_t *);
195 #endif /* HAVE_MAP_NIS */
199 extern int ndbm_init(mnt_map
*, char *, time_t *);
200 extern int ndbm_search(mnt_map
*, char *, char *, char **, time_t *);
201 extern int ndbm_mtime(mnt_map
*, char *, time_t *);
202 #endif /* HAVE_MAP_NDBM */
206 extern int file_init(mnt_map
*, char *, time_t *);
207 extern int file_reload(mnt_map
*, char *, add_fn
*);
208 extern int file_search(mnt_map
*, char *, char *, char **, time_t *);
209 extern int file_mtime(mnt_map
*, char *, time_t *);
210 #endif /* HAVE_MAP_FILE */
213 /* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */
214 static map_type maptypes
[] =
220 NULL
, /* isup function */
225 #ifdef HAVE_MAP_PASSWD
230 NULL
, /* isup function */
235 #endif /* HAVE_MAP_PASSWD */
236 #ifdef HAVE_MAP_HESIOD
241 hesiod_isup
, /* is Hesiod up or not? */
246 #endif /* HAVE_MAP_HESIOD */
252 NULL
, /* isup function */
257 #endif /* HAVE_MAP_LDAP */
258 #ifdef HAVE_MAP_UNION
263 NULL
, /* isup function */
268 #endif /* HAVE_MAP_UNION */
269 #ifdef HAVE_MAP_NISPLUS
274 NULL
, /* isup function */
279 #endif /* HAVE_MAP_NISPLUS */
285 nis_isup
, /* is NIS up or not? */
290 #endif /* HAVE_MAP_NIS */
296 NULL
, /* isup function */
301 #endif /* HAVE_MAP_NDBM */
307 NULL
, /* isup function */
312 #endif /* HAVE_MAP_FILE */
317 NULL
, /* isup function */
333 for (i
= 0; (j
= *key
++); i
+= j
) ;
340 mapc_showtypes(char *buf
)
346 for (mt
= maptypes
; mt
< maptypes
+ sizeof(maptypes
) / sizeof(maptypes
[0]); mt
++) {
348 strcat(buf
, mt
->name
);
355 * Check if a map of a certain type exists.
356 * Return 1 (true) if exists, 0 (false) if not.
359 mapc_type_exists(const char *type
)
366 mt
< maptypes
+ sizeof(maptypes
) / sizeof(maptypes
[0]);
368 if (STREQ(type
, mt
->name
))
371 return 0; /* not found anywhere */
376 * Add key and val to the map m.
377 * key and val are assumed to be safe copies
380 mapc_add_kv(mnt_map
*m
, char *key
, char *val
)
384 int hash
= kvhash_of(key
);
387 #endif /* HAVE_REGEXEC */
390 dlog("add_kv: %s -> %s", key
, val
);
395 char pattern
[MAXPATHLEN
];
399 * Make sure the string is bound to the start and end
401 sprintf(pattern
, "^%s$", key
);
402 retval
= regcomp(&re
, pattern
, REG_ICASE
);
406 /* XXX: this code was recently ported, and must be tested -Erez */
408 regerror(retval
, &re
, errstr
, 256);
409 plog(XLOG_USER
, "error compiling RE \"%s\": %s", pattern
, errstr
);
413 #endif /* HAVE_REGEXEC */
415 h
= &m
->kvhash
[hash
];
416 n
= ALLOC(struct kv
);
419 memcpy(&n
->re
, &re
, sizeof(regex_t
));
420 #endif /* HAVE_REGEXEC */
428 mapc_repl_kv(mnt_map
*m
, char *key
, char *val
)
433 * Compute the hash table offset
435 k
= m
->kvhash
[kvhash_of(key
)];
438 * Scan the linked list for the key
440 while (k
&& !FSTREQ(k
->key
, key
))
447 mapc_add_kv(m
, key
, val
);
453 * Search a map for a key.
454 * Calls map specific search routine.
455 * While map is out of date, keep re-syncing.
458 search_map(mnt_map
*m
, char *key
, char **valp
)
463 rc
= (*m
->search
) (m
, m
->map_name
, key
, valp
, &m
->modify
);
465 plog(XLOG_MAP
, "Re-synchronizing cache for map %s", m
->map_name
);
475 * Do a wildcard lookup in the map and
479 mapc_find_wildcard(mnt_map
*m
)
482 * Attempt to find the wildcard entry
484 int rc
= search_map(m
, wildcard
, &m
->wildcard
);
493 * Attempt to reload without losing current data by switching the hashes
497 mapc_reload_map(mnt_map
*m
)
500 kv
*maphash
[NKVHASH
], *tmphash
[NKVHASH
];
503 * skip reloading maps that have not been modified, unless
504 * amq -f was used (do_mapc_reload is 0)
506 if (m
->reloads
!= 0 && do_mapc_reload
!= 0) {
508 error
= (*m
->mtime
) (m
, m
->map_name
, &t
);
510 if (t
<= m
->modify
) {
511 plog(XLOG_INFO
, "reload of map %s is not needed (in sync)", m
->map_name
);
513 dlog("map %s last load time is %d, last modify time is %d",
514 m
->map_name
, (int) m
->modify
, (int) t
);
518 /* reload of the map is needed, update map reload time */
524 /* copy the old hash and zero the map */
525 memcpy((voidp
) maphash
, (voidp
) m
->kvhash
, sizeof(m
->kvhash
));
526 memset((voidp
) m
->kvhash
, 0, sizeof(m
->kvhash
));
529 dlog("calling map reload on %s", m
->map_name
);
531 error
= (*m
->reload
) (m
, m
->map_name
, mapc_add_kv
);
534 plog(XLOG_FATAL
, "first time load of map %s failed!", m
->map_name
);
536 plog(XLOG_ERROR
, "reload of map %s failed - using old values",
539 memcpy((voidp
) m
->kvhash
, (voidp
) maphash
, sizeof(m
->kvhash
));
541 if (m
->reloads
++ == 0)
542 plog(XLOG_INFO
, "first time load of map %s succeeded", m
->map_name
);
544 plog(XLOG_INFO
, "reload #%d of map %s succeeded",
545 m
->reloads
, m
->map_name
);
546 memcpy((voidp
) tmphash
, (voidp
) m
->kvhash
, sizeof(m
->kvhash
));
547 memcpy((voidp
) m
->kvhash
, (voidp
) maphash
, sizeof(m
->kvhash
));
549 memcpy((voidp
) m
->kvhash
, (voidp
) tmphash
, sizeof(m
->kvhash
));
554 dlog("calling mapc_search for wildcard");
556 error
= mapc_search(m
, wildcard
, &m
->wildcard
);
566 mapc_create(char *map
, char *opt
, const char *type
)
568 mnt_map
*m
= ALLOC(struct mnt_map
);
573 cmdoption(opt
, mapc_opt
, &alloc
);
576 * If using a configuration file, and the map_type is defined, then look
577 * for it, in the maptypes array. If found, initialize the map using that
578 * map_type. If not found, return error. If no map_type was defined,
579 * default to cycling through all maptypes.
581 if (use_conf_file
&& type
) {
582 /* find what type of map this one is */
584 mt
< maptypes
+ sizeof(maptypes
) / sizeof(maptypes
[0]);
586 if (STREQ(type
, mt
->name
)) {
587 plog(XLOG_INFO
, "initializing amd conf map %s of type %s", map
, type
);
588 if ((*mt
->init
) (m
, map
, &modify
) == 0) {
591 plog(XLOG_ERROR
, "failed to initialize map %s", map
);
592 error_init(m
, map
, &modify
);
596 } /* end of "for (mt =" loop */
598 } else { /* cycle through all known maptypes */
601 * not using amd conf file or using it by w/o specifying map type
604 mt
< maptypes
+ sizeof(maptypes
) / sizeof(maptypes
[0]);
607 dlog("trying to initialize map %s of type %s ...", map
, mt
->name
);
609 if ((*mt
->init
) (m
, map
, &modify
) == 0) {
613 } /* end of "if (use_conf_file && (colpos = strchr ..." statement */
615 /* assert: mt in maptypes */
617 m
->flags
= alloc
& ~MAPC_CACHE_MASK
;
618 alloc
&= MAPC_CACHE_MASK
;
620 if (alloc
== MAPC_DFLT
)
621 alloc
= mt
->def_alloc
;
625 plog(XLOG_USER
, "Ambiguous map cache type \"%s\"; using \"inc\"", opt
);
627 /* fall-through... */
635 * If there is no support for reload and it was requested
636 * then back off to incremental instead.
638 if (mt
->reload
== error_reload
) {
639 plog(XLOG_WARNING
, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt
->name
);
646 if (mt
->reload
== error_reload
) {
647 plog(XLOG_WARNING
, "Map type \"%s\" does not support cache type \"re\"", mt
->name
);
648 mt
= &maptypes
[sizeof(maptypes
) / sizeof(maptypes
[0]) - 1];
649 /* assert: mt->name == "error" */
652 #endif /* HAVE_REGEXEC */
656 dlog("Map for %s coming from maptype %s", map
, mt
->name
);
660 m
->reload
= mt
->reload
;
663 m
->search
= alloc
>= MAPC_ALL
? error_search
: mt
->search
;
664 m
->mtime
= mt
->mtime
;
665 memset((voidp
) m
->kvhash
, 0, sizeof(m
->kvhash
));
666 m
->map_name
= strdup(map
);
672 * synchronize cache with reality
681 * Free the cached data in a map
684 mapc_clear(mnt_map
*m
)
689 * For each of the hash slots, chain
690 * along free'ing the data.
692 for (i
= 0; i
< NKVHASH
; i
++) {
693 kv
*k
= m
->kvhash
[i
];
705 * Zero the hash slots
707 memset((voidp
) m
->kvhash
, 0, sizeof(m
->kvhash
));
710 * Free the wildcard if it exists
720 * Find a map, or create one if it does not exist
723 mapc_find(char *map
, char *opt
, const char *maptype
)
728 * Search the list of known maps to see if
729 * it has already been loaded. If it is found
730 * then return a duplicate reference to it.
731 * Otherwise make a new map as required and
732 * add it to the list of maps
734 ITER(m
, mnt_map
, &map_list_head
)
735 if (STREQ(m
->map_name
, map
))
737 m
= mapc_create(map
, opt
, maptype
);
738 ins_que(&m
->hdr
, &map_list_head
);
753 * Decrement the reference count.
754 * If the reference count hits zero
755 * then throw the map away.
757 if (m
&& --m
->refc
== 0) {
767 * Search the map for the key. Put a safe (malloc'ed) copy in *pval or
768 * return an error code
771 mapc_meta_search(mnt_map
*m
, char *key
, char **pval
, int recurse
)
780 plog(XLOG_ERROR
, "Null map request for %s", key
);
783 if (m
->flags
& MAPC_SYNC
) {
788 error
= (*m
->mtime
) (m
, m
->map_name
, &t
);
789 if (error
|| t
> m
->modify
) {
791 plog(XLOG_INFO
, "Map %s is out of date", m
->map_name
);
798 * Compute the hash table offset
800 k
= m
->kvhash
[kvhash_of(key
)];
803 * Scan the linked list for the key
805 while (k
&& !FSTREQ(k
->key
, key
))
811 else if (recurse
== MREC_FULL
) {
813 * Try for an RE match against the entire map.
814 * Note that this will be done in a "random"
819 for (i
= 0; i
< NKVHASH
; i
++) {
824 /* XXX: this code was recently ported, and must be tested -Erez */
825 retval
= regexec(&k
->re
, key
, 0, 0, 0);
826 if (retval
== 0) { /* succeeded */
828 } else { /* failed to match, log error */
832 regerror(retval
, &k
->re
, errstr
, 256);
833 plog(XLOG_USER
, "error matching RE \"%s\" against \"%s\": %s",
834 key
, k
->key
, errstr
);
842 #endif /* HAVE_REGEXEC */
845 * If found then take a copy
849 *pval
= strdup(k
->val
);
852 } else if (m
->alloc
>= MAPC_ALL
) {
854 * If the entire map is cached then this
855 * key does not exist.
860 * Otherwise search the map. If we are
861 * in incremental mode then add the key
864 error
= search_map(m
, key
, pval
);
865 if (!error
&& m
->alloc
== MAPC_INC
)
866 mapc_add_kv(m
, strdup(key
), strdup(*pval
));
870 * If an error, and a wildcard exists,
871 * and the key is not internal then
872 * return a copy of the wildcard.
875 if (recurse
== MREC_FULL
&& !MAPC_ISRE(m
)) {
876 char wildname
[MAXPATHLEN
];
881 * Keep chopping sub-directories from the RHS
882 * and replacing with "/ *" and repeat the lookup.
884 * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
886 strcpy(wildname
, key
);
887 while (error
&& (subp
= strrchr(wildname
, '/'))) {
890 dlog("mapc recurses on %s", wildname
);
892 error
= mapc_meta_search(m
, wildname
, pval
, MREC_PART
);
897 if (error
> 0 && m
->wildcard
) {
898 *pval
= strdup(m
->wildcard
);
908 mapc_search(mnt_map
*m
, char *key
, char **pval
)
910 return mapc_meta_search(m
, key
, pval
, MREC_FULL
);
915 * Get map cache in sync with physical representation
918 mapc_sync(mnt_map
*m
)
920 if (m
->alloc
!= MAPC_ROOT
) {
922 /* do not clear map if map service is down */
924 if (!((*m
->isup
)(m
, m
->map_name
))) {
925 plog(XLOG_ERROR
, "mapc_sync: map %s is down: not clearing map", m
->map_name
);
930 if (m
->alloc
>= MAPC_ALL
) {
931 /* mapc_reload_map() always works */
936 * Attempt to find the wildcard entry
938 mapc_find_wildcard(m
);
945 * Reload all the maps
946 * Called when Amd gets hit by a SIGHUP.
955 * Throw away the existing information.
959 ITER(m
, mnt_map
, &map_list_head
)
966 * The root map is used to bootstrap amd.
967 * All the require top-level mounts are added
968 * into the root map and then the map is iterated
969 * and a lookup is done on all the mount points.
970 * This causes the top level mounts to be automounted.
973 root_init(mnt_map
*m
, char *map
, time_t *tp
)
976 return STREQ(map
, ROOT_MAP
) ? 0 : ENOENT
;
981 * Add a new entry to the root map
983 * dir - directory (key)
984 * opts - mount options
986 * cfm - optional amd configuration file map section structure
989 root_newmap(const char *dir
, const char *opts
, const char *map
, const cf_map_t
*cfm
)
991 char str
[MAXPATHLEN
];
994 * First make sure we have a root map to talk about...
997 root_map
= mapc_find(ROOT_MAP
, "mapdefault", NULL
);
1000 * Then add the entry...
1004 * Here I plug in the code to process other amd.conf options like
1005 * map_type, search_path, and flags (browsable_dirs, mount_type).
1010 sprintf(str
, "cache:=mapdefault;type:=%s;fs:=\"%s\"",
1011 cfm
->cfm_flags
& CFM_MOUNT_TYPE_AUTOFS
? "autofs" : "toplvl",
1012 get_full_path(map
, cfm
->cfm_search_path
, cfm
->cfm_type
));
1013 if (opts
&& opts
[0] != '\0') {
1017 if (cfm
->cfm_flags
& CFM_BROWSABLE_DIRS_FULL
)
1018 strcat(str
, ";opts:=rw,fullybrowsable");
1019 if (cfm
->cfm_flags
& CFM_BROWSABLE_DIRS
)
1020 strcat(str
, ";opts:=rw,browsable");
1021 if (cfm
->cfm_type
) {
1022 strcat(str
, ";maptype:=");
1023 strcat(str
, cfm
->cfm_type
);
1030 sprintf(str
, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1031 map
, opts
? opts
: "");
1035 mapc_repl_kv(root_map
, strdup((char *)dir
), strdup(str
));
1040 mapc_keyiter(mnt_map
*m
, void (*fn
) (char *, voidp
), voidp arg
)
1045 for (i
= 0; i
< NKVHASH
; i
++) {
1046 kv
*k
= m
->kvhash
[i
];
1048 (*fn
) (k
->key
, arg
);
1059 * Iterate on the root map and call (*fn)() on the key of all the nodes.
1060 * Finally throw away the root map.
1063 root_keyiter(void (*fn
)(char *, voidp
), voidp arg
)
1066 int c
= mapc_keyiter(root_map
, fn
, arg
);
1075 * Was: NEW_TOPLVL_READDIR
1076 * Search a chain for an entry with some name.
1077 * -Erez Zadok <ezk@cs.columbia.edu>
1080 key_already_in_chain(char *keyname
, const nfsentry
*chain
)
1082 const nfsentry
*tmpchain
= chain
;
1085 if (keyname
&& tmpchain
->ne_name
&& STREQ(keyname
, tmpchain
->ne_name
))
1087 tmpchain
= tmpchain
->ne_nextentry
;
1095 * Create a chain of entries which are not linked.
1096 * -Erez Zadok <ezk@cs.columbia.edu>
1099 make_entry_chain(am_node
*mp
, const nfsentry
*current_chain
, int fully_browsable
)
1101 static u_int last_cookie
= (u_int
) 2; /* monotonically increasing */
1102 static nfsentry chain
[MAX_CHAIN
];
1103 static int max_entries
= MAX_CHAIN
;
1105 int num_entries
= 0, preflen
= 0, i
;
1106 nfsentry
*retval
= (nfsentry
*) NULL
;
1111 plog(XLOG_DEBUG
, "make_entry_chain: mp is (NULL)");
1116 plog(XLOG_DEBUG
, "make_entry_chain: mp->am_mnt is (NULL)");
1119 mmp
= (mnt_map
*) mf
->mf_private
;
1121 plog(XLOG_DEBUG
, "make_entry_chain: mp->am_mnt->mf_private is (NULL)");
1125 /* iterate over keys */
1126 for (i
= 0; i
< NKVHASH
; i
++) {
1128 for (k
= mmp
->kvhash
[i
]; k
; k
= k
->next
) {
1131 * Skip unwanted entries which are either not real entries or
1132 * very difficult to interpret (wildcards...) This test needs
1133 * lots of improvement. Any takers?
1140 if (!fully_browsable
&& strchr(key
, '*'))
1144 * If the map has a prefix-string then check if the key starts with
1145 * this * string, and if it does, skip over this prefix.
1148 if (!NSTREQ(key
, mp
->am_pref
, preflen
))
1153 /* no more '/' are allowed, unless browsable_dirs=full was used */
1154 if (!fully_browsable
&& strchr(key
, '/'))
1157 /* no duplicates allowed */
1158 if (key_already_in_chain(key
, current_chain
))
1161 /* fill in a cell and link the entry */
1162 if (num_entries
>= max_entries
) {
1164 plog(XLOG_DEBUG
, "make_entry_chain: no more space in chain");
1165 if (num_entries
> 0) {
1166 chain
[num_entries
- 1].ne_nextentry
= 0;
1172 /* we have space. put entry in next cell */
1174 chain
[num_entries
].ne_fileid
= (u_int
) last_cookie
;
1175 *(u_int
*) chain
[num_entries
].ne_cookie
= (u_int
) last_cookie
;
1176 chain
[num_entries
].ne_name
= key
;
1177 if (num_entries
< max_entries
- 1) { /* link to next one */
1178 chain
[num_entries
].ne_nextentry
= &chain
[num_entries
+ 1];
1181 } /* end of "while (k)" */
1182 } /* end of "for (i ... NKVHASH ..." */
1184 /* terminate chain */
1185 if (num_entries
> 0) {
1186 chain
[num_entries
- 1].ne_nextentry
= 0;
1198 error_init(mnt_map
*m
, char *map
, time_t *tp
)
1200 plog(XLOG_USER
, "No source data for map %s", map
);
1208 error_search(mnt_map
*m
, char *map
, char *key
, char **pval
, time_t *tp
)
1215 error_reload(mnt_map
*m
, char *map
, add_fn
*fn
)
1222 error_mtime(mnt_map
*m
, char *map
, time_t *tp
)
1231 * Return absolute path of map, searched in a type-specific path.
1232 * Note: uses a static buffer for returned data.
1235 get_full_path(const char *map
, const char *path
, const char *type
)
1237 char component
[MAXPATHLEN
], *str
;
1238 static char full_path
[MAXPATHLEN
];
1241 /* for now, only file-type search paths are implemented */
1242 if (type
&& !STREQ(type
, "file"))
1245 /* if null map, return it */
1249 /* if map includes a '/', return it (absolute or relative path) */
1250 if (strchr(map
, '/'))
1253 /* if path is empty, return map */
1257 /* now break path into components, and search in each */
1258 strcpy(component
, path
);
1260 str
= strtok(component
, ":");
1262 strcpy(full_path
, str
);
1263 len
= strlen(full_path
);
1264 if (full_path
[len
- 1] != '/') /* add trailing "/" if needed */
1265 strcat(full_path
, "/");
1266 strcat(full_path
, map
);
1267 if (access(full_path
, R_OK
) == 0)
1269 str
= strtok(NULL
, ":");
1272 return map
; /* if found nothing, return map */