No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / am-utils / dist / amd / mapc.c
blob6236a81540034b651e4c8526bdec29e8d2a6515d
1 /* $NetBSD$ */
3 /*
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.
8 * All rights reserved.
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
15 * are met:
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
39 * SUCH DAMAGE.
42 * File: am-utils/amd/mapc.c
47 * Mount map cache
50 #ifdef HAVE_CONFIG_H
51 # include <config.h>
52 #endif /* HAVE_CONFIG_H */
53 #include <am_defs.h>
54 #include <amd.h>
57 * Make a duplicate reference to an existing map
59 #define mapc_dup(m) ((m)->refc++, (m))
62 * Map cache types
63 * default, none, incremental, all, regexp
64 * MAPC_RE implies MAPC_ALL and must be numerically
65 * greater.
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
75 #ifdef HAVE_REGEXEC
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 */
83 * Lookup recursion
85 #define MREC_FULL 2
86 #define MREC_PART 1
87 #define MREC_NONE 0
89 static struct opt_tab mapc_opt[] =
91 {"all", MAPC_ALL},
92 {"default", MAPC_DFLT},
93 {"inc", MAPC_INC},
94 {"mapdefault", MAPC_DFLT},
95 {"none", MAPC_NONE},
96 #ifdef HAVE_REGEXEC
97 {"re", MAPC_RE},
98 {"regexp", MAPC_RE},
99 #endif /* HAVE_REGEXEC */
100 {"sync", MAPC_SYNC},
101 {NULL, 0}
105 * Wildcard key
107 static char wildcard[] = "*";
110 * Map type
112 typedef struct map_type map_type;
113 struct 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 */
124 * Map for root node
126 static mnt_map *root_map;
129 * List of known maps
131 qelem map_list_head = {&map_list_head, &map_list_head};
134 * Configuration
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 *);
143 /* ROOT MAP */
144 static int root_init(mnt_map *, char *, time_t *);
146 /* ERROR MAP */
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 *);
152 /* PASSWD MAPS */
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 */
158 /* HESIOD MAPS */
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 */
165 /* LDAP MAPS */
166 #ifdef HAVE_MAP_LDAP
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 */
172 /* UNION MAPS */
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) */
188 #ifdef HAVE_MAP_NIS
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 */
196 /* NDBM MAPS */
197 #ifdef HAVE_MAP_NDBM
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 */
203 /* FILE MAPS */
204 #ifdef HAVE_MAP_FILE
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 */
211 #ifdef HAVE_MAP_EXEC
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 */
217 #ifdef HAVE_MAP_SUN
218 /* XXX: fill in */
219 #endif /* HAVE_MAP_SUN */
221 /* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */
222 static map_type maptypes[] =
225 "root",
226 root_init,
227 error_reload,
228 NULL, /* isup function */
229 error_search,
230 error_mtime,
231 MAPC_ROOT
233 #ifdef HAVE_MAP_PASSWD
235 "passwd",
236 passwd_init,
237 error_reload,
238 NULL, /* isup function */
239 passwd_search,
240 error_mtime,
241 MAPC_INC
243 #endif /* HAVE_MAP_PASSWD */
244 #ifdef HAVE_MAP_HESIOD
246 "hesiod",
247 amu_hesiod_init,
248 error_reload,
249 hesiod_isup, /* is Hesiod up or not? */
250 hesiod_search,
251 error_mtime,
252 MAPC_INC
254 #endif /* HAVE_MAP_HESIOD */
255 #ifdef HAVE_MAP_LDAP
257 "ldap",
258 amu_ldap_init,
259 error_reload,
260 NULL, /* isup function */
261 amu_ldap_search,
262 amu_ldap_mtime,
263 MAPC_INC
265 #endif /* HAVE_MAP_LDAP */
266 #ifdef HAVE_MAP_UNION
268 "union",
269 union_init,
270 union_reload,
271 NULL, /* isup function */
272 union_search,
273 error_mtime,
274 MAPC_ALL
276 #endif /* HAVE_MAP_UNION */
277 #ifdef HAVE_MAP_NISPLUS
279 "nisplus",
280 nisplus_init,
281 nisplus_reload,
282 NULL, /* isup function */
283 nisplus_search,
284 nisplus_mtime,
285 MAPC_INC
287 #endif /* HAVE_MAP_NISPLUS */
288 #ifdef HAVE_MAP_NIS
290 "nis",
291 nis_init,
292 nis_reload,
293 nis_isup, /* is NIS up or not? */
294 nis_search,
295 nis_mtime,
296 MAPC_ALL
298 #endif /* HAVE_MAP_NIS */
299 #ifdef HAVE_MAP_NDBM
301 "ndbm",
302 ndbm_init,
303 error_reload,
304 NULL, /* isup function */
305 ndbm_search,
306 ndbm_mtime,
307 MAPC_INC
309 #endif /* HAVE_MAP_NDBM */
310 #ifdef HAVE_MAP_FILE
312 "file",
313 file_init_or_mtime,
314 file_reload,
315 NULL, /* isup function */
316 file_search,
317 file_init_or_mtime,
318 MAPC_ALL
320 #endif /* HAVE_MAP_FILE */
321 #ifdef HAVE_MAP_EXEC
323 "exec",
324 exec_init,
325 error_reload,
326 NULL, /* isup function */
327 exec_search,
328 error_mtime,
329 MAPC_INC
331 #endif /* HAVE_MAP_EXEC */
332 #ifdef HAVE_MAP_SUN
334 /* XXX: fill in */
335 "sun",
336 NULL,
337 NULL,
338 NULL, /* isup function */
339 NULL,
340 NULL,
343 #endif /* HAVE_MAP_SUN */
345 "error",
346 error_init,
347 error_reload,
348 NULL, /* isup function */
349 error_search,
350 error_mtime,
351 MAPC_NONE
357 * Hash function
359 static u_int
360 kvhash_of(char *key)
362 u_int i, j;
364 for (i = 0; (j = *key++); i += j) ;
366 return i % NKVHASH;
370 void
371 mapc_showtypes(char *buf, size_t l)
373 map_type *mt=NULL, *lastmt;
374 int linesize = 0, i;
376 i = sizeof(maptypes) / sizeof(maptypes[0]);
377 lastmt = maptypes + i;
378 buf[0] = '\0';
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);
384 if (--i > 0) {
385 xstrlcat(buf, ", ", l);
386 linesize += 2;
388 if (linesize > 54) {
389 linesize = 0;
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)
403 map_type *mt;
405 if (!type)
406 return 0;
407 for (mt = maptypes;
408 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
409 mt++) {
410 if (STREQ(type, mt->name))
411 return 1;
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
421 void
422 mapc_add_kv(mnt_map *m, char *key, char *val)
424 kv **h;
425 kv *n;
426 int hash = kvhash_of(key);
427 #ifdef HAVE_REGEXEC
428 regex_t re;
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'.
442 char *entry, *tok;
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) {
457 key = tok;
458 /* find the entry */
459 for (entry = key; *entry && !isspace((unsigned char)*entry); entry++);
460 if (*entry) {
461 *entry++ = '\0';
464 mapc_add_kv(m, strdup(key), strdup(entry));
467 XFREE(val);
468 return;
471 #ifdef HAVE_REGEXEC
472 if (MAPC_ISRE(m)) {
473 char pattern[MAXPATHLEN];
474 int retval;
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);
481 if (retval != 0) {
482 char errstr[256];
484 /* XXX: this code was recently ported, and must be tested -Erez */
485 errstr[0] = '\0';
486 regerror(retval, &re, errstr, 256);
487 plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr);
488 return;
491 #endif /* HAVE_REGEXEC */
493 h = &m->kvhash[hash];
494 n = ALLOC(struct kv);
495 n->key = key;
496 #ifdef HAVE_REGEXEC
497 memcpy(&n->re, &re, sizeof(regex_t));
498 #endif /* HAVE_REGEXEC */
499 n->val = val;
500 n->next = *h;
501 *h = n;
505 static void
506 mapc_repl_kv(mnt_map *m, char *key, char *val)
508 kv *k;
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))
519 k = k->next;
521 if (k) {
522 XFREE(k->val);
523 k->val = val;
524 } else {
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.
535 static int
536 search_map(mnt_map *m, char *key, char **valp)
538 int rc;
540 do {
541 rc = (*m->search) (m, m->map_name, key, valp, &m->modify);
542 if (rc < 0) {
543 plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
544 mapc_sync(m);
546 } while (rc < 0);
548 return rc;
553 * Do a wildcard lookup in the map and
554 * save the result.
556 static void
557 mapc_find_wildcard(mnt_map *m)
560 * Attempt to find the wildcard entry
562 int rc = search_map(m, wildcard, &m->wildcard);
564 if (rc != 0)
565 m->wildcard = NULL;
570 * Do a map reload.
571 * Attempt to reload without losing current data by switching the hashes
572 * round.
573 * If reloading was needed and succeeded, return 1; else return 0.
575 static int
576 mapc_reload_map(mnt_map *m)
578 int error, ret = 0;
579 kv *maphash[NKVHASH], *tmphash[NKVHASH];
580 time_t t;
582 error = (*m->mtime) (m, m->map_name, &t);
583 if (error) {
584 t = m->modify;
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);
596 return ret;
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);
606 if (error) {
607 if (m->reloads == 0)
608 plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name);
609 else
610 plog(XLOG_ERROR, "reload of map %s failed - using old values",
611 m->map_name);
612 mapc_clear(m);
613 memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash));
614 } else {
615 if (m->reloads++ == 0)
616 plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name);
617 else
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));
622 mapc_clear(m);
623 memcpy((voidp) m->kvhash, (voidp) tmphash, sizeof(m->kvhash));
624 m->modify = t;
625 ret = 1;
627 m->wildcard = NULL;
629 dlog("calling mapc_search for wildcard");
630 error = mapc_search(m, wildcard, &m->wildcard);
631 if (error)
632 m->wildcard = NULL;
633 return ret;
638 * Create a new map
640 static mnt_map *
641 mapc_create(char *map, char *opt, const char *type, const char *mntpt)
643 mnt_map *m = ALLOC(struct mnt_map);
644 map_type *mt;
645 time_t modify = 0;
646 u_int alloc = 0;
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 */
658 for (mt = maptypes;
659 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
660 mt++) {
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) {
664 break;
665 } else {
666 plog(XLOG_ERROR, "failed to initialize map %s", map);
667 error_init(m, map, &modify);
668 break;
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
678 for (mt = maptypes;
679 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
680 mt++) {
681 dlog("trying to initialize map %s of type %s ...", map, mt->name);
682 if ((*mt->init) (m, map, &modify) == 0) {
683 break;
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;
696 switch (alloc) {
697 default:
698 plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
699 alloc = MAPC_INC;
700 /* fall-through... */
701 case MAPC_NONE:
702 case MAPC_INC:
703 case MAPC_ROOT:
704 break;
706 case MAPC_ALL:
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);
713 alloc = MAPC_INC;
715 break;
717 #ifdef HAVE_REGEXEC
718 case MAPC_RE:
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" */
724 break;
725 #endif /* HAVE_REGEXEC */
728 dlog("Map for %s coming from maptype %s", map, mt->name);
730 m->alloc = alloc;
731 m->reload = mt->reload;
732 m->isup = mt->isup;
733 m->modify = modify;
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);
738 m->refc = 1;
739 m->wildcard = NULL;
740 m->reloads = 0;
741 /* initialize per-map information (flags, etc.) */
742 m->cfm = find_cf_map(mntpt);
745 * synchronize cache with reality
747 mapc_sync(m);
749 return m;
754 * Free the cached data in a map
756 static void
757 mapc_clear(mnt_map *m)
759 int i;
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];
767 while (k) {
768 kv *n = k->next;
769 XFREE(k->key);
770 if (k->val)
771 XFREE(k->val);
772 XFREE(k);
773 k = n;
778 * Zero the hash slots
780 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
783 * Free the wildcard if it exists
785 if (m->wildcard)
786 XFREE(m->wildcard);
791 * Find a map, or create one if it does not exist
793 mnt_map *
794 mapc_find(char *map, char *opt, const char *maptype, const char *mntpt)
796 mnt_map *m;
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))
807 return mapc_dup(m);
808 m = mapc_create(map, opt, maptype, mntpt);
809 ins_que(&m->hdr, &map_list_head);
811 return m;
816 * Free a map.
818 void
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) {
829 mapc_clear(m);
830 XFREE(m->map_name);
831 rem_que(&m->hdr);
832 XFREE(m);
838 * Search the map for the key. Put a safe (malloc'ed) copy in *pval or
839 * return an error code
841 static int
842 mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
844 int error = 0;
845 kv *k = NULL;
848 * Firewall
850 if (!m) {
851 plog(XLOG_ERROR, "Null map request for %s", key);
852 return ENOENT;
855 if (m->flags & MAPC_SYNC) {
857 * Get modify time...
859 time_t t;
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);
863 mapc_sync(m);
867 if (!MAPC_ISRE(m)) {
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))
877 k = k->next;
881 #ifdef HAVE_REGEXEC
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"
886 * order.
888 int i;
890 for (i = 0; i < NKVHASH; i++) {
891 k = m->kvhash[i];
892 while (k) {
893 int retval;
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 */
898 break;
899 } else { /* failed to match, log error */
900 char errstr[256];
902 errstr[0] = '\0';
903 regerror(retval, &k->re, errstr, 256);
904 plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s",
905 key, k->key, errstr);
907 k = k->next;
909 if (k)
910 break;
913 #endif /* HAVE_REGEXEC */
916 * If found then take a copy
918 if (k) {
919 if (k->val)
920 *pval = strdup(k->val);
921 else
922 error = ENOENT;
923 } else if (m->alloc >= MAPC_ALL) {
925 * If the entire map is cached then this
926 * key does not exist.
928 error = ENOENT;
929 } else {
931 * Otherwise search the map. If we are
932 * in incremental mode then add the key
933 * to the cache.
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.
945 if (error > 0) {
946 if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
947 char wildname[MAXPATHLEN];
948 char *subp;
949 if (*key == '/')
950 return error;
952 * Keep chopping sub-directories from the RHS
953 * and replacing with "/ *" and repeat the lookup.
954 * For example:
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
962 * subp.
964 xstrlcpy(subp, "/*", sizeof(wildname) - (subp - wildname));
965 dlog("mapc recurses on %s", wildname);
966 error = mapc_meta_search(m, wildname, pval, MREC_PART);
967 if (error)
968 *subp = '\0';
971 if (error > 0 && m->wildcard) {
972 *pval = strdup(m->wildcard);
973 error = 0;
977 return error;
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
991 static void
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 */
1000 if (m->isup) {
1001 if (!((*m->isup)(m, m->map_name))) {
1002 plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
1003 return;
1007 if (m->alloc >= MAPC_ALL) {
1008 /* mapc_reload_map() always works */
1009 need_mtime_update = mapc_reload_map(m);
1010 } else {
1011 mapc_clear(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);
1025 if (mp) {
1026 clocktime(&mp->am_fattr.na_mtime);
1027 } else {
1028 plog(XLOG_ERROR, "cannot find map %s to update its mtime",
1029 m->cfm->cfm_dir);
1036 * Reload all the maps
1037 * Called when Amd gets hit by a SIGHUP.
1039 void
1040 mapc_reload(void)
1042 mnt_map *m;
1045 * For all the maps,
1046 * Throw away the existing information.
1047 * Do a reload
1048 * Find the wildcard
1050 ITER(m, mnt_map, &map_list_head)
1051 mapc_sync(m);
1056 * Root map.
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.
1063 static int
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
1076 * map - map name
1077 * cfm - optional amd configuration file map section structure
1079 void
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...
1087 if (!root_map)
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).
1099 if (cfm) {
1100 if (map) {
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));
1117 } else {
1118 xstrlcpy(str, opts, sizeof(str));
1120 } else {
1121 if (map)
1122 xsnprintf(str, sizeof(str),
1123 "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1124 map, opts ? opts : "");
1125 else
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)
1135 int i;
1136 int c = 0;
1138 for (i = 0; i < NKVHASH; i++) {
1139 kv *k = m->kvhash[i];
1140 while (k) {
1141 (*fn) (k->key, arg);
1142 k = k->next;
1143 c++;
1147 return c;
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)
1158 if (root_map) {
1159 int c = mapc_keyiter(root_map, fn, arg);
1160 return c;
1163 return 0;
1168 * Error map
1170 static int
1171 error_init(mnt_map *m, char *map, time_t *tp)
1173 plog(XLOG_USER, "No source data for map %s", map);
1174 *tp = 0;
1176 return 0;
1180 static int
1181 error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
1183 return ENOENT;
1187 static int
1188 error_reload(mnt_map *m, char *map, add_fn *fn)
1190 return ENOENT;
1194 static int
1195 error_mtime(mnt_map *m, char *map, time_t *tp)
1197 *tp = 0;
1199 return 0;
1204 * Return absolute path of map, searched in a type-specific path.
1205 * Note: uses a static buffer for returned data.
1207 static const char *
1208 get_full_path(const char *map, const char *path, const char *type)
1210 char component[MAXPATHLEN], *str;
1211 static char full_path[MAXPATHLEN];
1212 int len;
1214 /* for now, only file-type search paths are implemented */
1215 if (type && !STREQ(type, "file"))
1216 return map;
1218 /* if null map, return it */
1219 if (!map)
1220 return map;
1222 /* if map includes a '/', return it (absolute or relative path) */
1223 if (strchr(map, '/'))
1224 return map;
1226 /* if path is empty, return map */
1227 if (!path)
1228 return map;
1230 /* now break path into components, and search in each */
1231 xstrlcpy(component, path, sizeof(component));
1233 str = strtok(component, ":");
1234 do {
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)
1241 return full_path;
1242 str = strtok(NULL, ":");
1243 } while (str);
1245 return map; /* if found nothing, return map */