Bug Summary

File:src/usr.sbin/amd/amd/mapc.c
Warning:line 742, column 1
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name mapc.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/amd/amd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/amd/amd/../rpcx -I /usr/src/usr.sbin/amd/amd/../include -D ARCH_REP="amd64" -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/amd/amd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/amd/amd/mapc.c
1/* $OpenBSD: mapc.c,v 1.24 2021/10/21 10:55:56 deraadt 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) (1 << 2) /* Power of two */
48
49/*
50 * Wildcard key
51 */
52static 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_DFLT0x000 0x000
61#define MAPC_NONE0x001 0x001
62#define MAPC_INC0x002 0x002
63#define MAPC_ROOT0x004 0x004
64#define MAPC_ALL0x010 0x010
65#define MAPC_RE0x020 0x020
66#define MAPC_ISRE(m)((m)->alloc == 0x020) ((m)->alloc == MAPC_RE0x020)
67#define MAPC_CACHE_MASK0x0ff 0x0ff
68#define MAPC_SYNC0x100 0x100
69
70static struct opt_tab mapc_opt[] = {
71 { "all", MAPC_ALL0x010 },
72 { "default", MAPC_DFLT0x000 },
73 { "inc", MAPC_INC0x002 },
74 { "mapdefault", MAPC_DFLT0x000 },
75 { "none", MAPC_NONE0x001 },
76 { "re", MAPC_RE0x020 },
77 { "regexp", MAPC_RE0x020 },
78 { "sync", MAPC_SYNC0x100 },
79 { 0, 0 }
80};
81
82/*
83 * Lookup recursion
84 */
85#define MREC_FULL2 2
86#define MREC_PART1 1
87#define MREC_NONE0 0
88
89/*
90 * Cache map operations
91 */
92typedef void add_fn(mnt_map *, char *, char *);
93typedef int init_fn(char *, time_t *);
94typedef int search_fn(mnt_map *, char *, char *, char **, time_t *);
95typedef int reload_fn(mnt_map *, char *, add_fn *);
96typedef int mtime_fn(char *, time_t *);
97
98static void mapc_sync(mnt_map *);
99
100/*
101 * Map type
102 */
103typedef struct map_type map_type;
104struct 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 */
116typedef struct kv kv;
117struct kv {
118 kv *next;
119 char *key;
120 char *val;
121};
122
123struct 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(1 << 2)]; /* Cached data */
135};
136
137/*
138 * Map for root node
139 */
140static mnt_map *root_map;
141
142/*
143 * List of known maps
144 */
145extern qelem map_list_head;
146qelem map_list_head = { &map_list_head, &map_list_head };
147
148/*
149 * Configuration
150 */
151
152/* ROOT MAP */
153static int root_init(char *, time_t *);
154
155/* FILE MAPS */
156extern int file_init(char *, time_t *);
157extern int file_reload(mnt_map *, char *, add_fn *);
158extern int file_search(mnt_map *, char *, char *, char **, time_t *);
159extern int file_mtime(char *, time_t *);
160
161/* Network Information Service (NIS) MAPS */
162extern int nis_init(char *, time_t *);
163extern int nis_reload(mnt_map *, char *, add_fn *);
164extern int nis_search(mnt_map *, char *, char *, char **, time_t *);
165#define nis_mtimenis_init nis_init
166
167/* NDBM MAPS */
168#ifdef HAS_NDBM_MAPS
169extern int ndbm_init(char *, time_t *);
170extern 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 */
175extern int passwd_init(char *, time_t *);
176extern int passwd_search(mnt_map *, char *, char *, char **, time_t *);
177
178/* UNION MAPS */
179extern int union_init(char *, time_t *);
180extern int union_search(mnt_map *, char *, char *, char **, time_t *);
181extern int union_reload(mnt_map *, char *, add_fn *);
182
183/* ERROR MAP */
184static int error_init(char *, time_t *);
185static int error_reload(mnt_map *, char *, add_fn *);
186static int error_search(mnt_map *, char *, char *, char **, time_t *);
187static int error_mtime(char *, time_t *);
188
189static map_type maptypes[] = {
190 { "root", root_init, error_reload, error_search, error_mtime, MAPC_ROOT0x004 },
191
192 { "passwd", passwd_init, error_reload, passwd_search, error_mtime, MAPC_INC0x002 },
193
194 { "union", union_init, union_reload, union_search, error_mtime, MAPC_ALL0x010 },
195
196 { "nis", nis_init, nis_reload, nis_search, nis_mtimenis_init, MAPC_INC0x002 },
197
198#ifdef HAS_NDBM_MAPS
199 { "ndbm", ndbm_init, error_reload, ndbm_search, ndbm_mtime, MAPC_INC0x002 },
200#endif
201
202 { "file", file_init, file_reload, file_search, file_mtime, MAPC_ALL0x010 },
203
204 { "error", error_init, error_reload, error_search, error_mtime, MAPC_NONE0x001 },
205};
206
207/*
208 * Hash function
209 */
210static unsigned int
211kvhash_of(char *key)
212{
213 unsigned int i, j;
214
215 for (i = 0; (j = *key++); i += j)
216 ;
217
218 return i % NKVHASH(1 << 2);
219}
220
221void
222mapc_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 */
237void
238mapc_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)((m)->alloc == 0x020)) {
249 char keyb[PATH_MAX1024];
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((void *)0)) {
259 plog(XLOG_USER0x0004, "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_USER0x0004, "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)((struct kv *) xmalloc(sizeof(struct kv)));
279 n->key = key;
280 n->val = val;
281 n->next = *h;
282 *h = n;
283}
284
285static void
286mapc_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)((*(k->key) == *(key)) && (strcmp(((k->key)), (
(key))) == 0))
)
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 */
315static 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_MAP0x0040, "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 */
334static void
335mapc_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)) ((m)->refc++, (m))
350
351/*
352 * Do a map reload
353 */
354static int
355mapc_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 */
377static mnt_map *
378mapc_create(char *map, char *opt)
379{
380 mnt_map *m = ALLOC(mnt_map)((struct mnt_map *) xmalloc(sizeof(struct 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_MASK0x0ff;
393 alloc &= MAPC_CACHE_MASK0x0ff;
394
395 if (alloc == MAPC_DFLT0x000)
396 alloc = mt->def_alloc;
397 switch (alloc) {
398 default:
399 plog(XLOG_USER0x0004, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
400 alloc = MAPC_INC0x002;
401 /* fallthrough... */
402 case MAPC_NONE0x001:
403 case MAPC_INC0x002:
404 case MAPC_ROOT0x004:
405 break;
406 case MAPC_ALL0x010:
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_WARNING0x0008, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name);
413 alloc = MAPC_INC0x002;
414 }
415 break;
416 case MAPC_RE0x020:
417 if (mt->reload == error_reload) {
418 plog(XLOG_WARNING0x0008, "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_ALL0x010 ? 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 */
450static void
451mapc_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(1 << 2); 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 */
485mnt_map *
486mapc_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)for ((m) = ((mnt_map *) (((&map_list_head))->q_forw));
(m) != ((mnt_map *) (&map_list_head)); (m) = ((mnt_map *
) (((qelem *) (m))->q_forw)))
498 if (STREQ(m->map_name, map)(strcmp((m->map_name), (map)) == 0))
499 return mapc_dup(m)((m)->refc++, (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 */
509void
510mapc_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 */
531int
532mapc_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_ERROR0x0002, "Null map request for %s", key);
542 return ENOENT2;
543 }
544
545 if (m->flags & MAPC_SYNC0x100) {
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_INFO0x0010, "Map %s is out of date", m->map_name);
554 mapc_sync(m);
555 }
556 }
557
558 if (!MAPC_ISRE(m)((m)->alloc == 0x020)) {
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->key) == *(key)) && (strcmp(((k->key)), (
(key))) == 0))
) k = k->next;
568
569 }
570 else if (recurse == MREC_FULL2) {
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(1 << 2); i++) {
580 k = m->kvhash[i];
581 while (k) {
582 if (regexec((regex_t *)k->key, key,
583 0, NULL((void *)0), 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 = ENOENT2;
600 } else if (m->alloc >= MAPC_ALL0x010) {
601 /*
602 * If the entire map is cached then this
603 * key does not exist.
604 */
605 error = ENOENT2;
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_INC0x002)
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_FULL2 && !MAPC_ISRE(m)((m)->alloc == 0x020)) {
624 char wildname[PATH_MAX1024];
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_PART1);
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
654int
655mapc_search(mnt_map *m, char *key, char **pval)
656{
657 return mapc_meta_search(m, key, pval, MREC_FULL2);
658}
659
660/*
661 * Get map cache in sync with physical representation
662 */
663static void
664mapc_sync(mnt_map *m)
665{
666 if (m->alloc != MAPC_ROOT0x004) {
667 mapc_clear(m);
668
669 if (m->alloc >= MAPC_ALL0x010)
670 if (mapc_reload_map(m))
671 m->alloc = MAPC_INC0x002;
672 /*
673 * Attempt to find the wildcard entry
674 */
675 if (m->alloc < MAPC_ALL0x010)
676 mapc_find_wildcard(m);
677 }
678}
679
680/*
681 * Reload all the maps
682 * Called when Amd gets hit by a SIGHUP.
683 */
684void 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)for ((m) = ((mnt_map *) (((&map_list_head))->q_forw));
(m) != ((mnt_map *) (&map_list_head)); (m) = ((mnt_map *
) (((qelem *) (m))->q_forw)))
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
707static int
708root_init(char *map, time_t *tp)
709{
710 *tp = clocktime()(clock_valid ? clock_valid : time(&clock_valid));
711 return strcmp(map, ROOT_MAP"\"root\"") == 0 ? 0 : ENOENT2;
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 */
721void
722root_newmap(char *dir, char *opts, char *map)
723{
724 char str[PATH_MAX1024];
725
726 /*
727 * First make sure we have a root map to talk about...
728 */
729 if (!root_map)
1
Assuming 'root_map' is non-null
2
Taking false branch
730 root_map = mapc_find(ROOT_MAP"\"root\"", "mapdefault");
731
732 /*
733 * Then add the entry...
734 */
735 dir = strdup(dir);
736 if (map)
3
Assuming 'map' is null
4
Taking false branch
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));
5
Memory is allocated
742}
6
Potential memory leak
743
744int
745mapc_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(1 << 2); 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 */
768int
769root_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 */
785static int
786error_init(char *map, time_t *tp)
787{
788 plog(XLOG_USER0x0004, "No source data for map %s", map);
789 *tp = 0;
790 return 0;
791}
792
793static int
794error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
795{
796 return ENOENT2;
797}
798
799static int
800error_reload(mnt_map *m, char *map, add_fn *fn)
801{
802 return ENOENT2;
803}
804
805static int
806error_mtime(char *map, time_t *tp)
807{
808 *tp = 0;
809 return 0;
810}