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