MFC r1.27:
[dragonfly.git] / contrib / amd / amd / mapc.c
blobe27928bf03d0c25e055b113e134dcceb828a7a0b
1 /*
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.
6 * All rights reserved.
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
13 * are met:
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
37 * SUCH DAMAGE.
39 * %W% (Berkeley) %G%
41 * $Id: mapc.c,v 1.5 1999/09/30 21:01:31 ezk Exp $
46 * Mount map cache
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <amd.h>
56 * Make a duplicate reference to an existing map
58 #define mapc_dup(m) ((m)->refc++, (m))
61 * Map cache types
62 * default, none, incremental, all, regexp
63 * MAPC_RE implies MAPC_ALL and must be numerically
64 * greater.
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
74 #ifdef HAVE_REGEXEC
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 */
82 * Lookup recursion
84 #define MREC_FULL 2
85 #define MREC_PART 1
86 #define MREC_NONE 0
88 #define MAX_CHAIN 2048
90 static struct opt_tab mapc_opt[] =
92 {"all", MAPC_ALL},
93 {"default", MAPC_DFLT},
94 {"inc", MAPC_INC},
95 {"mapdefault", MAPC_DFLT},
96 {"none", MAPC_NONE},
97 #ifdef HAVE_REGEXEC
98 {"re", MAPC_RE},
99 {"regexp", MAPC_RE},
100 #endif /* HAVE_REGEXEC */
101 {"sync", MAPC_SYNC},
102 {0, 0}
106 * Wildcard key
108 static char wildcard[] = "*";
111 * Map type
113 typedef struct map_type map_type;
114 struct 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 */
125 * Map for root node
127 static mnt_map *root_map;
130 * List of known maps
132 qelem map_list_head = {&map_list_head, &map_list_head};
135 * Configuration
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 *);
144 /* ROOT MAP */
145 static int root_init(mnt_map *, char *, time_t *);
147 /* ERROR MAP */
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 *);
153 /* PASSWD MAPS */
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 */
159 /* HESIOD MAPS */
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 */
166 /* LDAP MAPS */
167 #ifdef HAVE_MAP_LDAP
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 */
173 /* UNION MAPS */
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) */
189 #ifdef HAVE_MAP_NIS
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 */
197 /* NDBM MAPS */
198 #ifdef HAVE_MAP_NDBM
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 */
204 /* FILE MAPS */
205 #ifdef HAVE_MAP_FILE
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[] =
217 "root",
218 root_init,
219 error_reload,
220 NULL, /* isup function */
221 error_search,
222 error_mtime,
223 MAPC_ROOT
225 #ifdef HAVE_MAP_PASSWD
227 "passwd",
228 passwd_init,
229 error_reload,
230 NULL, /* isup function */
231 passwd_search,
232 error_mtime,
233 MAPC_ALL
235 #endif /* HAVE_MAP_PASSWD */
236 #ifdef HAVE_MAP_HESIOD
238 "hesiod",
239 amu_hesiod_init,
240 error_reload,
241 hesiod_isup, /* is Hesiod up or not? */
242 hesiod_search,
243 error_mtime,
244 MAPC_ALL
246 #endif /* HAVE_MAP_HESIOD */
247 #ifdef HAVE_MAP_LDAP
249 "ldap",
250 amu_ldap_init,
251 error_reload,
252 NULL, /* isup function */
253 amu_ldap_search,
254 amu_ldap_mtime,
255 MAPC_ALL
257 #endif /* HAVE_MAP_LDAP */
258 #ifdef HAVE_MAP_UNION
260 "union",
261 union_init,
262 union_reload,
263 NULL, /* isup function */
264 union_search,
265 error_mtime,
266 MAPC_ALL
268 #endif /* HAVE_MAP_UNION */
269 #ifdef HAVE_MAP_NISPLUS
271 "nisplus",
272 nisplus_init,
273 nisplus_reload,
274 NULL, /* isup function */
275 nisplus_search,
276 nisplus_mtime,
277 MAPC_INC
279 #endif /* HAVE_MAP_NISPLUS */
280 #ifdef HAVE_MAP_NIS
282 "nis",
283 nis_init,
284 nis_reload,
285 nis_isup, /* is NIS up or not? */
286 nis_search,
287 nis_mtime,
288 MAPC_ALL
290 #endif /* HAVE_MAP_NIS */
291 #ifdef HAVE_MAP_NDBM
293 "ndbm",
294 ndbm_init,
295 error_reload,
296 NULL, /* isup function */
297 ndbm_search,
298 ndbm_mtime,
299 MAPC_ALL
301 #endif /* HAVE_MAP_NDBM */
302 #ifdef HAVE_MAP_FILE
304 "file",
305 file_init,
306 file_reload,
307 NULL, /* isup function */
308 file_search,
309 file_mtime,
310 MAPC_ALL
312 #endif /* HAVE_MAP_FILE */
314 "error",
315 error_init,
316 error_reload,
317 NULL, /* isup function */
318 error_search,
319 error_mtime,
320 MAPC_NONE
326 * Hash function
328 static u_int
329 kvhash_of(char *key)
331 u_int i, j;
333 for (i = 0; (j = *key++); i += j) ;
335 return i % NKVHASH;
339 void
340 mapc_showtypes(char *buf)
342 map_type *mt;
343 char *sep = "";
345 buf[0] = '\0';
346 for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) {
347 strcat(buf, sep);
348 strcat(buf, mt->name);
349 sep = ", ";
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)
361 map_type *mt;
363 if (!type)
364 return 0;
365 for (mt = maptypes;
366 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
367 mt++) {
368 if (STREQ(type, mt->name))
369 return 1;
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
379 void
380 mapc_add_kv(mnt_map *m, char *key, char *val)
382 kv **h;
383 kv *n;
384 int hash = kvhash_of(key);
385 #ifdef HAVE_REGEXEC
386 regex_t re;
387 #endif /* HAVE_REGEXEC */
389 #ifdef DEBUG
390 dlog("add_kv: %s -> %s", key, val);
391 #endif /* DEBUG */
393 #ifdef HAVE_REGEXEC
394 if (MAPC_ISRE(m)) {
395 char pattern[MAXPATHLEN];
396 int retval;
399 * Make sure the string is bound to the start and end
401 sprintf(pattern, "^%s$", key);
402 retval = regcomp(&re, pattern, REG_ICASE);
403 if (retval != 0) {
404 char errstr[256];
406 /* XXX: this code was recently ported, and must be tested -Erez */
407 errstr[0] = '\0';
408 regerror(retval, &re, errstr, 256);
409 plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr);
410 return;
413 #endif /* HAVE_REGEXEC */
415 h = &m->kvhash[hash];
416 n = ALLOC(struct kv);
417 n->key = key;
418 #ifdef HAVE_REGEXEC
419 memcpy(&n->re, &re, sizeof(regex_t));
420 #endif /* HAVE_REGEXEC */
421 n->val = val;
422 n->next = *h;
423 *h = n;
427 static void
428 mapc_repl_kv(mnt_map *m, char *key, char *val)
430 kv *k;
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))
441 k = k->next;
443 if (k) {
444 XFREE(k->val);
445 k->val = val;
446 } else {
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.
457 static int
458 search_map(mnt_map *m, char *key, char **valp)
460 int rc;
462 do {
463 rc = (*m->search) (m, m->map_name, key, valp, &m->modify);
464 if (rc < 0) {
465 plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
466 mapc_sync(m);
468 } while (rc < 0);
470 return rc;
475 * Do a wildcard lookup in the map and
476 * save the result.
478 static void
479 mapc_find_wildcard(mnt_map *m)
482 * Attempt to find the wildcard entry
484 int rc = search_map(m, wildcard, &m->wildcard);
486 if (rc != 0)
487 m->wildcard = 0;
492 * Do a map reload.
493 * Attempt to reload without losing current data by switching the hashes
494 * round.
496 static void
497 mapc_reload_map(mnt_map *m)
499 int error;
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) {
507 time_t t;
508 error = (*m->mtime) (m, m->map_name, &t);
509 if (!error) {
510 if (t <= m->modify) {
511 plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name);
512 #ifdef DEBUG
513 dlog("map %s last load time is %d, last modify time is %d",
514 m->map_name, (int) m->modify, (int) t);
515 #endif /* DEBUG */
516 return;
517 } else {
518 /* reload of the map is needed, update map reload time */
519 m->modify = t;
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));
528 #ifdef DEBUG
529 dlog("calling map reload on %s", m->map_name);
530 #endif /* DEBUG */
531 error = (*m->reload) (m, m->map_name, mapc_add_kv);
532 if (error) {
533 if (m->reloads == 0)
534 plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name);
535 else
536 plog(XLOG_ERROR, "reload of map %s failed - using old values",
537 m->map_name);
538 mapc_clear(m);
539 memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash));
540 } else {
541 if (m->reloads++ == 0)
542 plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name);
543 else
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));
548 mapc_clear(m);
549 memcpy((voidp) m->kvhash, (voidp) tmphash, sizeof(m->kvhash));
551 m->wildcard = 0;
553 #ifdef DEBUG
554 dlog("calling mapc_search for wildcard");
555 #endif /* DEBUG */
556 error = mapc_search(m, wildcard, &m->wildcard);
557 if (error)
558 m->wildcard = 0;
563 * Create a new map
565 static mnt_map *
566 mapc_create(char *map, char *opt, const char *type)
568 mnt_map *m = ALLOC(struct mnt_map);
569 map_type *mt;
570 time_t modify;
571 int alloc = 0;
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 */
583 for (mt = maptypes;
584 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
585 mt++) {
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) {
589 break;
590 } else {
591 plog(XLOG_ERROR, "failed to initialize map %s", map);
592 error_init(m, map, &modify);
593 break;
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
603 for (mt = maptypes;
604 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
605 mt++) {
606 #ifdef DEBUG
607 dlog("trying to initialize map %s of type %s ...", map, mt->name);
608 #endif /* DEBUG */
609 if ((*mt->init) (m, map, &modify) == 0) {
610 break;
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;
623 switch (alloc) {
624 default:
625 plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
626 alloc = MAPC_INC;
627 /* fall-through... */
628 case MAPC_NONE:
629 case MAPC_INC:
630 case MAPC_ROOT:
631 break;
633 case MAPC_ALL:
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);
640 alloc = MAPC_INC;
642 break;
644 #ifdef HAVE_REGEXEC
645 case MAPC_RE:
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" */
651 break;
652 #endif /* HAVE_REGEXEC */
655 #ifdef DEBUG
656 dlog("Map for %s coming from maptype %s", map, mt->name);
657 #endif /* DEBUG */
659 m->alloc = alloc;
660 m->reload = mt->reload;
661 m->isup = mt->isup;
662 m->modify = modify;
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);
667 m->refc = 1;
668 m->wildcard = 0;
669 m->reloads = 0;
672 * synchronize cache with reality
674 mapc_sync(m);
676 return m;
681 * Free the cached data in a map
683 static void
684 mapc_clear(mnt_map *m)
686 int i;
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];
694 while (k) {
695 kv *n = k->next;
696 XFREE(k->key);
697 if (k->val)
698 XFREE(k->val);
699 XFREE(k);
700 k = n;
705 * Zero the hash slots
707 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
710 * Free the wildcard if it exists
712 if (m->wildcard) {
713 XFREE(m->wildcard);
714 m->wildcard = 0;
720 * Find a map, or create one if it does not exist
722 mnt_map *
723 mapc_find(char *map, char *opt, const char *maptype)
725 mnt_map *m;
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))
736 return mapc_dup(m);
737 m = mapc_create(map, opt, maptype);
738 ins_que(&m->hdr, &map_list_head);
740 return m;
745 * Free a map.
747 void
748 mapc_free(voidp v)
750 mnt_map *m = v;
753 * Decrement the reference count.
754 * If the reference count hits zero
755 * then throw the map away.
757 if (m && --m->refc == 0) {
758 mapc_clear(m);
759 XFREE(m->map_name);
760 rem_que(&m->hdr);
761 XFREE(m);
767 * Search the map for the key. Put a safe (malloc'ed) copy in *pval or
768 * return an error code
770 static int
771 mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
773 int error = 0;
774 kv *k = 0;
777 * Firewall
779 if (!m) {
780 plog(XLOG_ERROR, "Null map request for %s", key);
781 return ENOENT;
783 if (m->flags & MAPC_SYNC) {
785 * Get modify time...
787 time_t t;
788 error = (*m->mtime) (m, m->map_name, &t);
789 if (error || t > m->modify) {
790 m->modify = t;
791 plog(XLOG_INFO, "Map %s is out of date", m->map_name);
792 mapc_sync(m);
796 if (!MAPC_ISRE(m)) {
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))
806 k = k->next;
810 #ifdef HAVE_REGEXEC
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"
815 * order.
817 int i;
819 for (i = 0; i < NKVHASH; i++) {
820 k = m->kvhash[i];
821 while (k) {
822 int retval;
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 */
827 break;
828 } else { /* failed to match, log error */
829 char errstr[256];
831 errstr[0] = '\0';
832 regerror(retval, &k->re, errstr, 256);
833 plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s",
834 key, k->key, errstr);
836 k = k->next;
838 if (k)
839 break;
842 #endif /* HAVE_REGEXEC */
845 * If found then take a copy
847 if (k) {
848 if (k->val)
849 *pval = strdup(k->val);
850 else
851 error = ENOENT;
852 } else if (m->alloc >= MAPC_ALL) {
854 * If the entire map is cached then this
855 * key does not exist.
857 error = ENOENT;
858 } else {
860 * Otherwise search the map. If we are
861 * in incremental mode then add the key
862 * to the cache.
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.
874 if (error > 0) {
875 if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
876 char wildname[MAXPATHLEN];
877 char *subp;
878 if (*key == '/')
879 return error;
881 * Keep chopping sub-directories from the RHS
882 * and replacing with "/ *" and repeat the lookup.
883 * For example:
884 * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
886 strcpy(wildname, key);
887 while (error && (subp = strrchr(wildname, '/'))) {
888 strcpy(subp, "/*");
889 #ifdef DEBUG
890 dlog("mapc recurses on %s", wildname);
891 #endif /* DEBUG */
892 error = mapc_meta_search(m, wildname, pval, MREC_PART);
893 if (error)
894 *subp = 0;
897 if (error > 0 && m->wildcard) {
898 *pval = strdup(m->wildcard);
899 error = 0;
903 return error;
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
917 static void
918 mapc_sync(mnt_map *m)
920 if (m->alloc != MAPC_ROOT) {
922 /* do not clear map if map service is down */
923 if (m->isup) {
924 if (!((*m->isup)(m, m->map_name))) {
925 plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
926 return;
930 if (m->alloc >= MAPC_ALL) {
931 /* mapc_reload_map() always works */
932 mapc_reload_map(m);
933 } else {
934 mapc_clear(m);
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.
948 void
949 mapc_reload(void)
951 mnt_map *m;
954 * For all the maps,
955 * Throw away the existing information.
956 * Do a reload
957 * Find the wildcard
959 ITER(m, mnt_map, &map_list_head)
960 mapc_sync(m);
965 * Root map.
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.
972 static int
973 root_init(mnt_map *m, char *map, time_t *tp)
975 *tp = clocktime();
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
985 * map - map name
986 * cfm - optional amd configuration file map section structure
988 void
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...
996 if (!root_map)
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).
1008 if (cfm) {
1009 if (map) {
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') {
1014 strcat(str, ";");
1015 strcat(str, opts);
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);
1025 } else {
1026 strcpy(str, opts);
1028 } else {
1029 if (map)
1030 sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1031 map, opts ? opts : "");
1032 else
1033 strcpy(str, opts);
1035 mapc_repl_kv(root_map, strdup((char *)dir), strdup(str));
1040 mapc_keyiter(mnt_map *m, void (*fn) (char *, voidp), voidp arg)
1042 int i;
1043 int c = 0;
1045 for (i = 0; i < NKVHASH; i++) {
1046 kv *k = m->kvhash[i];
1047 while (k) {
1048 (*fn) (k->key, arg);
1049 k = k->next;
1050 c++;
1054 return c;
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)
1065 if (root_map) {
1066 int c = mapc_keyiter(root_map, fn, arg);
1067 return c;
1070 return 0;
1075 * Was: NEW_TOPLVL_READDIR
1076 * Search a chain for an entry with some name.
1077 * -Erez Zadok <ezk@cs.columbia.edu>
1079 static int
1080 key_already_in_chain(char *keyname, const nfsentry *chain)
1082 const nfsentry *tmpchain = chain;
1084 while (tmpchain) {
1085 if (keyname && tmpchain->ne_name && STREQ(keyname, tmpchain->ne_name))
1086 return 1;
1087 tmpchain = tmpchain->ne_nextentry;
1090 return 0;
1095 * Create a chain of entries which are not linked.
1096 * -Erez Zadok <ezk@cs.columbia.edu>
1098 nfsentry *
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;
1104 char *key;
1105 int num_entries = 0, preflen = 0, i;
1106 nfsentry *retval = (nfsentry *) NULL;
1107 mntfs *mf;
1108 mnt_map *mmp;
1110 if (!mp) {
1111 plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)");
1112 return retval;
1114 mf = mp->am_mnt;
1115 if (!mf) {
1116 plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt is (NULL)");
1117 return retval;
1119 mmp = (mnt_map *) mf->mf_private;
1120 if (!mmp) {
1121 plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt->mf_private is (NULL)");
1122 return retval;
1125 /* iterate over keys */
1126 for (i = 0; i < NKVHASH; i++) {
1127 kv *k;
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?
1135 key = k->key;
1136 if (!key)
1137 continue;
1139 /* Skip '*' */
1140 if (!fully_browsable && strchr(key, '*'))
1141 continue;
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.
1147 if (preflen) {
1148 if (!NSTREQ(key, mp->am_pref, preflen))
1149 continue;
1150 key += preflen;
1153 /* no more '/' are allowed, unless browsable_dirs=full was used */
1154 if (!fully_browsable && strchr(key, '/'))
1155 continue;
1157 /* no duplicates allowed */
1158 if (key_already_in_chain(key, current_chain))
1159 continue;
1161 /* fill in a cell and link the entry */
1162 if (num_entries >= max_entries) {
1163 /* out of space */
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;
1167 retval = &chain[0];
1169 return retval;
1172 /* we have space. put entry in next cell */
1173 ++last_cookie;
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];
1180 ++num_entries;
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;
1187 retval = &chain[0];
1190 return retval;
1195 * Error map
1197 static int
1198 error_init(mnt_map *m, char *map, time_t *tp)
1200 plog(XLOG_USER, "No source data for map %s", map);
1201 *tp = 0;
1203 return 0;
1207 static int
1208 error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
1210 return ENOENT;
1214 static int
1215 error_reload(mnt_map *m, char *map, add_fn *fn)
1217 return ENOENT;
1221 static int
1222 error_mtime(mnt_map *m, char *map, time_t *tp)
1224 *tp = 0;
1226 return 0;
1231 * Return absolute path of map, searched in a type-specific path.
1232 * Note: uses a static buffer for returned data.
1234 static const char *
1235 get_full_path(const char *map, const char *path, const char *type)
1237 char component[MAXPATHLEN], *str;
1238 static char full_path[MAXPATHLEN];
1239 int len;
1241 /* for now, only file-type search paths are implemented */
1242 if (type && !STREQ(type, "file"))
1243 return map;
1245 /* if null map, return it */
1246 if (!map)
1247 return map;
1249 /* if map includes a '/', return it (absolute or relative path) */
1250 if (strchr(map, '/'))
1251 return map;
1253 /* if path is empty, return map */
1254 if (!path)
1255 return map;
1257 /* now break path into components, and search in each */
1258 strcpy(component, path);
1260 str = strtok(component, ":");
1261 do {
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)
1268 return full_path;
1269 str = strtok(NULL, ":");
1270 } while (str);
1272 return map; /* if found nothing, return map */