home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / amd / part07 / mapc.c < prev   
Encoding:
C/C++ Source or Header  |  1990-04-10  |  11.3 KB  |  592 lines

  1. /*
  2.  * $Id: mapc.c,v 5.1.1.1 89/11/28 17:52:47 jsp Exp Locker: jsp $
  3.  *
  4.  * Copyright (c) 1989 Jan-Simon Pendry
  5.  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1989 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. /*
  29.  * Mount map cache
  30.  */
  31.  
  32. #include "am.h"
  33.  
  34. /*
  35.  * Hash table size
  36.  */
  37. #define    NKVHASH    (1 << 2)        /* Power of two */
  38.  
  39. /*
  40.  * Wildcard key
  41.  */
  42. static char wildcard[] = "*";
  43.  
  44. /*
  45.  * Map cache types
  46.  * default, none, incremental, all
  47.  */
  48. #define    MAPC_DFLT    -1
  49. #define    MAPC_NONE    0
  50. #define    MAPC_INC    1
  51. #define    MAPC_ALL    2
  52.  
  53. /*
  54.  * Do a map reload
  55.  */
  56. #define mapc_reload_map(m) \
  57.     ((*(m)->reload)(m, m->map_name, mapc_add_kv))
  58.  
  59. /*
  60.  * Cache map operations
  61.  */
  62. typedef void add_fn P((mnt_map*, char*, char*));
  63. typedef int init_fn P((char*));
  64. typedef int search_fn P((mnt_map*, char*, char*, char**, time_t*));
  65. typedef int reload_fn P((mnt_map*, char*, add_fn*));
  66.  
  67. static void mapc_sync P((mnt_map*));
  68.  
  69. /*
  70.  * Map type
  71.  */
  72. typedef struct map_type map_type;
  73. struct map_type {
  74.     char *name;            /* Name of this map type */
  75.     init_fn *init;            /* Initialisation */
  76.     reload_fn *reload;        /* Reload or fill */
  77.     search_fn *search;        /* Search for new entry */
  78.     int def_alloc;            /* Default allocation mode */
  79. };
  80.  
  81. /*
  82.  * Key-value pair
  83.  */
  84. typedef struct kv kv;
  85. struct kv {
  86.     kv *next;
  87.     char *key;
  88.     char *val;
  89. };
  90.  
  91. struct mnt_map {
  92.     qelem hdr;
  93.     int refc;            /* Reference count */
  94.     int alloc;            /* Allocation mode */
  95.     time_t modify;            /* Modify time of map */
  96.     char *map_name;            /* Name of this map */
  97.     char *wildcard;            /* Wildcard value */
  98.     reload_fn *reload;        /* Function to be used for reloads */
  99.     search_fn *search;        /* Function to be used for searching */
  100.     kv *kvhash[NKVHASH];        /* Cached data */
  101. };
  102.  
  103. /*
  104.  * Map for root node
  105.  */
  106. static mnt_map *root_map;
  107.  
  108. /*
  109.  * List of known maps
  110.  */
  111. extern qelem map_list_head;
  112. qelem map_list_head = { &map_list_head, &map_list_head };
  113.  
  114. /*
  115.  * Configuration
  116.  */
  117.  
  118. /* ROOT MAP */
  119. static int root_init P((char*));
  120.  
  121. /* FILE MAPS */
  122. #ifdef HAS_FILE_MAPS
  123. extern int file_init P((char*));
  124. extern int file_reload P((mnt_map*, char*, add_fn*));
  125. extern int file_search P((mnt_map*, char*, char*, char**, time_t*));
  126. #endif
  127.  
  128. /* YELLOW PAGES MAPS */
  129. #ifdef HAS_YP_MAPS
  130. extern int yp_init P((char*));
  131. extern int yp_search P((mnt_map*, char*, char*, char**, time_t*));
  132. #endif
  133.  
  134. /* GDBM MAPS */
  135. #ifdef HAS_GDBM_MAPS
  136. #define HAS_DATABASE
  137. #undef HAS_NDBM_MAPS
  138. extern int gdbm_init P((char*));
  139. extern int gdbm_search P((mnt_map*, char*, char*, char**, time_t*));
  140. #endif
  141.  
  142. /* NDBM MAPS */
  143. #ifndef HAS_DATABASE
  144. #ifdef HAS_NDBM_MAPS
  145. #ifdef OS_HAS_NDBM
  146. #define    HAS_DATABASE
  147. #undef HAS_GDBM_MAPS
  148. extern int ndbm_init P((char*));
  149. extern int ndbm_search P((mnt_map*, char*, char*, char**, time_t*));
  150. #endif
  151. #endif
  152. #endif
  153.  
  154. /* HESIOD MAPS */
  155. #ifdef HAS_HESIOD_MAPS
  156. extern int hesiod_init P((char*));
  157. extern int hesiod_search P((mnt_map*, char*, char*, char**, time_t*));
  158. #endif
  159.  
  160. /* ERROR MAP */
  161. static int error_init P((char*));
  162. static int error_reload P((mnt_map*, char*, add_fn*));
  163. static int error_search P((mnt_map*, char*, char*, char**, time_t*));
  164.  
  165. static map_type maptypes[] = {
  166.     { "root", root_init, error_reload, error_search, MAPC_ALL },
  167.  
  168. #ifdef HAS_HESIOD_MAPS
  169.     { "hesiod", hesiod_init, error_reload, hesiod_search, MAPC_INC },
  170. #endif
  171.  
  172. #ifdef HAS_YP_MAPS
  173.     { "yp", yp_init, error_reload, yp_search, MAPC_INC },
  174. #endif
  175.  
  176. #ifdef HAS_NDBM_MAPS
  177.     { "ndbm", ndbm_init, error_reload, ndbm_search, MAPC_INC },
  178. #endif
  179.  
  180. #ifdef HAS_GDBM_MAPS
  181.     { "gdbm", gdbm_init, error_reload, gdbm_search, MAPC_INC },
  182. #endif
  183.  
  184. #ifdef HAS_FILE_MAPS
  185.     { "file", file_init, file_reload, file_search, MAPC_ALL },
  186. #endif
  187.  
  188.     { "error", error_init, error_reload, error_search, MAPC_NONE },
  189. };
  190.  
  191. /*
  192.  * Hash function
  193.  */
  194. static unsigned int kvhash_of(key)
  195. char *key;
  196. {
  197.     unsigned int i, j;
  198.  
  199.     for (i = 0; j = *key++; i += j)
  200.         ;
  201.  
  202.     return i % NKVHASH;
  203. }
  204.  
  205. void mapc_showtypes(fp)
  206. FILE *fp;
  207. {
  208.     map_type *mt;
  209.     char *sep = "";
  210.     for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) {
  211.         fprintf(fp, "%s%s", sep, mt->name);
  212.         sep = ", ";
  213.     }
  214. }
  215.  
  216. /*
  217.  * Add key and val to the map m.
  218.  * key and val are assumed to be safe copies
  219.  */
  220. void mapc_add_kv(m, key, val)
  221. mnt_map *m;
  222. char *key;
  223. char *val;
  224. {
  225.     kv **h = &m->kvhash[kvhash_of(key)];
  226.     kv *n = ALLOC(kv);
  227.     n->key = key;
  228.     n->val = val;
  229.     n->next = *h;
  230.     *h = n;
  231. }
  232.  
  233. static int search_map(m, key, valp)
  234. mnt_map *m;
  235. char *key;
  236. char **valp;
  237. {
  238.     int rc;
  239.     do {
  240.         rc = (*m->search)(m, m->map_name, key, valp, &m->modify);
  241.         if (rc < 0) {
  242.             plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
  243.             mapc_sync(m);
  244.         }
  245.     } while (rc < 0);
  246.  
  247.     return rc;
  248. }
  249.  
  250. /*
  251.  * Do a wildcard lookup in the map and
  252.  * save the result.
  253.  */
  254. static void mapc_find_wildcard(m)
  255. mnt_map *m;
  256. {
  257.     /*
  258.      * Attempt to find the wildcard entry
  259.      */
  260.     int rc = search_map(m, wildcard, &m->wildcard);
  261.  
  262.     if (rc != 0)
  263.         m->wildcard = 0;
  264. }
  265.  
  266. /*
  267.  * Make a duplicate reference to an existing map
  268.  */
  269. #define mapc_dup(m) ((m)->refc++, (m))
  270.  
  271. /*
  272.  * Create a new map
  273.  */
  274. static mnt_map *mapc_create(map, opt)
  275. char *map;
  276. char *opt;
  277. {
  278.     mnt_map *m = ALLOC(mnt_map);
  279.     map_type *mt;
  280.     int alloc = STREQ(opt, "all") ? MAPC_ALL :
  281.             (STREQ(opt, "inc") ? MAPC_INC :
  282.             ((STREQ(opt, "default") || STREQ(opt, "mapdefault")) ? MAPC_DFLT :
  283.             MAPC_NONE));
  284.  
  285.     for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++)
  286.         if ((*mt->init)(map) == 0)
  287.             break;
  288.  
  289. #ifdef DEBUG
  290.     dlog("Map for %s coming from maptype %s", map, mt->name);
  291. #endif
  292.     /*
  293.      * If there is no support for reload and it was requested
  294.      * then back off to incremental instead.
  295.      */
  296.     if (mt->reload == error_reload && alloc == MAPC_ALL && mt->def_alloc != MAPC_ALL) {
  297.         plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"",
  298.                     mt->name);
  299.         alloc = MAPC_INC;
  300.     } else if (alloc == MAPC_DFLT)
  301.         alloc = mt->def_alloc;
  302.     m->alloc = alloc;
  303.     m->reload = mt->reload;
  304.     m->modify = clocktime();
  305.     m->search = alloc == MAPC_ALL ? error_search : mt->search;
  306.     bzero((voidp) m->kvhash, sizeof(m->kvhash));
  307.     m->map_name = strdup(map);
  308.     m->refc = 1;
  309.     /*
  310.      * Attempt to find the wildcard entry
  311.      */
  312.     mapc_find_wildcard(m);
  313.  
  314.     if (alloc == MAPC_ALL) {
  315.         /*
  316.          * If cache all is specified then load the cache
  317.          */
  318.         if (mapc_reload_map(m)) {
  319.             /*
  320.              * If that doesn't work then fallback to
  321.              * incremental cache mode
  322.              */
  323.             m->alloc = MAPC_INC;
  324.         }
  325.     }
  326.     return m;
  327. }
  328.  
  329. /*
  330.  * Free the cached data in a map
  331.  */
  332. static void mapc_clear(m)
  333. mnt_map *m;
  334. {
  335.     int i;
  336.  
  337.     /*
  338.      * For each of the hash slots, chain
  339.      * along free'ing the data.
  340.      */
  341.     for (i = 0; i < NKVHASH; i++) {
  342.         kv *k = m->kvhash[i];
  343.         while (k) {
  344.             kv *n = k->next;
  345.             free(k->key);
  346.             if (k->val)
  347.                 free(k->val);
  348.             free(k);
  349.             k = n;
  350.         }
  351.     }
  352.     /*
  353.      * Zero the hash slots
  354.      */
  355.     bzero((voidp) m->kvhash, sizeof(m->kvhash));
  356.     /*
  357.      * Free the wildcard if it exists
  358.      */
  359.     if (m->wildcard) {
  360.         free(m->wildcard);
  361.         m->wildcard = 0;
  362.     }
  363. }
  364.  
  365. /*
  366.  * Find a map, or create one if it does not exist
  367.  */
  368. mnt_map *mapc_find(map, opt)
  369. char *map;
  370. char *opt;
  371. {
  372.     mnt_map *m;
  373.  
  374.     /*
  375.      * Search the list of known maps to see if
  376.      * it has already been loaded.  If it is found
  377.      * then return a duplicate reference to it.
  378.      * Otherwise make a new map as required and
  379.      * add it to the list of maps
  380.      */
  381.     ITER(m, mnt_map, &map_list_head)
  382.         if (STREQ(m->map_name, map))
  383.             return mapc_dup(m);
  384.  
  385.     m = mapc_create(map, opt);
  386.     ins_que(&m->hdr, &map_list_head);
  387.     return m;
  388. }
  389.  
  390. /*
  391.  * Free a map.
  392.  */
  393. void mapc_free(m)
  394. mnt_map *m;
  395. {
  396.     /*
  397.      * Decrement the reference count.
  398.      * If the reference count hits zero
  399.      * then throw the map away.
  400.      */
  401.     if (--m->refc == 0) {
  402.         mapc_clear(m);
  403.         free(m->map_name);
  404.         rem_que(&m->hdr);
  405.         free(m);
  406.     }
  407. }
  408.  
  409. /*
  410.  * Search the map for the key.
  411.  * Put a safe copy in *pval or return
  412.  * an error code
  413.  */
  414. int mapc_search(m, key, pval)
  415. mnt_map *m;
  416. char *key;
  417. char **pval;
  418. {
  419.     int error = 0;
  420.     kv *k;
  421.  
  422.     /*
  423.      * Compute the hash table offset
  424.      */
  425.     k = m->kvhash[kvhash_of(key)];
  426.  
  427.     /*
  428.      * Scan the linked list for the key
  429.      */
  430.     while (k && !FSTREQ(k->key, key))
  431.         k = k->next;
  432.  
  433.     /*
  434.      * If found then take a copy
  435.      */
  436.     if (k) {
  437.         if (k->val)
  438.             *pval = strdup(k->val);
  439.         else
  440.             error = ENOENT;
  441.     } else if (m->alloc == MAPC_ALL) {
  442.         /*
  443.          * If the entire map is cached then this
  444.          * key does not exist.
  445.          */
  446.         error = ENOENT;
  447.     } else {
  448.         /*
  449.          * Otherwise search the map.  If we are
  450.          * in incremental mode then add the key
  451.          * to the cache.
  452.          */
  453.         error = search_map(m, key, pval);
  454.         if (!error && m->alloc == MAPC_INC)
  455.             mapc_add_kv(m, strdup(key), strdup(*pval));
  456.     }
  457.  
  458.     /*
  459.      * If an error, and a wildcard exists,
  460.      * and the key is not internal then
  461.      * return a copy of the wildcard.
  462.      */
  463.     if (error && m->wildcard && *key != '/') {
  464.         *pval = strdup(m->wildcard);
  465.         return 0;
  466.     }
  467.  
  468.     return error;
  469. }
  470.  
  471. static void mapc_sync(m)
  472. mnt_map *m;
  473. {
  474.     mapc_clear(m);
  475.  
  476.     if (m->alloc == MAPC_ALL)
  477.         if (mapc_reload_map(m))
  478.             m->alloc = MAPC_INC;
  479.     mapc_find_wildcard(m);
  480. }
  481.  
  482. /*
  483.  * Reload all the maps
  484.  * Called when amd gets hit by a SIGHUP.
  485.  */
  486. void mapc_reload()
  487. {
  488.     mnt_map *m;
  489.  
  490.     /*
  491.      * For all the maps,
  492.      * Throw away the existing information.
  493.      * Do a reload
  494.      * Find the wildcard
  495.      */
  496.     ITER(m, mnt_map, &map_list_head)
  497.         mapc_sync(m);
  498. }
  499.  
  500. /*
  501.  * Root map.
  502.  * The root map is used to bootstrap amd.
  503.  * All the require top-level mounts are added
  504.  * into the root map and then the map is iterated
  505.  * and a lookup is done on all the mount points.
  506.  * This causes the top level mounts to be automounted.
  507.  */
  508.  
  509. static int root_init(map)
  510. char *map;
  511. {
  512.     return strcmp(map, ROOT_MAP) == 0 ? 0 : ENOENT;
  513. }
  514.  
  515. /*
  516.  * Add a new entry to the root map
  517.  *
  518.  * dir - directory (key)
  519.  * opts - mount options
  520.  * map - map name
  521.  */
  522. void root_newmap(dir, opts, map)
  523. char *dir;
  524. char *opts;
  525. char *map;
  526. {
  527.     char str[MAXPATHLEN];
  528.  
  529.     if (!root_map)
  530.         root_map = mapc_find(ROOT_MAP, "all");
  531.  
  532.     dir = strdup(dir);
  533.     sprintf(str, "cache:=none;type:=auto;fs:=\"%s\";%s", map, opts ? opts : "");
  534.     mapc_add_kv(root_map, dir, strdup(str));
  535. }
  536.  
  537. /*
  538.  * Iterate of the the root map
  539.  * and call (*fn)() on the key
  540.  * of all the nodes.
  541.  * Finally throw away the root map.
  542.  */
  543. int root_keyiter(fn)
  544. void (*fn)P((char*));
  545. {
  546.     int i;
  547.     int c = 0;
  548.  
  549.     if (root_map) {
  550.         for (i = 0; i < NKVHASH; i++) {
  551.             kv *k = root_map->kvhash[i];
  552.             while (k) {
  553.                 (*fn)(k->key);
  554.                 k = k->next;
  555.                 c++;
  556.             }
  557.         }
  558.         mapc_free(root_map);
  559.         root_map = 0;
  560.     }
  561.     return c;
  562. }
  563.  
  564. /*
  565.  * Error map
  566.  */
  567. static int error_init(map)
  568. char *map;
  569. {
  570.     return 0;
  571. }
  572.  
  573. /*ARGSUSED*/
  574. static int error_search(m, map, key, pval, tp)
  575. mnt_map *m;
  576. char *map;
  577. char *key;
  578. char **pval;
  579. time_t *tp;
  580. {
  581.     return ENOENT;
  582. }
  583.  
  584. /*ARGSUSED*/
  585. static int error_reload(m, map, fn)
  586. mnt_map *m;
  587. char *map;
  588. add_fn *fn;
  589. {
  590.     return ENOENT;
  591. }
  592.