 |
|
|
| |
1 /*
2 * Copyright (c) 1997-2005 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.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
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.
26 *
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.
38 *
39 *
40 * File: am-utils/amd/mapc.c
41 *
42 */
43
44 /*
45 * Mount map cache
46 */
47
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif /* HAVE_CONFIG_H */
51 #include <am_defs.h>
52 #include <amd.h>
53
54 /*
55 * Make a duplicate reference to an existing map
56 */
57 #define mapc_dup(m) ((m)->refc++, (m))
58
59 /*
60 * Map cache types
61 * default, none, incremental, all, regexp
62 * MAPC_RE implies MAPC_ALL and must be numerically
63 * greater.
64 */
65 #define MAPC_DFLT 0x000
66 #define MAPC_NONE 0x001
67 #define MAPC_INC 0x002
68 #define MAPC_ROOT 0x004
69 #define MAPC_ALL 0x010
70 #define MAPC_CACHE_MASK 0x0ff
71 #define MAPC_SYNC 0x100
72
73 #ifdef HAVE_REGEXEC
74 # define MAPC_RE 0x020
75 # define MAPC_ISRE(m) ((m)->alloc == MAPC_RE)
76 #else /* not HAVE_REGEXEC */
77 # define MAPC_ISRE(m) FALSE
78 #endif /* not HAVE_REGEXEC */
79
80 /*
81 * Lookup recursion
82 */
83 #define MREC_FULL 2
84 #define MREC_PART 1
85 #define MREC_NONE 0
86
87 static struct opt_tab mapc_opt[] =
88 {
89 {"all", MAPC_ALL},
90 {"default", MAPC_DFLT},
91 {"inc", MAPC_INC},
92 {"mapdefault", MAPC_DFLT},
93 {"none", MAPC_NONE},
94 #ifdef HAVE_REGEXEC
95 {"re", MAPC_RE},
96 {"regexp", MAPC_RE},
97 #endif /* HAVE_REGEXEC */
98 {"sync", MAPC_SYNC},
99 {0, 0}
100 };
101
102 /*
103 * Wildcard key
104 */
105 static char wildcard[] = "*";
106
107 /*
108 * Map type
109 */
110 typedef struct map_type map_type;
111 struct map_type {
112 char *name; /* Name of this map type */
113 init_fn *init; /* Initialization */
114 reload_fn *reload; /* Reload or fill */
115 isup_fn *isup; /* Is service up or not? (1=up, 0=down) */
116 search_fn *search; /* Search for new entry */
117 mtime_fn *mtime; /* Find modify time */
118 int def_alloc; /* Default allocation mode */
119 };
120
121 /*
122 * Map for root node
123 */
124 static mnt_map *root_map;
125
126 /*
127 * List of known maps
128 */
129 qelem map_list_head = {&map_list_head, &map_list_head};
130
131 /*
132 * Configuration
133 */
134
135 /* forward definitions */
136 static const char *get_full_path(const char *map, const char *path, const char *type);
137 static int mapc_meta_search(mnt_map *, char *, char **, int);
138 static void mapc_sync(mnt_map *);
139 static void mapc_clear(mnt_map *);
140
141 /* ROOT MAP */
142 static int root_init(mnt_map *, char *, time_t *);
143
144 /* ERROR MAP */
145 static int error_init(mnt_map *, char *, time_t *);
146 static int error_reload(mnt_map *, char *, add_fn *);
147 static int error_search(mnt_map *, char *, char *, char **, time_t *);
148 static int error_mtime(mnt_map *, char *, time_t *);
149
150 /* PASSWD MAPS */
151 #ifdef HAVE_MAP_PASSWD
152 extern int passwd_init(mnt_map *, char *, time_t *);
153 extern int passwd_search(mnt_map *, char *, char *, char **, time_t *);
154 #endif /* HAVE_MAP_PASSWD */
155
156 /* HESIOD MAPS */
157 #ifdef HAVE_MAP_HESIOD
158 extern int amu_hesiod_init(mnt_map *, char *map, time_t *tp);
159 extern int hesiod_isup(mnt_map *, char *);
160 extern int hesiod_search(mnt_map *, char *, char *, char **, time_t *);
161 #endif /* HAVE_MAP_HESIOD */
162
163 /* LDAP MAPS */
164 #ifdef HAVE_MAP_LDAP
165 extern int amu_ldap_init(mnt_map *, char *map, time_t *tp);
166 extern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *);
167 extern int amu_ldap_mtime(mnt_map *, char *, time_t *);
168 #endif /* HAVE_MAP_LDAP */
169
170 /* UNION MAPS */
171 #ifdef HAVE_MAP_UNION
172 extern int union_init(mnt_map *, char *, time_t *);
173 extern int union_search(mnt_map *, char *, char *, char **, time_t *);
174 extern int union_reload(mnt_map *, char *, add_fn *);
175 #endif /* HAVE_MAP_UNION */
176
177 /* Network Information Service PLUS (NIS+) */
178 #ifdef HAVE_MAP_NISPLUS
179 extern int nisplus_init(mnt_map *, char *, time_t *);
180 extern int nisplus_reload(mnt_map *, char *, add_fn *);
181 extern int nisplus_search(mnt_map *, char *, char *, char **, time_t *);
182 extern int nisplus_mtime(mnt_map *, char *, time_t *);
183 #endif /* HAVE_MAP_NISPLUS */
184
185 /* Network Information Service (YP, Yellow Pages) */
186 #ifdef HAVE_MAP_NIS
187 extern int nis_init(mnt_map *, char *, time_t *);
188 extern int nis_reload(mnt_map *, char *, add_fn *);
189 extern int nis_isup(mnt_map *, char *);
190 extern int nis_search(mnt_map *, char *, char *, char **, time_t *);
191 extern int nis_mtime(mnt_map *, char *, time_t *);
192 #endif /* HAVE_MAP_NIS */
193
194 /* NDBM MAPS */
195 #ifdef HAVE_MAP_NDBM
196 extern int ndbm_init(mnt_map *, char *, time_t *);
197 extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *);
198 extern int ndbm_mtime(mnt_map *, char *, time_t *);
199 #endif /* HAVE_MAP_NDBM */
200
201 /* EXECUTABLE MAPS */
202 #ifdef HAVE_MAP_EXEC
203 extern int exec_init(mnt_map *, char *, time_t *);
204 extern int exec_search(mnt_map *, char *, char *, char **, time_t *);
205 #endif /* HAVE_MAP_EXEC */
206
207 /* FILE MAPS */
208 #ifdef HAVE_MAP_FILE
209 extern int file_init_or_mtime(mnt_map *, char *, time_t *);
210 extern int file_reload(mnt_map *, char *, add_fn *);
211 extern int file_search(mnt_map *, char *, char *, char **, time_t *);
212 #endif /* HAVE_MAP_FILE */
213
214
215 /* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */
216 static map_type maptypes[] =
217 {
218 {
219 "root",
220 root_init,
221 error_reload,
222 NULL, /* isup function */
223 error_search,
224 error_mtime,
225 MAPC_ROOT
226 },
227 #ifdef HAVE_MAP_PASSWD
228 {
229 "passwd",
230 passwd_init,
231 error_reload,
232 NULL, /* isup function */
233 passwd_search,
234 error_mtime,
235 MAPC_INC
236 },
237 #endif /* HAVE_MAP_PASSWD */
238 #ifdef HAVE_MAP_HESIOD
239 {
240 "hesiod",
241 amu_hesiod_init,
242 error_reload,
243 hesiod_isup, /* is Hesiod up or not? */
244 hesiod_search,
245 error_mtime,
246 MAPC_INC
247 },
248 #endif /* HAVE_MAP_HESIOD */
249 #ifdef HAVE_MAP_LDAP
250 {
251 "ldap",
252 amu_ldap_init,
253 error_reload,
254 NULL, /* isup function */
255 amu_ldap_search,
256 amu_ldap_mtime,
257 MAPC_INC
258 },
259 #endif /* HAVE_MAP_LDAP */
260 #ifdef HAVE_MAP_UNION
261 {
262 "union",
263 union_init,
264 union_reload,
265 NULL, /* isup function */
266 union_search,
267 error_mtime,
268 MAPC_ALL
269 },
270 #endif /* HAVE_MAP_UNION */
271 #ifdef HAVE_MAP_NISPLUS
272 {
273 "nisplus",
274 nisplus_init,
275 nisplus_reload,
276 NULL, /* isup function */
277 nisplus_search,
278 nisplus_mtime,
279 MAPC_INC
280 },
281 #endif /* HAVE_MAP_NISPLUS */
282 #ifdef HAVE_MAP_NIS
283 {
284 "nis",
285 nis_init,
286 nis_reload,
287 nis_isup, /* is NIS up or not? */
288 nis_search,
289 nis_mtime,
290 MAPC_ALL
291 },
292 #endif /* HAVE_MAP_NIS */
293 #ifdef HAVE_MAP_NDBM
294 {
295 "ndbm",
296 ndbm_init,
297 error_reload,
298 NULL, /* isup function */
299 ndbm_search,
300 ndbm_mtime,
301 MAPC_INC
302 },
303 #endif /* HAVE_MAP_NDBM */
304 #ifdef HAVE_MAP_FILE
305 {
306 "file",
307 file_init_or_mtime,
308 file_reload,
309 NULL, /* isup function */
310 file_search,
311 file_init_or_mtime,
312 MAPC_ALL
313 },
314 #endif /* HAVE_MAP_FILE */
315 #ifdef HAVE_MAP_EXEC
316 {
317 "exec",
318 exec_init,
319 error_reload,
320 NULL, /* isup function */
321 exec_search,
322 error_mtime,
323 MAPC_INC
324 },
325 #endif /* HAVE_MAP_EXEC */
326 {
327 "error",
328 error_init,
329 error_reload,
330 NULL, /* isup function */
331 error_search,
332 error_mtime,
333 MAPC_NONE
334 },
335 };
336
337
338 /*
339 * Hash function
340 */
341 static u_int
342 kvhash_of(char *key)
343 {
344 u_int i, j;
345
346 for (i = 0; (j = *key++); i += j) ;
347
348 return i % NKVHASH;
349 }
350
351
352 void
353 mapc_showtypes(char *buf)
354 {
355 map_type *mt=NULL, *lastmt;
356 int l = 0, i;
357
358 i = sizeof(maptypes) / sizeof(maptypes[0]);
359 lastmt = maptypes + i;
360 buf[0] = '\0';
361 for (mt = maptypes; mt < lastmt; mt++) {
362 strcat(buf, mt->name);
363 if (mt == (lastmt-1))
364 break; /* if last one, don't do strcat's that follow */
365 l += strlen(mt->name);
366 if (--i > 0) {
367 strcat(buf, ", ");
368 l += 2;
369 }
370 if (l > 54) {
371 l = 0;
372 strcat(buf, "\n\t\t ");
373 }
374 }
375 }
376
377
378 /*
379 * Check if a map of a certain type exists.
380 * Return 1 (true) if exists, 0 (false) if not.
381 */
382 int
383 mapc_type_exists(const char *type)
384 {
385 map_type *mt;
386
387 if (!type)
388 return 0;
389 for (mt = maptypes;
390 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
391 mt++) {
392 if (STREQ(type, mt->name))
393 return 1;
394 }
395 return 0; /* not found anywhere */
396 }
397
398
399 /*
400 * Add key and val to the map m.
401 * key and val are assumed to be safe copies
402 */
403 void
404 mapc_add_kv(mnt_map *m, char *key, char *val)
405 {
406 kv **h;
407 kv *n;
408 int hash = kvhash_of(key);
409 #ifdef HAVE_REGEXEC
410 regex_t re;
411 #endif /* HAVE_REGEXEC */
412
413 dlog("add_kv: %s -> %s", key, val);
414
415 #ifdef HAVE_REGEXEC
416 if (MAPC_ISRE(m)) {
417 char pattern[MAXPATHLEN];
418 int retval;
419
420 /*
421 * Make sure the string is bound to the start and end
422 */
423 sprintf(pattern, "^%s$", key);
424 retval = regcomp(&re, pattern, REG_ICASE);
425 if (retval != 0) {
426 char errstr[256];
427
428 /* XXX: this code was recently ported, and must be tested -Erez */
429 errstr[0] = '\0';
430 regerror(retval, &re, errstr, 256);
431 plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr);
432 return;
433 }
434 }
435 #endif /* HAVE_REGEXEC */
436
437 h = &m->kvhash[hash];
438 n = ALLOC(struct kv);
439 n->key = key;
440 #ifdef HAVE_REGEXEC
441 memcpy(&n->re, &re, sizeof(regex_t));
442 #endif /* HAVE_REGEXEC */
443 n->val = val;
444 n->next = *h;
445 *h = n;
446 }
447
448
449 static void
450 mapc_repl_kv(mnt_map *m, char *key, char *val)
451 {
452 kv *k;
453
454 /*
455 * Compute the hash table offset
456 */
457 k = m->kvhash[kvhash_of(key)];
458
459 /*
460 * Scan the linked list for the key
461 */
462 while (k && !FSTREQ(k->key, key))
463 k = k->next;
464
465 if (k) {
466 XFREE(k->val);
467 k->val = val;
468 } else {
469 mapc_add_kv(m, key, val);
470 }
471 }
472
473
474 /*
475 * Search a map for a key.
476 * Calls map specific search routine.
477 * While map is out of date, keep re-syncing.
478 */
479 static int
480 search_map(mnt_map *m, char *key, char **valp)
481 {
482 int rc;
483
484 do {
485 rc = (*m->search) (m, m->map_name, key, valp, &m->modify);
486 if (rc < 0) {
487 plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
488 mapc_sync(m);
489 }
490 } while (rc < 0);
491
492 return rc;
493 }
494
495
496 /*
497 * Do a wildcard lookup in the map and
498 * save the result.
499 */
500 static void
501 mapc_find_wildcard(mnt_map *m)
502 {
503 /*
504 * Attempt to find the wildcard entry
505 */
506 int rc = search_map(m, wildcard, &m->wildcard);
507
508 if (rc != 0)
509 m->wildcard = 0;
510 }
511
512
513 /*
514 * Do a map reload.
515 * Attempt to reload without losing current data by switching the hashes
516 * round.
517 */
518 static void
519 mapc_reload_map(mnt_map *m)
520 {
521 int error;
522 kv *maphash[NKVHASH], *tmphash[NKVHASH];
523 time_t t;
524
525 error = (*m->mtime) (m, m->map_name, &t);
526 if (error) {
527 t = m->modify;
528 }
529
530 /*
531 * skip reloading maps that have not been modified, unless
532 * amq -f was used (do_mapc_reload is 0)
533 */
534 if (m->reloads != 0 && do_mapc_reload != 0) {
535 if (t <= m->modify) {
536 plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name);
537 dlog("map %s last load time is %d, last modify time is %d",
538 m->map_name, (int) m->modify, (int) t);
539 return;
540 }
541 }
542
543 /* copy the old hash and zero the map */
544 memcpy((voidp) maphash, (voidp) m->kvhash, sizeof(m->kvhash));
545 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
546
547 dlog("calling map reload on %s", m->map_name);
548 error = (*m->reload) (m, m->map_name, mapc_add_kv);
549 if (error) {
550 if (m->reloads == 0)
551 plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name);
552 else
553 plog(XLOG_ERROR, "reload of map %s failed - using old values",
554 m->map_name);
555 mapc_clear(m);
556 memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash));
557 } else {
558 if (m->reloads++ == 0)
559 plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name);
560 else
561 plog(XLOG_INFO, "reload #%d of map %s succeeded",
562 m->reloads, m->map_name);
563 memcpy((voidp) tmphash, (voidp) m->kvhash, sizeof(m->kvhash));
564 memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash));
565 mapc_clear(m);
566 memcpy((voidp) m->kvhash, (voidp) tmphash, sizeof(m->kvhash));
567 m->modify = t;
568 }
569 m->wildcard = 0;
570
571 dlog("calling mapc_search for wildcard");
572 error = mapc_search(m, wildcard, &m->wildcard);
573 if (error)
574 m->wildcard = 0;
575 }
576
577
578 /*
579 * Create a new map
580 */
581 static mnt_map *
582 mapc_create(char *map, char *opt, const char *type)
583 {
584 mnt_map *m = ALLOC(struct mnt_map);
585 map_type *mt;
586 time_t modify;
587 int alloc = 0;
588
589 cmdoption(opt, mapc_opt, &alloc);
590
591 /*
592 * If using a configuration file, and the map_type is defined, then look
593 * for it, in the maptypes array. If found, initialize the map using that
594 * map_type. If not found, return error. If no map_type was defined,
595 * default to cycling through all maptypes.
596 */
597 if (use_conf_file && type) {
598 /* find what type of map this one is */
599 for (mt = maptypes;
600 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
601 mt++) {
602 if (STREQ(type, mt->name)) {
603 plog(XLOG_INFO, "initializing amd.conf map %s of type %s", map, type);
604 if ((*mt->init) (m, map, &modify) == 0) {
605 break;
606 } else {
607 plog(XLOG_ERROR, "failed to initialize map %s", map);
608 error_init(m, map, &modify);
609 break;
610 }
611 }
612 } /* end of "for (mt =" loop */
613
614 } else { /* cycle through all known maptypes */
615
616 /*
617 * not using amd conf file or using it by w/o specifying map type
618 */
619 for (mt = maptypes;
620 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
621 mt++) {
622 dlog("trying to initialize map %s of type %s ...", map, mt->name);
623 if ((*mt->init) (m, map, &modify) == 0) {
624 break;
625 }
626 }
627 } /* end of "if (use_conf_file && (colpos = strchr ..." statement */
628
629 /* assert: mt in maptypes */
630
631 m->flags = alloc & ~MAPC_CACHE_MASK;
632 alloc &= MAPC_CACHE_MASK;
633
634 if (alloc == MAPC_DFLT)
635 alloc = mt->def_alloc;
636
637 switch (alloc) {
638 default:
639 plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
640 alloc = MAPC_INC;
641 /* fall-through... */
642 case MAPC_NONE:
643 case MAPC_INC:
644 case MAPC_ROOT:
645 break;
646
647 case MAPC_ALL:
648 /*
649 * If there is no support for reload and it was requested
650 * then back off to incremental instead.
651 */
652 if (mt->reload == error_reload) {
653 plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name);
654 alloc = MAPC_INC;
655 }
656 break;
657
658 #ifdef HAVE_REGEXEC
659 case MAPC_RE:
660 if (mt->reload == error_reload) {
661 plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name);
662 mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1];
663 /* assert: mt->name == "error" */
664 }
665 break;
666 #endif /* HAVE_REGEXEC */
667 }
668
669 dlog("Map for %s coming from maptype %s", map, mt->name);
670
671 m->alloc = alloc;
672 m->reload = mt->reload;
673 m->isup = mt->isup;
674 m->modify = modify;
675 m->search = alloc >= MAPC_ALL ? error_search : mt->search;
676 m->mtime = mt->mtime;
677 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
678 m->map_name = strdup(map);
679 m->refc = 1;
680 m->wildcard = 0;
681 m->reloads = 0;
682 /* Unfortunately with current code structure, this cannot be initialized here */
683 m->cfm = NULL;
684
685 /*
686 * synchronize cache with reality
687 */
688 mapc_sync(m);
689
690 return m;
691 }
692
693
694 /*
695 * Free the cached data in a map
696 */
697 static void
698 mapc_clear(mnt_map *m)
699 {
700 int i;
701
702 /*
703 * For each of the hash slots, chain
704 * along free'ing the data.
705 */
706 for (i = 0; i < NKVHASH; i++) {
707 kv *k = m->kvhash[i];
708 while (k) {
709 kv *n = k->next;
710 XFREE(k->key);
711 if (k->val)
712 XFREE(k->val);
713 XFREE(k);
714 k = n;
715 }
716 }
717
718 /*
719 * Zero the hash slots
720 */
721 memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
722
723 /*
724 * Free the wildcard if it exists
725 */
726 if (m->wildcard) {
727 XFREE(m->wildcard);
728 m->wildcard = 0;
729 }
730 }
731
732
733 /*
734 * Find a map, or create one if it does not exist
735 */
736 mnt_map *
737 mapc_find(char *map, char *opt, const char *maptype)
738 {
739 mnt_map *m;
740
741 /*
742 * Search the list of known maps to see if
743 * it has already been loaded. If it is found
744 * then return a duplicate reference to it.
745 * Otherwise make a new map as required and
746 * add it to the list of maps
747 */
748 ITER(m, mnt_map, &map_list_head)
749 if (STREQ(m->map_name, map))
750 return mapc_dup(m);
751 m = mapc_create(map, opt, maptype);
752 ins_que(&m->hdr, &map_list_head);
753
754 return m;
755 }
756
757
758 /*
759 * Free a map.
760 */
761 void
762 mapc_free(opaque_t arg)
763 {
764 mnt_map *m = (mnt_map *) arg;
765
766 /*
767 * Decrement the reference count.
768 * If the reference count hits zero
769 * then throw the map away.
770 */
771 if (m && --m->refc == 0) {
772 mapc_clear(m);
773 XFREE(m->map_name);
774 rem_que(&m->hdr);
775 XFREE(m);
776 }
777 }
778
779
780 /*
781 * Search the map for the key. Put a safe (malloc'ed) copy in *pval or
782 * return an error code
783 */
784 static int
785 mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
786 {
787 int error = 0;
788 kv *k = 0;
789
790 /*
791 * Firewall
792 */
793 if (!m) {
794 plog(XLOG_ERROR, "Null map request for %s", key);
795 return ENOENT;
796 }
797
798 if (m->flags & MAPC_SYNC) {
799 /*
800 * Get modify time...
801 */
802 time_t t;
803 error = (*m->mtime) (m, m->map_name, &t);
804 if (error || t > m->modify) {
805 plog(XLOG_INFO, "Map %s is out of date", m->map_name);
806 mapc_sync(m);
807 }
808 }
809
810 if (!MAPC_ISRE(m)) {
811 /*
812 * Compute the hash table offset
813 */
814 k = m->kvhash[kvhash_of(key)];
815
816 /*
817 * Scan the linked list for the key
818 */
819 while (k && !FSTREQ(k->key, key))
820 k = k->next;
821
822 }
823
824 #ifdef HAVE_REGEXEC
825 else if (recurse == MREC_FULL) {
826 /*
827 * Try for an RE match against the entire map.
828 * Note that this will be done in a "random"
829 * order.
830 */
831 int i;
832
833 for (i = 0; i < NKVHASH; i++) {
834 k = m->kvhash[i];
835 while (k) {
836 int retval;
837
838 /* XXX: this code was recently ported, and must be tested -Erez */
839 retval = regexec(&k->re, key, 0, 0, 0);
840 if (retval == 0) { /* succeeded */
841 break;
842 } else { /* failed to match, log error */
843 char errstr[256];
844
845 errstr[0] = '\0';
846 regerror(retval, &k->re, errstr, 256);
847 plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s",
848 key, k->key, errstr);
849 }
850 k = k->next;
851 }
852 if (k)
853 break;
854 }
855 }
856 #endif /* HAVE_REGEXEC */
857
858 /*
859 * If found then take a copy
860 */
861 if (k) {
862 if (k->val)
863 *pval = strdup(k->val);
864 else
865 error = ENOENT;
866 } else if (m->alloc >= MAPC_ALL) {
867 /*
868 * If the entire map is cached then this
869 * key does not exist.
870 */
871 error = ENOENT;
872 } else {
873 /*
874 * Otherwise search the map. If we are
875 * in incremental mode then add the key
876 * to the cache.
877 */
878 error = search_map(m, key, pval);
879 if (!error && m->alloc == MAPC_INC)
880 mapc_add_kv(m, strdup(key), strdup(*pval));
881 }
882
883 /*
884 * If an error, and a wildcard exists,
885 * and the key is not internal then
886 * return a copy of the wildcard.
887 */
888 if (error > 0) {
889 if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
890 char wildname[MAXPATHLEN];
891 char *subp;
892 if (*key == '/')
893 return error;
894 /*
895 * Keep chopping sub-directories from the RHS
896 * and replacing with "/ *" and repeat the lookup.
897 * For example:
898 * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
899 */
900 strcpy(wildname, key);
901 while (error && (subp = strrchr(wildname, '/'))) {
902 strcpy(subp, "/*");
903 dlog("mapc recurses on %s", wildname);
904 error = mapc_meta_search(m, wildname, pval, MREC_PART);
905 if (error)
906 *subp = 0;
907 }
908
909 if (error > 0 && m->wildcard) {
910 *pval = strdup(m->wildcard);
911 error = 0;
912 }
913 }
914 }
915 return error;
916 }
917
918
919 int
920 mapc_search(mnt_map *m, char *key, char **pval)
921 {
922 return mapc_meta_search(m, key, pval, MREC_FULL);
923 }
924
925
926 /*
927 * Get map cache in sync with physical representation
928 */
929 static void
930 mapc_sync(mnt_map *m)
931 {
932 if (m->alloc != MAPC_ROOT) {
933
934 /* do not clear map if map service is down */
935 if (m->isup) {
936 if (!((*m->isup)(m, m->map_name))) {
937 plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
938 return;
939 }
940 }
941
942 if (m->alloc >= MAPC_ALL) {
943 /* mapc_reload_map() always works */
944 mapc_reload_map(m);
945 } else {
946 mapc_clear(m);
947 /*
948 * Attempt to find the wildcard entry
949 */
950 mapc_find_wildcard(m);
951 }
952 }
953 }
954
955
956 /*
957 * Reload all the maps
958 * Called when Amd gets hit by a SIGHUP.
959 */
960 void
961 mapc_reload(void)
962 {
963 mnt_map *m;
964
965 /*
966 * For all the maps,
967 * Throw away the existing information.
968 * Do a reload
969 * Find the wildcard
970 */
971 ITER(m, mnt_map, &map_list_head)
972 mapc_sync(m);
973 }
974
975
976 /*
977 * Root map.
978 * The root map is used to bootstrap amd.
979 * All the require top-level mounts are added
980 * into the root map and then the map is iterated
981 * and a lookup is done on all the mount points.
982 * This causes the top level mounts to be automounted.
983 */
984 static int
985 root_init(mnt_map *m, char *map, time_t *tp)
986 {
987 *tp = clocktime();
988 return STREQ(map, ROOT_MAP) ? 0 : ENOENT;
989 }
990
991
992 /*
993 * Add a new entry to the root map
994 *
995 * dir - directory (key)
996 * opts - mount options
997 * map - map name
998 * cfm - optional amd configuration file map section structure
999 */
1000 void
1001 root_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm)
1002 {
1003 char str[MAXPATHLEN];
1004
1005 /*
1006 * First make sure we have a root map to talk about...
1007 */
1008 if (!root_map)
1009 root_map = mapc_find(ROOT_MAP, "mapdefault", NULL);
1010
1011 /*
1012 * Then add the entry...
1013 */
1014
1015 /*
1016 * Here I plug in the code to process other amd.conf options like
1017 * map_type, search_path, and flags (browsable_dirs, mount_type).
1018 */
1019
1020 if (cfm) {
1021 if (map) {
1022 sprintf(str, "cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"",
1023 cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "nfs",
1024 get_full_path(map, cfm->cfm_search_path, cfm->cfm_type));
1025 if (opts && opts[0] != '\0') {
1026 strcat(str, ";");
1027 strcat(str, opts);
1028 }
1029 if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL)
1030 strcat(str, ";opts:=rw,fullybrowsable");
1031 if (cfm->cfm_flags & CFM_BROWSABLE_DIRS)
1032 strcat(str, ";opts:=rw,browsable");
1033 if (cfm->cfm_type) {
1034 strcat(str, ";maptype:=");
1035 strcat(str, cfm->cfm_type);
1036 }
1037 } else {
1038 strcpy(str, opts);
1039 }
1040 } else {
1041 if (map)
1042 sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1043 map, opts ? opts : "");
1044 else
1045 strcpy(str, opts);
1046 }
1047 mapc_repl_kv(root_map, strdup((char *)dir), strdup(str));
1048 }
1049
1050
1051 int
1052 mapc_keyiter(mnt_map *m, key_fun *fn, opaque_t arg)
1053 {
1054 int i;
1055 int c = 0;
1056
1057 for (i = 0; i < NKVHASH; i++) {
1058 kv *k = m->kvhash[i];
1059 while (k) {
1060 (*fn) (k->key, arg);
1061 k = k->next;
1062 c++;
1063 }
1064 }
1065
1066 return c;
1067 }
1068
1069
1070 /*
1071 * Iterate on the root map and call (*fn)() on the key of all the nodes.
1072 * Returns the number of entries in the root map.
1073 */
1074 int
1075 root_keyiter(key_fun *fn, opaque_t arg)
1076 {
1077 if (root_map) {
1078 int c = mapc_keyiter(root_map, fn, arg);
1079 return c;
1080 }
1081
1082 return 0;
1083 }
1084
1085
1086 /*
1087 * Error map
1088 */
1089 static int
1090 error_init(mnt_map *m, char *map, time_t *tp)
1091 {
1092 plog(XLOG_USER, "No source data for map %s", map);
1093 *tp = 0;
1094
1095 return 0;
1096 }
1097
1098
1099 static int
1100 error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
1101 {
1102 return ENOENT;
1103 }
1104
1105
1106 static int
1107 error_reload(mnt_map *m, char *map, add_fn *fn)
1108 {
1109 return ENOENT;
1110 }
1111
1112
1113 static int
1114 error_mtime(mnt_map *m, char *map, time_t *tp)
1115 {
1116 *tp = 0;
1117
1118 return 0;
1119 }
1120
1121
1122 /*
1123 * Return absolute path of map, searched in a type-specific path.
1124 * Note: uses a static buffer for returned data.
1125 */
1126 static const char *
1127 get_full_path(const char *map, const char *path, const char *type)
1128 {
1129 char component[MAXPATHLEN], *str;
1130 static char full_path[MAXPATHLEN];
1131 int len;
1132
1133 /* for now, only file-type search paths are implemented */
1134 if (type && !STREQ(type, "file"))
1135 return map;
1136
1137 /* if null map, return it */
1138 if (!map)
1139 return map;
1140
1141 /* if map includes a '/', return it (absolute or relative path) */
1142 if (strchr(map, '/'))
1143 return map;
1144
1145 /* if path is empty, return map */
1146 if (!path)
1147 return map;
1148
1149 /* now break path into components, and search in each */
1150 strcpy(component, path);
1151
1152 str = strtok(component, ":");
1153 do {
1154 strcpy(full_path, str);
1155 len = strlen(full_path);
1156 if (full_path[len - 1] != '/') /* add trailing "/" if needed */
1157 strcat(full_path, "/");
1158 strcat(full_path, map);
1159 if (access(full_path, R_OK) == 0)
1160 return full_path;
1161 str = strtok(NULL, ":");
1162 } while (str);
1163
1164 return map; /* if found nothing, return map */
1165 }
1166