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