xref: /original-bsd/usr.sbin/amd/amd/mapc.c (revision baf24c0d)
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