GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amd/mapc.c Lines: 0 184 0.0 %
Date: 2017-11-13 Branches: 0 138 0.0 %

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