1 /* 2 * Copyright (c) 1989 Jan-Simon Pendry 3 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1989 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry at Imperial College, London. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)mapc.c 5.4 (Berkeley) 05/12/91 13 * 14 * $Id: mapc.c,v 5.2.1.9 91/05/07 22:18:07 jsp Alpha $ 15 * 16 */ 17 18 /* 19 * Mount map cache 20 */ 21 22 #include "am.h" 23 #ifdef HAS_REGEXP 24 #include RE_HDR 25 #endif 26 27 /* 28 * Hash table size 29 */ 30 #define NKVHASH (1 << 2) /* Power of two */ 31 32 /* 33 * Wildcard key 34 */ 35 static char wildcard[] = "*"; 36 37 /* 38 * Map cache types 39 * default, none, incremental, all, regexp 40 * MAPC_RE implies MAPC_ALL and must be numerically 41 * greater. 42 */ 43 #define MAPC_DFLT 0x000 44 #define MAPC_NONE 0x001 45 #define MAPC_INC 0x002 46 #define MAPC_ROOT 0x004 47 #define MAPC_ALL 0x010 48 #ifdef HAS_REGEXP 49 #define MAPC_RE 0x020 50 #define MAPC_ISRE(m) ((m)->alloc == MAPC_RE) 51 #else 52 #define MAPC_ISRE(m) FALSE 53 #endif 54 #define MAPC_CACHE_MASK 0x0ff 55 #define MAPC_SYNC 0x100 56 57 static struct opt_tab mapc_opt[] = { 58 { "all", MAPC_ALL }, 59 { "default", MAPC_DFLT }, 60 { "inc", MAPC_INC }, 61 { "mapdefault", MAPC_DFLT }, 62 { "none", MAPC_NONE }, 63 { "re", MAPC_RE }, 64 { "regexp", MAPC_RE }, 65 { "sync", MAPC_SYNC }, 66 { 0, 0 } 67 }; 68 69 /* 70 * Lookup recursion 71 */ 72 #define MREC_FULL 2 73 #define MREC_PART 1 74 #define MREC_NONE 0 75 76 /* 77 * Cache map operations 78 */ 79 typedef void add_fn P((mnt_map*, char*, char*)); 80 typedef int init_fn P((char*, time_t*)); 81 typedef int search_fn P((mnt_map*, char*, char*, char**, time_t*)); 82 typedef int reload_fn P((mnt_map*, char*, add_fn*)); 83 typedef int mtime_fn P((char*, time_t*)); 84 85 static void mapc_sync P((mnt_map*)); 86 87 /* 88 * Map type 89 */ 90 typedef struct map_type map_type; 91 struct map_type { 92 char *name; /* Name of this map type */ 93 init_fn *init; /* Initialisation */ 94 reload_fn *reload; /* Reload or fill */ 95 search_fn *search; /* Search for new entry */ 96 mtime_fn *mtime; /* Find modify time */ 97 int def_alloc; /* Default allocation mode */ 98 }; 99 100 /* 101 * Key-value pair 102 */ 103 typedef struct kv kv; 104 struct kv { 105 kv *next; 106 char *key; 107 char *val; 108 }; 109 110 struct mnt_map { 111 qelem hdr; 112 int refc; /* Reference count */ 113 short flags; /* Allocation flags */ 114 short alloc; /* Allocation mode */ 115 time_t modify; /* Modify time of map */ 116 char *map_name; /* Name of this map */ 117 char *wildcard; /* Wildcard value */ 118 reload_fn *reload; /* Function to be used for reloads */ 119 search_fn *search; /* Function to be used for searching */ 120 mtime_fn *mtime; /* Modify time function */ 121 kv *kvhash[NKVHASH]; /* Cached data */ 122 }; 123 124 /* 125 * Map for root node 126 */ 127 static mnt_map *root_map; 128 129 /* 130 * List of known maps 131 */ 132 extern qelem map_list_head; 133 qelem map_list_head = { &map_list_head, &map_list_head }; 134 135 /* 136 * Configuration 137 */ 138 139 /* ROOT MAP */ 140 static int root_init P((char*, time_t*)); 141 142 /* FILE MAPS */ 143 #ifdef HAS_FILE_MAPS 144 extern int file_init P((char*, time_t*)); 145 extern int file_reload P((mnt_map*, char*, add_fn*)); 146 extern int file_search P((mnt_map*, char*, char*, char**, time_t*)); 147 extern int file_mtime P((char*, time_t*)); 148 #endif /* HAS_FILE_MAPS */ 149 150 /* Network Information Service (NIS) MAPS */ 151 #ifdef HAS_NIS_MAPS 152 extern int nis_init P((char*, time_t*)); 153 #ifdef HAS_NIS_RELOAD 154 extern int nis_reload P((mnt_map*, char*, add_fn*)); 155 #else 156 #define nis_reload error_reload 157 #endif 158 extern int nis_search P((mnt_map*, char*, char*, char**, time_t*)); 159 #define nis_mtime nis_init 160 #endif /* HAS_NIS_MAPS */ 161 162 /* NDBM MAPS */ 163 #ifdef HAS_NDBM_MAPS 164 #ifdef OS_HAS_NDBM 165 extern int ndbm_init P((char*, time_t*)); 166 extern int ndbm_search P((mnt_map*, char*, char*, char**, time_t*)); 167 #define ndbm_mtime ndbm_init 168 #endif /* OS_HAS_NDBM */ 169 #endif /* HAS_NDBM_MAPS */ 170 171 /* PASSWD MAPS */ 172 #ifdef HAS_PASSWD_MAPS 173 extern int passwd_init P((char*, time_t*)); 174 extern int passwd_search P((mnt_map*, char*, char*, char**, time_t*)); 175 #endif /* HAS_PASSWD_MAPS */ 176 177 /* HESIOD MAPS */ 178 #ifdef HAS_HESIOD_MAPS 179 extern int hesiod_init P((char*, time_t*)); 180 #ifdef HAS_HESIOD_RELOAD 181 extern int hesiod_reload P((mnt_map*, char*, add_fn*)); 182 #else 183 #define hesiod_reload error_reload 184 #endif 185 extern int hesiod_search P((mnt_map*, char*, char*, char**, time_t*)); 186 #endif /* HAS_HESIOD_MAPS */ 187 188 /* UNION MAPS */ 189 #ifdef HAS_UNION_MAPS 190 extern int union_init P((char*, time_t*)); 191 extern int union_search P((mnt_map*, char*, char*, char**, time_t*)); 192 extern int union_reload P((mnt_map*, char*, add_fn*)); 193 #endif /* HAS_UNION_MAPS */ 194 195 /* ERROR MAP */ 196 static int error_init P((char*, time_t*)); 197 static int error_reload P((mnt_map*, char*, add_fn*)); 198 static int error_search P((mnt_map*, char*, char*, char**, time_t*)); 199 static int error_mtime P((char*, time_t*)); 200 201 static map_type maptypes[] = { 202 { "root", root_init, error_reload, error_search, error_mtime, MAPC_ROOT }, 203 204 #ifdef HAS_PASSWD_MAPS 205 { "passwd", passwd_init, error_reload, passwd_search, error_mtime, MAPC_INC }, 206 #endif 207 208 #ifdef HAS_HESIOD_MAPS 209 { "hesiod", hesiod_init, hesiod_reload, hesiod_search, error_mtime, MAPC_ALL }, 210 #endif 211 212 #ifdef HAS_UNION_MAPS 213 { "union", union_init, union_reload, union_search, error_mtime, MAPC_ALL }, 214 #endif 215 216 #ifdef HAS_NIS_MAPS 217 { "nis", nis_init, nis_reload, nis_search, nis_mtime, MAPC_INC }, 218 #endif 219 220 #ifdef HAS_NDBM_MAPS 221 { "ndbm", ndbm_init, error_reload, ndbm_search, ndbm_mtime, MAPC_INC }, 222 #endif 223 224 #ifdef HAS_FILE_MAPS 225 { "file", file_init, file_reload, file_search, file_mtime, MAPC_ALL }, 226 #endif 227 228 { "error", error_init, error_reload, error_search, error_mtime, MAPC_NONE }, 229 }; 230 231 /* 232 * Hash function 233 */ 234 static unsigned int kvhash_of P((char *key)); 235 static unsigned int kvhash_of(key) 236 char *key; 237 { 238 unsigned int i, j; 239 240 for (i = 0; j = *key++; i += j) 241 ; 242 243 return i % NKVHASH; 244 } 245 246 void mapc_showtypes P((FILE *fp)); 247 void mapc_showtypes(fp) 248 FILE *fp; 249 { 250 map_type *mt; 251 char *sep = ""; 252 for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) { 253 fprintf(fp, "%s%s", sep, mt->name); 254 sep = ", "; 255 } 256 } 257 258 static const char *reg_error = "?"; 259 void regerror P((const char *m)); 260 void regerror(m) 261 const char *m; 262 { 263 reg_error = m; 264 } 265 266 /* 267 * Add key and val to the map m. 268 * key and val are assumed to be safe copies 269 */ 270 void mapc_add_kv P((mnt_map *m, char *key, char *val)); 271 void mapc_add_kv(m, key, val) 272 mnt_map *m; 273 char *key; 274 char *val; 275 { 276 kv **h; 277 kv *n; 278 int hash = kvhash_of(key); 279 280 #ifdef DEBUG 281 dlog("add_kv: %s -> %s", key, val); 282 #endif 283 284 #ifdef HAS_REGEXP 285 if (MAPC_ISRE(m)) { 286 char keyb[MAXPATHLEN]; 287 regexp *re; 288 /* 289 * Make sure the string is bound to the start and end 290 */ 291 sprintf(keyb, "^%s$", key); 292 re = regcomp(keyb); 293 if (re == 0) { 294 plog(XLOG_USER, "error compiling RE \"%s\": %s", keyb, reg_error); 295 return; 296 } else { 297 free(key); 298 key = (char *) re; 299 } 300 } 301 #endif 302 303 h = &m->kvhash[hash]; 304 n = ALLOC(kv); 305 n->key = key; 306 n->val = val; 307 n->next = *h; 308 *h = n; 309 } 310 311 void mapc_repl_kv P((mnt_map *m, char *key, char *val)); 312 void mapc_repl_kv(m, key, val) 313 mnt_map *m; 314 char *key; 315 char *val; 316 { 317 kv *k; 318 319 /* 320 * Compute the hash table offset 321 */ 322 k = m->kvhash[kvhash_of(key)]; 323 324 /* 325 * Scan the linked list for the key 326 */ 327 while (k && !FSTREQ(k->key, key)) 328 k = k->next; 329 330 if (k) { 331 free(k->val); 332 k->val = val; 333 } else { 334 mapc_add_kv(m, key, val); 335 } 336 337 } 338 339 /* 340 * Search a map for a key. 341 * Calls map specific search routine. 342 * While map is out of date, keep re-syncing. 343 */ 344 static int search_map P((mnt_map *m, char *key, char **valp)); 345 static int search_map(m, key, valp) 346 mnt_map *m; 347 char *key; 348 char **valp; 349 { 350 int rc; 351 do { 352 rc = (*m->search)(m, m->map_name, key, valp, &m->modify); 353 if (rc < 0) { 354 plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name); 355 mapc_sync(m); 356 } 357 } while (rc < 0); 358 359 return rc; 360 } 361 362 /* 363 * Do a wildcard lookup in the map and 364 * save the result. 365 */ 366 static void mapc_find_wildcard P((mnt_map *m)); 367 static void mapc_find_wildcard(m) 368 mnt_map *m; 369 { 370 /* 371 * Attempt to find the wildcard entry 372 */ 373 int rc = search_map(m, wildcard, &m->wildcard); 374 375 if (rc != 0) 376 m->wildcard = 0; 377 } 378 379 /* 380 * Make a duplicate reference to an existing map 381 */ 382 #define mapc_dup(m) ((m)->refc++, (m)) 383 384 /* 385 * Do a map reload 386 */ 387 static int mapc_reload_map(m) 388 mnt_map *m; 389 { 390 int error; 391 #ifdef DEBUG 392 dlog("calling map reload on %s", m->map_name); 393 #endif 394 error = (*m->reload)(m, m->map_name, mapc_add_kv); 395 if (error) 396 return error; 397 m->wildcard = 0; 398 #ifdef DEBUG 399 dlog("calling mapc_search for wildcard"); 400 #endif 401 error = mapc_search(m, wildcard, &m->wildcard); 402 if (error) 403 m->wildcard = 0; 404 return 0; 405 } 406 407 /* 408 * Create a new map 409 */ 410 static mnt_map *mapc_create P((char *map, char *opt)); 411 static mnt_map *mapc_create(map, opt) 412 char *map; 413 char *opt; 414 { 415 mnt_map *m = ALLOC(mnt_map); 416 map_type *mt; 417 time_t modify; 418 int alloc = 0; 419 420 (void) cmdoption(opt, mapc_opt, &alloc); 421 422 for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) 423 if ((*mt->init)(map, &modify) == 0) 424 break; 425 /* assert: mt in maptypes */ 426 427 m->flags = alloc & ~MAPC_CACHE_MASK; 428 alloc &= MAPC_CACHE_MASK; 429 430 if (alloc == MAPC_DFLT) 431 alloc = mt->def_alloc; 432 switch (alloc) { 433 default: 434 plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt); 435 alloc = MAPC_INC; 436 /* fallthrough... */ 437 case MAPC_NONE: 438 case MAPC_INC: 439 case MAPC_ROOT: 440 break; 441 case MAPC_ALL: 442 /* 443 * If there is no support for reload and it was requested 444 * then back off to incremental instead. 445 */ 446 if (mt->reload == error_reload) { 447 plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name); 448 alloc = MAPC_INC; 449 } 450 break; 451 case MAPC_RE: 452 if (mt->reload == error_reload) { 453 plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name); 454 mt = &maptypes[sizeof(maptypes)/sizeof(maptypes[0]) - 1]; 455 /* assert: mt->name == "error" */ 456 } 457 break; 458 } 459 460 #ifdef DEBUG 461 dlog("Map for %s coming from maptype %s", map, mt->name); 462 #endif 463 464 m->alloc = alloc; 465 m->reload = mt->reload; 466 m->modify = modify; 467 m->search = alloc >= MAPC_ALL ? error_search : mt->search; 468 m->mtime = mt->mtime; 469 bzero((voidp) m->kvhash, sizeof(m->kvhash)); 470 m->map_name = strdup(map); 471 m->refc = 1; 472 m->wildcard = 0; 473 474 /* 475 * synchronize cache with reality 476 */ 477 mapc_sync(m); 478 479 return m; 480 } 481 482 /* 483 * Free the cached data in a map 484 */ 485 static void mapc_clear P((mnt_map *m)); 486 static void mapc_clear(m) 487 mnt_map *m; 488 { 489 int i; 490 491 /* 492 * For each of the hash slots, chain 493 * along free'ing the data. 494 */ 495 for (i = 0; i < NKVHASH; i++) { 496 kv *k = m->kvhash[i]; 497 while (k) { 498 kv *n = k->next; 499 free((voidp) k->key); 500 if (k->val) 501 free((voidp) k->val); 502 free((voidp) k); 503 k = n; 504 } 505 } 506 /* 507 * Zero the hash slots 508 */ 509 bzero((voidp) m->kvhash, sizeof(m->kvhash)); 510 /* 511 * Free the wildcard if it exists 512 */ 513 if (m->wildcard) { 514 free(m->wildcard); 515 m->wildcard = 0; 516 } 517 } 518 519 /* 520 * Find a map, or create one if it does not exist 521 */ 522 mnt_map *mapc_find P((char *map, char *opt)); 523 mnt_map *mapc_find(map, opt) 524 char *map; 525 char *opt; 526 { 527 mnt_map *m; 528 529 /* 530 * Search the list of known maps to see if 531 * it has already been loaded. If it is found 532 * then return a duplicate reference to it. 533 * Otherwise make a new map as required and 534 * add it to the list of maps 535 */ 536 ITER(m, mnt_map, &map_list_head) 537 if (STREQ(m->map_name, map)) 538 return mapc_dup(m); 539 540 m = mapc_create(map, opt); 541 ins_que(&m->hdr, &map_list_head); 542 return m; 543 } 544 545 /* 546 * Free a map. 547 */ 548 void mapc_free P((mnt_map *m)); 549 void mapc_free(m) 550 mnt_map *m; 551 { 552 /* 553 * Decrement the reference count. 554 * If the reference count hits zero 555 * then throw the map away. 556 */ 557 if (m && --m->refc == 0) { 558 mapc_clear(m); 559 free((voidp) m->map_name); 560 rem_que(&m->hdr); 561 free((voidp) m); 562 } 563 } 564 565 /* 566 * Search the map for the key. 567 * Put a safe copy in *pval or return 568 * an error code 569 */ 570 int mapc_meta_search P((mnt_map *m, char *key, char **pval, int recurse)); 571 int mapc_meta_search(m, key, pval, recurse) 572 mnt_map *m; 573 char *key; 574 char **pval; 575 int recurse; 576 { 577 int error = 0; 578 kv *k = 0; 579 580 /* 581 * Firewall 582 */ 583 if (!m) { 584 plog(XLOG_ERROR, "Null map request for %s", key); 585 return ENOENT; 586 } 587 588 if (m->flags & MAPC_SYNC) { 589 /* 590 * Get modify time... 591 */ 592 time_t t; 593 error = (*m->mtime)(m->map_name, &t); 594 if (error || t > m->modify) { 595 m->modify = t; 596 plog(XLOG_INFO, "Map %s is out of date", m->map_name); 597 mapc_sync(m); 598 } 599 } 600 601 if (!MAPC_ISRE(m)) { 602 /* 603 * Compute the hash table offset 604 */ 605 k = m->kvhash[kvhash_of(key)]; 606 607 /* 608 * Scan the linked list for the key 609 */ 610 while (k && !FSTREQ(k->key, key)) k = k->next; 611 612 } 613 #ifdef HAS_REGEXP 614 else if (recurse == MREC_FULL) { 615 /* 616 * Try for an RE match against the entire map. 617 * Note that this will be done in a "random" 618 * order. 619 */ 620 621 int i; 622 623 for (i = 0; i < NKVHASH; i++) { 624 k = m->kvhash[i]; 625 while (k) { 626 if (regexec(k->key, key)) 627 break; 628 k = k->next; 629 } 630 if (k) 631 break; 632 } 633 } 634 #endif 635 636 /* 637 * If found then take a copy 638 */ 639 if (k) { 640 if (k->val) 641 *pval = strdup(k->val); 642 else 643 error = ENOENT; 644 } else if (m->alloc >= MAPC_ALL) { 645 /* 646 * If the entire map is cached then this 647 * key does not exist. 648 */ 649 error = ENOENT; 650 } else { 651 /* 652 * Otherwise search the map. If we are 653 * in incremental mode then add the key 654 * to the cache. 655 */ 656 error = search_map(m, key, pval); 657 if (!error && m->alloc == MAPC_INC) 658 mapc_add_kv(m, strdup(key), strdup(*pval)); 659 } 660 661 /* 662 * If an error, and a wildcard exists, 663 * and the key is not internal then 664 * return a copy of the wildcard. 665 */ 666 if (error > 0) { 667 if (recurse == MREC_FULL && !MAPC_ISRE(m)) { 668 char wildname[MAXPATHLEN]; 669 char *subp; 670 if (*key == '/') 671 return error; 672 /* 673 * Keep chopping sub-directories from the RHS 674 * and replacing with "/ *" and repeat the lookup. 675 * For example: 676 * "src/gnu/gcc" -> "src / gnu / *" -> "src / *" 677 */ 678 strcpy(wildname, key); 679 while (error && (subp = strrchr(wildname, '/'))) { 680 strcpy(subp, "/*"); 681 #ifdef DEBUG 682 dlog("mapc recurses on %s", wildname); 683 #endif 684 error = mapc_meta_search(m, wildname, pval, MREC_PART); 685 if (error) 686 *subp = 0; 687 } 688 if (error > 0 && m->wildcard) { 689 *pval = strdup(m->wildcard); 690 error = 0; 691 } 692 } 693 } 694 695 return error; 696 } 697 698 int mapc_search P((mnt_map *m, char *key, char **pval)); 699 int mapc_search(m, key, pval) 700 mnt_map *m; 701 char *key; 702 char **pval; 703 { 704 return mapc_meta_search(m, key, pval, MREC_FULL); 705 } 706 707 /* 708 * Get map cache in sync with physical representation 709 */ 710 static void mapc_sync P((mnt_map *m)); 711 static void mapc_sync(m) 712 mnt_map *m; 713 { 714 if (m->alloc != MAPC_ROOT) { 715 mapc_clear(m); 716 717 if (m->alloc >= MAPC_ALL) 718 if (mapc_reload_map(m)) 719 m->alloc = MAPC_INC; 720 /* 721 * Attempt to find the wildcard entry 722 */ 723 if (m->alloc < MAPC_ALL) 724 mapc_find_wildcard(m); 725 } 726 } 727 728 /* 729 * Reload all the maps 730 * Called when Amd gets hit by a SIGHUP. 731 */ 732 void mapc_reload(P_void); 733 void mapc_reload() 734 { 735 mnt_map *m; 736 737 /* 738 * For all the maps, 739 * Throw away the existing information. 740 * Do a reload 741 * Find the wildcard 742 */ 743 ITER(m, mnt_map, &map_list_head) 744 mapc_sync(m); 745 } 746 747 /* 748 * Root map. 749 * The root map is used to bootstrap amd. 750 * All the require top-level mounts are added 751 * into the root map and then the map is iterated 752 * and a lookup is done on all the mount points. 753 * This causes the top level mounts to be automounted. 754 */ 755 756 static int root_init P((char *map, time_t *tp)); 757 static int root_init(map, tp) 758 char *map; 759 time_t *tp; 760 { 761 *tp = clocktime(); 762 return strcmp(map, ROOT_MAP) == 0 ? 0 : ENOENT; 763 } 764 765 /* 766 * Add a new entry to the root map 767 * 768 * dir - directory (key) 769 * opts - mount options 770 * map - map name 771 */ 772 void root_newmap P((char *dir, char *opts, char *map)); 773 void root_newmap(dir, opts, map) 774 char *dir; 775 char *opts; 776 char *map; 777 { 778 char str[MAXPATHLEN]; 779 780 /* 781 * First make sure we have a root map to talk about... 782 */ 783 if (!root_map) 784 root_map = mapc_find(ROOT_MAP, "mapdefault"); 785 786 /* 787 * Then add the entry... 788 */ 789 dir = strdup(dir); 790 if (map) 791 sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s", 792 map, opts ? opts : ""); 793 else 794 strcpy(str, opts); 795 mapc_repl_kv(root_map, dir, strdup(str)); 796 } 797 798 int mapc_keyiter P((mnt_map *m, void (*fn)(char*,voidp), voidp arg)); 799 int mapc_keyiter(m, fn, arg) 800 mnt_map *m; 801 void (*fn)P((char*, voidp)); 802 voidp arg; 803 { 804 int i; 805 int c = 0; 806 807 for (i = 0; i < NKVHASH; i++) { 808 kv *k = m->kvhash[i]; 809 while (k) { 810 (*fn)(k->key, arg); 811 k = k->next; 812 c++; 813 } 814 } 815 816 return c; 817 } 818 819 /* 820 * Iterate of the the root map 821 * and call (*fn)() on the key 822 * of all the nodes. 823 * Finally throw away the root map. 824 */ 825 int root_keyiter P((void (*fn)(char*,voidp), voidp arg)); 826 int root_keyiter(fn, arg) 827 void (*fn)P((char*,voidp)); 828 voidp arg; 829 { 830 if (root_map) { 831 int c = mapc_keyiter(root_map, fn, arg); 832 #ifdef notdef 833 mapc_free(root_map); 834 root_map = 0; 835 #endif 836 return c; 837 } 838 return 0; 839 } 840 841 /* 842 * Error map 843 */ 844 static int error_init P((char *map, time_t *tp)); 845 static int error_init(map, tp) 846 char *map; 847 time_t *tp; 848 { 849 plog(XLOG_USER, "No source data for map %s", map); 850 *tp = 0; 851 return 0; 852 } 853 854 /*ARGSUSED*/ 855 static int error_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp)); 856 static int error_search(m, map, key, pval, tp) 857 mnt_map *m; 858 char *map; 859 char *key; 860 char **pval; 861 time_t *tp; 862 { 863 return ENOENT; 864 } 865 866 /*ARGSUSED*/ 867 static int error_reload P((mnt_map *m, char *map, add_fn *fn)); 868 static int error_reload(m, map, fn) 869 mnt_map *m; 870 char *map; 871 add_fn *fn; 872 { 873 return ENOENT; 874 } 875 876 static int error_mtime P((char *map, time_t *tp)); 877 static int error_mtime(map, tp) 878 char *map; 879 time_t *tp; 880 { 881 *tp = 0; 882 return 0; 883 } 884