Am-Utils Cross Reference
am-utils/amd/mapc.c

source navigation ]
diff markup ]
identifier search ]
freetext search ]
file search ]
 
Version: 6.0.1 ] [ 6.0.2 ] [ 6.0.3 ] [ 6.0.4 ] [ 6.0.5 ] [ 6.0.6 ] [ 6.0.7 ] [ 6.0.8 ] [ 6.0.9 ] [ 6.0.10 ] [ 6.1 ] [ 6.1.1 ]

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
This page is hosted at the Filesystems and Storage Lab at Stony Brook.