xref: /netbsd/external/bsd/am-utils/dist/amd/mapc.c (revision 31bdb48a)
1*31bdb48aSchristos /*	$NetBSD: mapc.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
2a53f50b9Schristos 
3a53f50b9Schristos /*
4*31bdb48aSchristos  * Copyright (c) 1997-2014 Erez Zadok
5a53f50b9Schristos  * Copyright (c) 1989 Jan-Simon Pendry
6a53f50b9Schristos  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7a53f50b9Schristos  * Copyright (c) 1989 The Regents of the University of California.
8a53f50b9Schristos  * All rights reserved.
9a53f50b9Schristos  *
10a53f50b9Schristos  * This code is derived from software contributed to Berkeley by
11a53f50b9Schristos  * Jan-Simon Pendry at Imperial College, London.
12a53f50b9Schristos  *
13a53f50b9Schristos  * Redistribution and use in source and binary forms, with or without
14a53f50b9Schristos  * modification, are permitted provided that the following conditions
15a53f50b9Schristos  * are met:
16a53f50b9Schristos  * 1. Redistributions of source code must retain the above copyright
17a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer.
18a53f50b9Schristos  * 2. Redistributions in binary form must reproduce the above copyright
19a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer in the
20a53f50b9Schristos  *    documentation and/or other materials provided with the distribution.
21*31bdb48aSchristos  * 3. Neither the name of the University nor the names of its contributors
22a53f50b9Schristos  *    may be used to endorse or promote products derived from this software
23a53f50b9Schristos  *    without specific prior written permission.
24a53f50b9Schristos  *
25a53f50b9Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26a53f50b9Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27a53f50b9Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28a53f50b9Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29a53f50b9Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30a53f50b9Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31a53f50b9Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32a53f50b9Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33a53f50b9Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34a53f50b9Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35a53f50b9Schristos  * SUCH DAMAGE.
36a53f50b9Schristos  *
37a53f50b9Schristos  *
38a53f50b9Schristos  * File: am-utils/amd/mapc.c
39a53f50b9Schristos  *
40a53f50b9Schristos  */
41a53f50b9Schristos 
42a53f50b9Schristos /*
43a53f50b9Schristos  * Mount map cache
44a53f50b9Schristos  */
45a53f50b9Schristos 
46a53f50b9Schristos #ifdef HAVE_CONFIG_H
47a53f50b9Schristos # include <config.h>
48a53f50b9Schristos #endif /* HAVE_CONFIG_H */
49a53f50b9Schristos #include <am_defs.h>
50a53f50b9Schristos #include <amd.h>
51a53f50b9Schristos 
52a53f50b9Schristos /*
53a53f50b9Schristos  * Make a duplicate reference to an existing map
54a53f50b9Schristos  */
55a53f50b9Schristos #define mapc_dup(m) ((m)->refc++, (m))
56a53f50b9Schristos 
57a53f50b9Schristos /*
58a53f50b9Schristos  * Map cache types
59a53f50b9Schristos  * default, none, incremental, all, regexp
60a53f50b9Schristos  * MAPC_RE implies MAPC_ALL and must be numerically
61a53f50b9Schristos  * greater.
62a53f50b9Schristos  */
63a53f50b9Schristos #define	MAPC_DFLT	0x000
64a53f50b9Schristos #define	MAPC_NONE	0x001
65a53f50b9Schristos #define	MAPC_INC	0x002
66a53f50b9Schristos #define	MAPC_ROOT	0x004
67a53f50b9Schristos #define	MAPC_ALL	0x010
68a53f50b9Schristos #define	MAPC_CACHE_MASK	0x0ff
69a53f50b9Schristos #define	MAPC_SYNC	0x100
70a53f50b9Schristos 
71a53f50b9Schristos #ifdef HAVE_REGEXEC
72a53f50b9Schristos # define	MAPC_RE		0x020
73a53f50b9Schristos # define	MAPC_ISRE(m)	((m)->alloc == MAPC_RE)
74a53f50b9Schristos #else /* not HAVE_REGEXEC */
75a53f50b9Schristos # define	MAPC_ISRE(m)	FALSE
76a53f50b9Schristos #endif /* not HAVE_REGEXEC */
77a53f50b9Schristos 
78a53f50b9Schristos /*
79a53f50b9Schristos  * Lookup recursion
80a53f50b9Schristos  */
81a53f50b9Schristos #define	MREC_FULL	2
82a53f50b9Schristos #define	MREC_PART	1
83a53f50b9Schristos #define	MREC_NONE	0
84a53f50b9Schristos 
85a53f50b9Schristos static struct opt_tab mapc_opt[] =
86a53f50b9Schristos {
87a53f50b9Schristos   {"all", MAPC_ALL},
88a53f50b9Schristos   {"default", MAPC_DFLT},
89a53f50b9Schristos   {"inc", MAPC_INC},
90a53f50b9Schristos   {"mapdefault", MAPC_DFLT},
91a53f50b9Schristos   {"none", MAPC_NONE},
92a53f50b9Schristos #ifdef HAVE_REGEXEC
93a53f50b9Schristos   {"re", MAPC_RE},
94a53f50b9Schristos   {"regexp", MAPC_RE},
95a53f50b9Schristos #endif /* HAVE_REGEXEC */
96a53f50b9Schristos   {"sync", MAPC_SYNC},
97a53f50b9Schristos   {NULL, 0}
98a53f50b9Schristos };
99a53f50b9Schristos 
100a53f50b9Schristos /*
101a53f50b9Schristos  * Wildcard key
102a53f50b9Schristos  */
103a53f50b9Schristos static char wildcard[] = "*";
104a53f50b9Schristos 
105a53f50b9Schristos /*
106a53f50b9Schristos  * Map type
107a53f50b9Schristos  */
108a53f50b9Schristos typedef struct map_type map_type;
109a53f50b9Schristos struct map_type {
110a53f50b9Schristos   char *name;			/* Name of this map type */
111a53f50b9Schristos   init_fn *init;		/* Initialization */
112a53f50b9Schristos   reload_fn *reload;		/* Reload or fill */
113a53f50b9Schristos   isup_fn *isup;		/* Is service up or not? (1=up, 0=down) */
114a53f50b9Schristos   search_fn *search;		/* Search for new entry */
115a53f50b9Schristos   mtime_fn *mtime;		/* Find modify time */
116a53f50b9Schristos   int def_alloc;		/* Default allocation mode */
117a53f50b9Schristos };
118a53f50b9Schristos 
119a53f50b9Schristos /*
120a53f50b9Schristos  * Map for root node
121a53f50b9Schristos  */
122a53f50b9Schristos static mnt_map *root_map;
123a53f50b9Schristos 
124a53f50b9Schristos /*
125a53f50b9Schristos  * List of known maps
126a53f50b9Schristos  */
127a53f50b9Schristos qelem map_list_head = {&map_list_head, &map_list_head};
128a53f50b9Schristos 
129a53f50b9Schristos /*
130a53f50b9Schristos  * Configuration
131a53f50b9Schristos  */
132a53f50b9Schristos 
133a53f50b9Schristos /* forward definitions */
134a53f50b9Schristos static const char *get_full_path(const char *map, const char *path, const char *type);
135a53f50b9Schristos static int mapc_meta_search(mnt_map *, char *, char **, int);
136a53f50b9Schristos static void mapc_sync(mnt_map *);
137a53f50b9Schristos static void mapc_clear(mnt_map *);
138*31bdb48aSchristos static void mapc_clear_kvhash(kv **);
139a53f50b9Schristos 
140a53f50b9Schristos /* ROOT MAP */
141a53f50b9Schristos static int root_init(mnt_map *, char *, time_t *);
142a53f50b9Schristos 
143a53f50b9Schristos /* ERROR MAP */
144a53f50b9Schristos static int error_init(mnt_map *, char *, time_t *);
145a53f50b9Schristos static int error_reload(mnt_map *, char *, add_fn *);
146a53f50b9Schristos static int error_search(mnt_map *, char *, char *, char **, time_t *);
147a53f50b9Schristos static int error_mtime(mnt_map *, char *, time_t *);
148a53f50b9Schristos 
149a53f50b9Schristos /* PASSWD MAPS */
150a53f50b9Schristos #ifdef HAVE_MAP_PASSWD
151a53f50b9Schristos extern int passwd_init(mnt_map *, char *, time_t *);
152a53f50b9Schristos extern int passwd_search(mnt_map *, char *, char *, char **, time_t *);
153a53f50b9Schristos #endif /* HAVE_MAP_PASSWD */
154a53f50b9Schristos 
155a53f50b9Schristos /* HESIOD MAPS */
156a53f50b9Schristos #ifdef HAVE_MAP_HESIOD
157a53f50b9Schristos extern int amu_hesiod_init(mnt_map *, char *map, time_t *tp);
158a53f50b9Schristos extern int hesiod_isup(mnt_map *, char *);
159a53f50b9Schristos extern int hesiod_search(mnt_map *, char *, char *, char **, time_t *);
160a53f50b9Schristos #endif /* HAVE_MAP_HESIOD */
161a53f50b9Schristos 
162a53f50b9Schristos /* LDAP MAPS */
163a53f50b9Schristos #ifdef HAVE_MAP_LDAP
164a53f50b9Schristos extern int amu_ldap_init(mnt_map *, char *map, time_t *tp);
165a53f50b9Schristos extern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *);
166a53f50b9Schristos extern int amu_ldap_mtime(mnt_map *, char *, time_t *);
167a53f50b9Schristos #endif /* HAVE_MAP_LDAP */
168a53f50b9Schristos 
169a53f50b9Schristos /* UNION MAPS */
170a53f50b9Schristos #ifdef HAVE_MAP_UNION
171a53f50b9Schristos extern int union_init(mnt_map *, char *, time_t *);
172a53f50b9Schristos extern int union_search(mnt_map *, char *, char *, char **, time_t *);
173a53f50b9Schristos extern int union_reload(mnt_map *, char *, add_fn *);
174a53f50b9Schristos #endif /* HAVE_MAP_UNION */
175a53f50b9Schristos 
176a53f50b9Schristos /* Network Information Service PLUS (NIS+) */
177a53f50b9Schristos #ifdef HAVE_MAP_NISPLUS
178a53f50b9Schristos extern int nisplus_init(mnt_map *, char *, time_t *);
179a53f50b9Schristos extern int nisplus_reload(mnt_map *, char *, add_fn *);
180a53f50b9Schristos extern int nisplus_search(mnt_map *, char *, char *, char **, time_t *);
181a53f50b9Schristos extern int nisplus_mtime(mnt_map *, char *, time_t *);
182a53f50b9Schristos #endif /* HAVE_MAP_NISPLUS */
183a53f50b9Schristos 
184a53f50b9Schristos /* Network Information Service (YP, Yellow Pages) */
185a53f50b9Schristos #ifdef HAVE_MAP_NIS
186a53f50b9Schristos extern int nis_init(mnt_map *, char *, time_t *);
187a53f50b9Schristos extern int nis_reload(mnt_map *, char *, add_fn *);
188a53f50b9Schristos extern int nis_isup(mnt_map *, char *);
189a53f50b9Schristos extern int nis_search(mnt_map *, char *, char *, char **, time_t *);
190a53f50b9Schristos extern int nis_mtime(mnt_map *, char *, time_t *);
191a53f50b9Schristos #endif /* HAVE_MAP_NIS */
192a53f50b9Schristos 
193a53f50b9Schristos /* NDBM MAPS */
194a53f50b9Schristos #ifdef HAVE_MAP_NDBM
195a53f50b9Schristos extern int ndbm_init(mnt_map *, char *, time_t *);
196a53f50b9Schristos extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *);
197a53f50b9Schristos extern int ndbm_mtime(mnt_map *, char *, time_t *);
198a53f50b9Schristos #endif /* HAVE_MAP_NDBM */
199a53f50b9Schristos 
200a53f50b9Schristos /* FILE MAPS */
201a53f50b9Schristos #ifdef HAVE_MAP_FILE
202a53f50b9Schristos extern int file_init_or_mtime(mnt_map *, char *, time_t *);
203a53f50b9Schristos extern int file_reload(mnt_map *, char *, add_fn *);
204a53f50b9Schristos extern int file_search(mnt_map *, char *, char *, char **, time_t *);
205a53f50b9Schristos #endif /* HAVE_MAP_FILE */
206a53f50b9Schristos 
207a53f50b9Schristos /* EXECUTABLE MAPS */
208a53f50b9Schristos #ifdef HAVE_MAP_EXEC
209a53f50b9Schristos extern int exec_init(mnt_map *, char *, time_t *);
210a53f50b9Schristos extern int exec_search(mnt_map *, char *, char *, char **, time_t *);
211a53f50b9Schristos #endif /* HAVE_MAP_EXEC */
212a53f50b9Schristos 
213a53f50b9Schristos /* Sun-syntax MAPS */
214a53f50b9Schristos #ifdef HAVE_MAP_SUN
215a53f50b9Schristos /* XXX: fill in */
216a53f50b9Schristos #endif /* HAVE_MAP_SUN */
217a53f50b9Schristos 
218a53f50b9Schristos /* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */
219a53f50b9Schristos static map_type maptypes[] =
220a53f50b9Schristos {
221a53f50b9Schristos   {
222a53f50b9Schristos     "root",
223a53f50b9Schristos     root_init,
224a53f50b9Schristos     error_reload,
225a53f50b9Schristos     NULL,			/* isup function */
226a53f50b9Schristos     error_search,
227a53f50b9Schristos     error_mtime,
228a53f50b9Schristos     MAPC_ROOT
229a53f50b9Schristos   },
230a53f50b9Schristos #ifdef HAVE_MAP_PASSWD
231a53f50b9Schristos   {
232a53f50b9Schristos     "passwd",
233a53f50b9Schristos     passwd_init,
234a53f50b9Schristos     error_reload,
235a53f50b9Schristos     NULL,			/* isup function */
236a53f50b9Schristos     passwd_search,
237a53f50b9Schristos     error_mtime,
238a53f50b9Schristos     MAPC_INC
239a53f50b9Schristos   },
240a53f50b9Schristos #endif /* HAVE_MAP_PASSWD */
241a53f50b9Schristos #ifdef HAVE_MAP_HESIOD
242a53f50b9Schristos   {
243a53f50b9Schristos     "hesiod",
244a53f50b9Schristos     amu_hesiod_init,
245a53f50b9Schristos     error_reload,
246a53f50b9Schristos     hesiod_isup,		/* is Hesiod up or not? */
247a53f50b9Schristos     hesiod_search,
248a53f50b9Schristos     error_mtime,
249a53f50b9Schristos     MAPC_INC
250a53f50b9Schristos   },
251a53f50b9Schristos #endif /* HAVE_MAP_HESIOD */
252a53f50b9Schristos #ifdef HAVE_MAP_LDAP
253a53f50b9Schristos   {
254a53f50b9Schristos     "ldap",
255a53f50b9Schristos     amu_ldap_init,
256a53f50b9Schristos     error_reload,
257a53f50b9Schristos     NULL,			/* isup function */
258a53f50b9Schristos     amu_ldap_search,
259a53f50b9Schristos     amu_ldap_mtime,
260a53f50b9Schristos     MAPC_INC
261a53f50b9Schristos   },
262a53f50b9Schristos #endif /* HAVE_MAP_LDAP */
263a53f50b9Schristos #ifdef HAVE_MAP_UNION
264a53f50b9Schristos   {
265a53f50b9Schristos     "union",
266a53f50b9Schristos     union_init,
267a53f50b9Schristos     union_reload,
268a53f50b9Schristos     NULL,			/* isup function */
269a53f50b9Schristos     union_search,
270a53f50b9Schristos     error_mtime,
271a53f50b9Schristos     MAPC_ALL
272a53f50b9Schristos   },
273a53f50b9Schristos #endif /* HAVE_MAP_UNION */
274a53f50b9Schristos #ifdef HAVE_MAP_NISPLUS
275a53f50b9Schristos   {
276a53f50b9Schristos     "nisplus",
277a53f50b9Schristos     nisplus_init,
278a53f50b9Schristos     nisplus_reload,
279a53f50b9Schristos     NULL,			/* isup function */
280a53f50b9Schristos     nisplus_search,
281a53f50b9Schristos     nisplus_mtime,
282a53f50b9Schristos     MAPC_INC
283a53f50b9Schristos   },
284a53f50b9Schristos #endif /* HAVE_MAP_NISPLUS */
285a53f50b9Schristos #ifdef HAVE_MAP_NIS
286a53f50b9Schristos   {
287a53f50b9Schristos     "nis",
288a53f50b9Schristos     nis_init,
289a53f50b9Schristos     nis_reload,
290a53f50b9Schristos     nis_isup,			/* is NIS up or not? */
291a53f50b9Schristos     nis_search,
292a53f50b9Schristos     nis_mtime,
293a53f50b9Schristos     MAPC_ALL
294a53f50b9Schristos   },
295a53f50b9Schristos #endif /* HAVE_MAP_NIS */
296a53f50b9Schristos #ifdef HAVE_MAP_NDBM
297a53f50b9Schristos   {
298a53f50b9Schristos     "ndbm",
299a53f50b9Schristos     ndbm_init,
300a53f50b9Schristos     error_reload,
301a53f50b9Schristos     NULL,			/* isup function */
302a53f50b9Schristos     ndbm_search,
303a53f50b9Schristos     ndbm_mtime,
304a53f50b9Schristos     MAPC_INC
305a53f50b9Schristos   },
306a53f50b9Schristos #endif /* HAVE_MAP_NDBM */
307a53f50b9Schristos #ifdef HAVE_MAP_FILE
308a53f50b9Schristos   {
309a53f50b9Schristos     "file",
310a53f50b9Schristos     file_init_or_mtime,
311a53f50b9Schristos     file_reload,
312a53f50b9Schristos     NULL,			/* isup function */
313a53f50b9Schristos     file_search,
314a53f50b9Schristos     file_init_or_mtime,
315a53f50b9Schristos     MAPC_ALL
316a53f50b9Schristos   },
317a53f50b9Schristos #endif /* HAVE_MAP_FILE */
318a53f50b9Schristos #ifdef HAVE_MAP_EXEC
319a53f50b9Schristos   {
320a53f50b9Schristos     "exec",
321a53f50b9Schristos     exec_init,
322a53f50b9Schristos     error_reload,
323a53f50b9Schristos     NULL,			/* isup function */
324a53f50b9Schristos     exec_search,
325a53f50b9Schristos     error_mtime,
326a53f50b9Schristos     MAPC_INC
327a53f50b9Schristos   },
328a53f50b9Schristos #endif /* HAVE_MAP_EXEC */
329*31bdb48aSchristos #ifdef notyet /* probe function needs to be there or SEGV */
330a53f50b9Schristos #ifdef HAVE_MAP_SUN
331a53f50b9Schristos   {
332a53f50b9Schristos     /* XXX: fill in */
333a53f50b9Schristos     "sun",
334a53f50b9Schristos     NULL,
335a53f50b9Schristos     NULL,
336a53f50b9Schristos     NULL,			/* isup function */
337a53f50b9Schristos     NULL,
338a53f50b9Schristos     NULL,
339a53f50b9Schristos     0
340a53f50b9Schristos   },
341a53f50b9Schristos #endif /* HAVE_MAP_SUN */
342*31bdb48aSchristos #endif
343a53f50b9Schristos   {
344a53f50b9Schristos     "error",
345a53f50b9Schristos     error_init,
346a53f50b9Schristos     error_reload,
347a53f50b9Schristos     NULL,			/* isup function */
348a53f50b9Schristos     error_search,
349a53f50b9Schristos     error_mtime,
350a53f50b9Schristos     MAPC_NONE
351a53f50b9Schristos   },
352a53f50b9Schristos };
353a53f50b9Schristos 
354a53f50b9Schristos 
355a53f50b9Schristos /*
356a53f50b9Schristos  * Hash function
357a53f50b9Schristos  */
358a53f50b9Schristos static u_int
kvhash_of(char * key)359a53f50b9Schristos kvhash_of(char *key)
360a53f50b9Schristos {
361a53f50b9Schristos   u_int i, j;
362a53f50b9Schristos 
363a53f50b9Schristos   for (i = 0; (j = *key++); i += j) ;
364a53f50b9Schristos 
365a53f50b9Schristos   return i % NKVHASH;
366a53f50b9Schristos }
367a53f50b9Schristos 
368a53f50b9Schristos 
369a53f50b9Schristos void
mapc_showtypes(char * buf,size_t l)370a53f50b9Schristos mapc_showtypes(char *buf, size_t l)
371a53f50b9Schristos {
372a53f50b9Schristos   map_type *mt=NULL, *lastmt;
373a53f50b9Schristos   int linesize = 0, i;
374a53f50b9Schristos 
375a53f50b9Schristos   i = sizeof(maptypes) / sizeof(maptypes[0]);
376a53f50b9Schristos   lastmt = maptypes + i;
377a53f50b9Schristos   buf[0] = '\0';
378a53f50b9Schristos   for (mt = maptypes; mt < lastmt; mt++) {
379a53f50b9Schristos     xstrlcat(buf, mt->name, l);
380a53f50b9Schristos     if (mt == (lastmt-1))
381a53f50b9Schristos       break;	      /* if last one, don't do xstrlcat's that follows */
382a53f50b9Schristos     linesize += strlen(mt->name);
383a53f50b9Schristos     if (--i > 0) {
384a53f50b9Schristos       xstrlcat(buf, ", ", l);
385a53f50b9Schristos       linesize += 2;
386a53f50b9Schristos     }
387a53f50b9Schristos     if (linesize > 54) {
388a53f50b9Schristos       linesize = 0;
389a53f50b9Schristos       xstrlcat(buf, "\n\t\t ", l);
390a53f50b9Schristos     }
391a53f50b9Schristos   }
392a53f50b9Schristos }
393a53f50b9Schristos 
394a53f50b9Schristos 
395a53f50b9Schristos /*
396a53f50b9Schristos  * Check if a map of a certain type exists.
397a53f50b9Schristos  * Return 1 (true) if exists, 0 (false) if not.
398a53f50b9Schristos  */
399a53f50b9Schristos int
mapc_type_exists(const char * type)400a53f50b9Schristos mapc_type_exists(const char *type)
401a53f50b9Schristos {
402a53f50b9Schristos   map_type *mt;
403a53f50b9Schristos 
404a53f50b9Schristos   if (!type)
405a53f50b9Schristos     return 0;
406a53f50b9Schristos   for (mt = maptypes;
407a53f50b9Schristos        mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
408a53f50b9Schristos        mt++) {
409a53f50b9Schristos     if (STREQ(type, mt->name))
410a53f50b9Schristos       return 1;
411a53f50b9Schristos   }
412a53f50b9Schristos   return 0;			/* not found anywhere */
413a53f50b9Schristos }
414a53f50b9Schristos 
415a53f50b9Schristos 
416a53f50b9Schristos /*
417a53f50b9Schristos  * Add key and val to the map m.
418a53f50b9Schristos  * key and val are assumed to be safe copies
419a53f50b9Schristos  */
420a53f50b9Schristos void
mapc_add_kv(mnt_map * m,char * key,char * val)421a53f50b9Schristos mapc_add_kv(mnt_map *m, char *key, char *val)
422a53f50b9Schristos {
423a53f50b9Schristos   kv **h;
424a53f50b9Schristos   kv *n;
425a53f50b9Schristos   int hash = kvhash_of(key);
426a53f50b9Schristos #ifdef HAVE_REGEXEC
427a53f50b9Schristos   regex_t re;
428a53f50b9Schristos #endif /* HAVE_REGEXEC */
429a53f50b9Schristos 
430a53f50b9Schristos   dlog("add_kv: %s -> %s", key, val);
431a53f50b9Schristos 
432a53f50b9Schristos   if (val != NULL && strchr(val, '\n') != NULL) {
433a53f50b9Schristos     /*
434a53f50b9Schristos      * If the entry value contains multiple lines we need to break
435a53f50b9Schristos      * them up and add them recursively.  This is a workaround to
436a53f50b9Schristos      * support Sun style multi-mounts.  Amd converts Sun style
437a53f50b9Schristos      * mulit-mounts to type:=auto.  The problem is that Sun packs all
438a53f50b9Schristos      * the entries on one line.  When Amd does the conversion it puts
439a53f50b9Schristos      * each type:=auto entry on the same line separated by '\n'.
440a53f50b9Schristos      */
441a53f50b9Schristos     char *entry, *tok;
442a53f50b9Schristos 
443a53f50b9Schristos     /*
444a53f50b9Schristos      * The first line should contain the first entry.  The key for
445a53f50b9Schristos      * this entry is the key passed into this function.
446a53f50b9Schristos      */
447a53f50b9Schristos     if ((tok = strtok(val, "\n")) != NULL) {
448*31bdb48aSchristos       mapc_add_kv(m, key, xstrdup(tok));
449a53f50b9Schristos     }
450a53f50b9Schristos 
451a53f50b9Schristos     /*
452a53f50b9Schristos      * For the rest of the entries we need to tokenize them by '\n'
453a53f50b9Schristos      * and separate the keys from there entries.
454a53f50b9Schristos      */
455a53f50b9Schristos     while ((tok = strtok(NULL, "\n")) != NULL) {
456a53f50b9Schristos       key = tok;
457a53f50b9Schristos       /* find the entry */
458a53f50b9Schristos       for (entry = key; *entry && !isspace((unsigned char)*entry); entry++);
459a53f50b9Schristos       if (*entry) {
460a53f50b9Schristos 	*entry++ = '\0';
461a53f50b9Schristos       }
462a53f50b9Schristos 
463*31bdb48aSchristos       mapc_add_kv(m, xstrdup(key), xstrdup(entry));
464a53f50b9Schristos     }
465a53f50b9Schristos 
466a53f50b9Schristos     XFREE(val);
467a53f50b9Schristos     return;
468a53f50b9Schristos   }
469a53f50b9Schristos 
470a53f50b9Schristos #ifdef HAVE_REGEXEC
471a53f50b9Schristos   if (MAPC_ISRE(m)) {
472a53f50b9Schristos     char pattern[MAXPATHLEN];
473a53f50b9Schristos     int retval;
474a53f50b9Schristos 
475a53f50b9Schristos     /*
476a53f50b9Schristos      * Make sure the string is bound to the start and end
477a53f50b9Schristos      */
478a53f50b9Schristos     xsnprintf(pattern, sizeof(pattern), "^%s$", key);
479a53f50b9Schristos     retval = regcomp(&re, pattern, REG_ICASE);
480a53f50b9Schristos     if (retval != 0) {
481a53f50b9Schristos       char errstr[256];
482a53f50b9Schristos 
483a53f50b9Schristos       /* XXX: this code was recently ported, and must be tested -Erez */
484a53f50b9Schristos       errstr[0] = '\0';
485a53f50b9Schristos       regerror(retval, &re, errstr, 256);
486a53f50b9Schristos       plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr);
487a53f50b9Schristos       return;
488a53f50b9Schristos     }
489*31bdb48aSchristos   } else
490*31bdb48aSchristos     memset(&re, 0, sizeof(re));
491a53f50b9Schristos #endif /* HAVE_REGEXEC */
492a53f50b9Schristos 
493a53f50b9Schristos   h = &m->kvhash[hash];
494a53f50b9Schristos   n = ALLOC(struct kv);
495a53f50b9Schristos   n->key = key;
496a53f50b9Schristos #ifdef HAVE_REGEXEC
497a53f50b9Schristos   memcpy(&n->re, &re, sizeof(regex_t));
498a53f50b9Schristos #endif /* HAVE_REGEXEC */
499a53f50b9Schristos   n->val = val;
500a53f50b9Schristos   n->next = *h;
501a53f50b9Schristos   *h = n;
502*31bdb48aSchristos   m->nentries++;
503a53f50b9Schristos }
504a53f50b9Schristos 
505a53f50b9Schristos 
506a53f50b9Schristos static void
mapc_repl_kv(mnt_map * m,char * key,char * val)507a53f50b9Schristos mapc_repl_kv(mnt_map *m, char *key, char *val)
508a53f50b9Schristos {
509a53f50b9Schristos   kv *k;
510a53f50b9Schristos 
511a53f50b9Schristos   /*
512a53f50b9Schristos    * Compute the hash table offset
513a53f50b9Schristos    */
514a53f50b9Schristos   k = m->kvhash[kvhash_of(key)];
515a53f50b9Schristos 
516a53f50b9Schristos   /*
517a53f50b9Schristos    * Scan the linked list for the key
518a53f50b9Schristos    */
519a53f50b9Schristos   while (k && !FSTREQ(k->key, key))
520a53f50b9Schristos     k = k->next;
521a53f50b9Schristos 
522a53f50b9Schristos   if (k) {
523a53f50b9Schristos     XFREE(k->val);
524a53f50b9Schristos     k->val = val;
525a53f50b9Schristos   } else {
526a53f50b9Schristos     mapc_add_kv(m, key, val);
527a53f50b9Schristos   }
528a53f50b9Schristos }
529a53f50b9Schristos 
530a53f50b9Schristos 
531a53f50b9Schristos /*
532a53f50b9Schristos  * Search a map for a key.
533a53f50b9Schristos  * Calls map specific search routine.
534a53f50b9Schristos  * While map is out of date, keep re-syncing.
535a53f50b9Schristos  */
536a53f50b9Schristos static int
search_map(mnt_map * m,char * key,char ** valp)537a53f50b9Schristos search_map(mnt_map *m, char *key, char **valp)
538a53f50b9Schristos {
539a53f50b9Schristos   int rc;
540a53f50b9Schristos 
541a53f50b9Schristos   do {
542a53f50b9Schristos     rc = (*m->search) (m, m->map_name, key, valp, &m->modify);
543a53f50b9Schristos     if (rc < 0) {
544a53f50b9Schristos       plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
545a53f50b9Schristos       mapc_sync(m);
546a53f50b9Schristos     }
547a53f50b9Schristos   } while (rc < 0);
548a53f50b9Schristos 
549a53f50b9Schristos   return rc;
550a53f50b9Schristos }
551a53f50b9Schristos 
552a53f50b9Schristos 
553a53f50b9Schristos /*
554a53f50b9Schristos  * Do a wildcard lookup in the map and
555a53f50b9Schristos  * save the result.
556a53f50b9Schristos  */
557a53f50b9Schristos static void
mapc_find_wildcard(mnt_map * m)558a53f50b9Schristos mapc_find_wildcard(mnt_map *m)
559a53f50b9Schristos {
560a53f50b9Schristos   /*
561a53f50b9Schristos    * Attempt to find the wildcard entry
562a53f50b9Schristos    */
563a53f50b9Schristos   int rc = search_map(m, wildcard, &m->wildcard);
564a53f50b9Schristos 
565a53f50b9Schristos   if (rc != 0)
566a53f50b9Schristos     m->wildcard = NULL;
567a53f50b9Schristos }
568a53f50b9Schristos 
569a53f50b9Schristos 
570a53f50b9Schristos /*
571a53f50b9Schristos  * Do a map reload.
572a53f50b9Schristos  * Attempt to reload without losing current data by switching the hashes
573a53f50b9Schristos  * round.
574a53f50b9Schristos  * If reloading was needed and succeeded, return 1; else return 0.
575a53f50b9Schristos  */
576a53f50b9Schristos static int
mapc_reload_map(mnt_map * m)577a53f50b9Schristos mapc_reload_map(mnt_map *m)
578a53f50b9Schristos {
579a53f50b9Schristos   int error, ret = 0;
580*31bdb48aSchristos   kv *maphash[NKVHASH];
581a53f50b9Schristos   time_t t;
582a53f50b9Schristos 
583a53f50b9Schristos   error = (*m->mtime) (m, m->map_name, &t);
584a53f50b9Schristos   if (error) {
585a53f50b9Schristos     t = m->modify;
586a53f50b9Schristos   }
587a53f50b9Schristos 
588a53f50b9Schristos   /*
589a53f50b9Schristos    * skip reloading maps that have not been modified, unless
590a53f50b9Schristos    * amq -f was used (do_mapc_reload is 0)
591a53f50b9Schristos    */
592a53f50b9Schristos   if (m->reloads != 0 && do_mapc_reload != 0) {
593a53f50b9Schristos     if (t <= m->modify) {
594a53f50b9Schristos       plog(XLOG_INFO, "reload of map %s is not needed (in sync)", m->map_name);
595a53f50b9Schristos       dlog("map %s last load time is %d, last modify time is %d",
596a53f50b9Schristos 	   m->map_name, (int) m->modify, (int) t);
597a53f50b9Schristos       return ret;
598a53f50b9Schristos     }
599a53f50b9Schristos   }
600a53f50b9Schristos 
601a53f50b9Schristos   /* copy the old hash and zero the map */
602a53f50b9Schristos   memcpy((voidp) maphash, (voidp) m->kvhash, sizeof(m->kvhash));
603a53f50b9Schristos   memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
604a53f50b9Schristos 
605a53f50b9Schristos   dlog("calling map reload on %s", m->map_name);
606*31bdb48aSchristos   m->nentries = 0;
607a53f50b9Schristos   error = (*m->reload) (m, m->map_name, mapc_add_kv);
608a53f50b9Schristos   if (error) {
609a53f50b9Schristos     if (m->reloads == 0)
610a53f50b9Schristos       plog(XLOG_FATAL, "first time load of map %s failed!", m->map_name);
611a53f50b9Schristos     else
612a53f50b9Schristos       plog(XLOG_ERROR, "reload of map %s failed - using old values",
613a53f50b9Schristos 	   m->map_name);
614a53f50b9Schristos     mapc_clear(m);
615a53f50b9Schristos     memcpy((voidp) m->kvhash, (voidp) maphash, sizeof(m->kvhash));
616a53f50b9Schristos   } else {
617a53f50b9Schristos     if (m->reloads++ == 0)
618a53f50b9Schristos       plog(XLOG_INFO, "first time load of map %s succeeded", m->map_name);
619a53f50b9Schristos     else
620a53f50b9Schristos       plog(XLOG_INFO, "reload #%d of map %s succeeded",
621a53f50b9Schristos 	   m->reloads, m->map_name);
622*31bdb48aSchristos     mapc_clear_kvhash(maphash);
623*31bdb48aSchristos     if (m->wildcard) {
624*31bdb48aSchristos        XFREE(m->wildcard);
625*31bdb48aSchristos        m->wildcard = NULL;
626*31bdb48aSchristos     }
627a53f50b9Schristos     m->modify = t;
628a53f50b9Schristos     ret = 1;
629a53f50b9Schristos   }
630a53f50b9Schristos 
631a53f50b9Schristos   dlog("calling mapc_search for wildcard");
632a53f50b9Schristos   error = mapc_search(m, wildcard, &m->wildcard);
633a53f50b9Schristos   if (error)
634a53f50b9Schristos     m->wildcard = NULL;
635a53f50b9Schristos   return ret;
636a53f50b9Schristos }
637a53f50b9Schristos 
638a53f50b9Schristos 
639a53f50b9Schristos /*
640a53f50b9Schristos  * Create a new map
641a53f50b9Schristos  */
642a53f50b9Schristos static mnt_map *
mapc_create(char * map,char * opt,const char * type,const char * mntpt)643a53f50b9Schristos mapc_create(char *map, char *opt, const char *type, const char *mntpt)
644a53f50b9Schristos {
645a53f50b9Schristos   mnt_map *m = ALLOC(struct mnt_map);
646a53f50b9Schristos   map_type *mt;
647a53f50b9Schristos   time_t modify = 0;
648a53f50b9Schristos   u_int alloc = 0;
649a53f50b9Schristos 
650a53f50b9Schristos   cmdoption(opt, mapc_opt, &alloc);
651a53f50b9Schristos 
652a53f50b9Schristos   /*
653a53f50b9Schristos    * If using a configuration file, and the map_type is defined, then look
654a53f50b9Schristos    * for it, in the maptypes array.  If found, initialize the map using that
655a53f50b9Schristos    * map_type.  If not found, return error.  If no map_type was defined,
656a53f50b9Schristos    * default to cycling through all maptypes.
657a53f50b9Schristos    */
658a53f50b9Schristos   if (use_conf_file && type) {
659a53f50b9Schristos     /* find what type of map this one is */
660a53f50b9Schristos     for (mt = maptypes;
661a53f50b9Schristos 	 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
662a53f50b9Schristos 	 mt++) {
663a53f50b9Schristos       if (STREQ(type, mt->name)) {
664a53f50b9Schristos 	plog(XLOG_INFO, "initializing amd.conf map %s of type %s", map, type);
665a53f50b9Schristos 	if ((*mt->init) (m, map, &modify) == 0) {
666a53f50b9Schristos 	  break;
667a53f50b9Schristos 	} else {
668a53f50b9Schristos 	  plog(XLOG_ERROR, "failed to initialize map %s", map);
669a53f50b9Schristos 	  error_init(m, map, &modify);
670a53f50b9Schristos 	  break;
671a53f50b9Schristos 	}
672a53f50b9Schristos       }
673a53f50b9Schristos     } /* end of "for (mt =" loop */
674a53f50b9Schristos 
675a53f50b9Schristos   } else {			/* cycle through all known maptypes */
676a53f50b9Schristos 
677a53f50b9Schristos     /*
678a53f50b9Schristos      * not using amd conf file or using it by w/o specifying map type
679a53f50b9Schristos      */
680a53f50b9Schristos     for (mt = maptypes;
681a53f50b9Schristos 	 mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]);
682a53f50b9Schristos 	 mt++) {
683a53f50b9Schristos       dlog("trying to initialize map %s of type %s ...", map, mt->name);
684a53f50b9Schristos       if ((*mt->init) (m, map, &modify) == 0) {
685a53f50b9Schristos 	break;
686a53f50b9Schristos       }
687a53f50b9Schristos     }
688a53f50b9Schristos   } /* end of "if (use_conf_file && (colpos = strchr ..." statement */
689a53f50b9Schristos 
690a53f50b9Schristos   /* assert: mt in maptypes */
691a53f50b9Schristos 
692a53f50b9Schristos   m->flags = alloc & ~MAPC_CACHE_MASK;
693*31bdb48aSchristos   m->nentries = 0;
694a53f50b9Schristos   alloc &= MAPC_CACHE_MASK;
695a53f50b9Schristos 
696a53f50b9Schristos   if (alloc == MAPC_DFLT)
697a53f50b9Schristos     alloc = mt->def_alloc;
698a53f50b9Schristos 
699a53f50b9Schristos   switch (alloc) {
700a53f50b9Schristos   default:
701a53f50b9Schristos     plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
702a53f50b9Schristos     alloc = MAPC_INC;
703a53f50b9Schristos     /* fall-through... */
704a53f50b9Schristos   case MAPC_NONE:
705a53f50b9Schristos   case MAPC_INC:
706a53f50b9Schristos   case MAPC_ROOT:
707a53f50b9Schristos     break;
708a53f50b9Schristos 
709a53f50b9Schristos   case MAPC_ALL:
710a53f50b9Schristos     /*
711a53f50b9Schristos      * If there is no support for reload and it was requested
712a53f50b9Schristos      * then back off to incremental instead.
713a53f50b9Schristos      */
714a53f50b9Schristos     if (mt->reload == error_reload) {
715a53f50b9Schristos       plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name);
716a53f50b9Schristos       alloc = MAPC_INC;
717a53f50b9Schristos     }
718a53f50b9Schristos     break;
719a53f50b9Schristos 
720a53f50b9Schristos #ifdef HAVE_REGEXEC
721a53f50b9Schristos   case MAPC_RE:
722a53f50b9Schristos     if (mt->reload == error_reload) {
723a53f50b9Schristos       plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name);
724a53f50b9Schristos       mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1];
725a53f50b9Schristos       /* assert: mt->name == "error" */
726a53f50b9Schristos     }
727a53f50b9Schristos     break;
728a53f50b9Schristos #endif /* HAVE_REGEXEC */
729a53f50b9Schristos   }
730a53f50b9Schristos 
731a53f50b9Schristos   dlog("Map for %s coming from maptype %s", map, mt->name);
732a53f50b9Schristos 
733a53f50b9Schristos   m->alloc = alloc;
734a53f50b9Schristos   m->reload = mt->reload;
735a53f50b9Schristos   m->isup = mt->isup;
736a53f50b9Schristos   m->modify = modify;
737a53f50b9Schristos   m->search = alloc >= MAPC_ALL ? error_search : mt->search;
738a53f50b9Schristos   m->mtime = mt->mtime;
739a53f50b9Schristos   memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
740*31bdb48aSchristos   m->map_name = xstrdup(map);
741a53f50b9Schristos   m->refc = 1;
742a53f50b9Schristos   m->wildcard = NULL;
743a53f50b9Schristos   m->reloads = 0;
744a53f50b9Schristos   /* initialize per-map information (flags, etc.) */
745a53f50b9Schristos   m->cfm = find_cf_map(mntpt);
746a53f50b9Schristos 
747a53f50b9Schristos   /*
748a53f50b9Schristos    * synchronize cache with reality
749a53f50b9Schristos    */
750a53f50b9Schristos   mapc_sync(m);
751a53f50b9Schristos 
752a53f50b9Schristos   return m;
753a53f50b9Schristos }
754a53f50b9Schristos 
755a53f50b9Schristos 
756a53f50b9Schristos /*
757*31bdb48aSchristos  * Free the cached data in a map hash
758a53f50b9Schristos  */
759a53f50b9Schristos static void
mapc_clear_kvhash(kv ** kvhash)760*31bdb48aSchristos mapc_clear_kvhash(kv **kvhash)
761a53f50b9Schristos {
762a53f50b9Schristos   int i;
763a53f50b9Schristos 
764a53f50b9Schristos   /*
765a53f50b9Schristos    * For each of the hash slots, chain
766a53f50b9Schristos    * along free'ing the data.
767a53f50b9Schristos    */
768a53f50b9Schristos   for (i = 0; i < NKVHASH; i++) {
769*31bdb48aSchristos     kv *k = kvhash[i];
770a53f50b9Schristos     while (k) {
771a53f50b9Schristos       kv *n = k->next;
772a53f50b9Schristos       XFREE(k->key);
773a53f50b9Schristos       XFREE(k->val);
774a53f50b9Schristos       XFREE(k);
775a53f50b9Schristos       k = n;
776a53f50b9Schristos     }
777a53f50b9Schristos   }
778*31bdb48aSchristos }
779*31bdb48aSchristos 
780*31bdb48aSchristos 
781*31bdb48aSchristos /*
782*31bdb48aSchristos  * Free the cached data in a map
783*31bdb48aSchristos  */
784*31bdb48aSchristos static void
mapc_clear(mnt_map * m)785*31bdb48aSchristos mapc_clear(mnt_map *m)
786*31bdb48aSchristos {
787*31bdb48aSchristos   mapc_clear_kvhash(m->kvhash);
788a53f50b9Schristos 
789a53f50b9Schristos   /*
790a53f50b9Schristos    * Zero the hash slots
791a53f50b9Schristos    */
792a53f50b9Schristos   memset((voidp) m->kvhash, 0, sizeof(m->kvhash));
793a53f50b9Schristos 
794a53f50b9Schristos   /*
795a53f50b9Schristos    * Free the wildcard if it exists
796a53f50b9Schristos    */
797a53f50b9Schristos   XFREE(m->wildcard);
798*31bdb48aSchristos   m->wildcard = NULL;
799*31bdb48aSchristos 
800*31bdb48aSchristos   m->nentries = 0;
801a53f50b9Schristos }
802a53f50b9Schristos 
803a53f50b9Schristos 
804a53f50b9Schristos /*
805a53f50b9Schristos  * Find a map, or create one if it does not exist
806a53f50b9Schristos  */
807a53f50b9Schristos mnt_map *
mapc_find(char * map,char * opt,const char * maptype,const char * mntpt)808a53f50b9Schristos mapc_find(char *map, char *opt, const char *maptype, const char *mntpt)
809a53f50b9Schristos {
810a53f50b9Schristos   mnt_map *m;
811a53f50b9Schristos 
812a53f50b9Schristos   /*
813a53f50b9Schristos    * Search the list of known maps to see if
814a53f50b9Schristos    * it has already been loaded.  If it is found
815a53f50b9Schristos    * then return a duplicate reference to it.
816a53f50b9Schristos    * Otherwise make a new map as required and
817a53f50b9Schristos    * add it to the list of maps
818a53f50b9Schristos    */
819a53f50b9Schristos   ITER(m, mnt_map, &map_list_head)
820a53f50b9Schristos     if (STREQ(m->map_name, map))
821a53f50b9Schristos       return mapc_dup(m);
822a53f50b9Schristos   m = mapc_create(map, opt, maptype, mntpt);
823a53f50b9Schristos   ins_que(&m->hdr, &map_list_head);
824a53f50b9Schristos 
825a53f50b9Schristos   return m;
826a53f50b9Schristos }
827a53f50b9Schristos 
828a53f50b9Schristos 
829a53f50b9Schristos /*
830a53f50b9Schristos  * Free a map.
831a53f50b9Schristos  */
832a53f50b9Schristos void
mapc_free(opaque_t arg)833a53f50b9Schristos mapc_free(opaque_t arg)
834a53f50b9Schristos {
835a53f50b9Schristos   mnt_map *m = (mnt_map *) arg;
836a53f50b9Schristos 
837a53f50b9Schristos   /*
838a53f50b9Schristos    * Decrement the reference count.
839a53f50b9Schristos    * If the reference count hits zero
840a53f50b9Schristos    * then throw the map away.
841a53f50b9Schristos    */
842a53f50b9Schristos   if (m && --m->refc == 0) {
843a53f50b9Schristos     mapc_clear(m);
844a53f50b9Schristos     XFREE(m->map_name);
845a53f50b9Schristos     rem_que(&m->hdr);
846a53f50b9Schristos     XFREE(m);
847a53f50b9Schristos   }
848a53f50b9Schristos }
849a53f50b9Schristos 
850a53f50b9Schristos 
851a53f50b9Schristos /*
852a53f50b9Schristos  * Search the map for the key.  Put a safe (malloc'ed) copy in *pval or
853a53f50b9Schristos  * return an error code
854a53f50b9Schristos  */
855a53f50b9Schristos static int
mapc_meta_search(mnt_map * m,char * key,char ** pval,int recurse)856a53f50b9Schristos mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
857a53f50b9Schristos {
858a53f50b9Schristos   int error = 0;
859a53f50b9Schristos   kv *k = NULL;
860a53f50b9Schristos 
861a53f50b9Schristos   /*
862a53f50b9Schristos    * Firewall
863a53f50b9Schristos    */
864a53f50b9Schristos   if (!m) {
865a53f50b9Schristos     plog(XLOG_ERROR, "Null map request for %s", key);
866a53f50b9Schristos     return ENOENT;
867a53f50b9Schristos   }
868a53f50b9Schristos 
869a53f50b9Schristos   if (m->flags & MAPC_SYNC) {
870a53f50b9Schristos     /*
871a53f50b9Schristos      * Get modify time...
872a53f50b9Schristos      */
873a53f50b9Schristos     time_t t;
874a53f50b9Schristos     error = (*m->mtime) (m, m->map_name, &t);
875a53f50b9Schristos     if (error || t > m->modify) {
876a53f50b9Schristos       plog(XLOG_INFO, "Map %s is out of date", m->map_name);
877a53f50b9Schristos       mapc_sync(m);
878a53f50b9Schristos     }
879a53f50b9Schristos   }
880a53f50b9Schristos 
881a53f50b9Schristos   if (!MAPC_ISRE(m)) {
882a53f50b9Schristos     /*
883a53f50b9Schristos      * Compute the hash table offset
884a53f50b9Schristos      */
885a53f50b9Schristos     k = m->kvhash[kvhash_of(key)];
886a53f50b9Schristos 
887a53f50b9Schristos     /*
888a53f50b9Schristos      * Scan the linked list for the key
889a53f50b9Schristos      */
890a53f50b9Schristos     while (k && !FSTREQ(k->key, key))
891a53f50b9Schristos       k = k->next;
892a53f50b9Schristos 
893a53f50b9Schristos   }
894a53f50b9Schristos 
895a53f50b9Schristos #ifdef HAVE_REGEXEC
896a53f50b9Schristos   else if (recurse == MREC_FULL) {
897a53f50b9Schristos     /*
898a53f50b9Schristos      * Try for an RE match against the entire map.
899a53f50b9Schristos      * Note that this will be done in a "random"
900a53f50b9Schristos      * order.
901a53f50b9Schristos      */
902a53f50b9Schristos     int i;
903a53f50b9Schristos 
904a53f50b9Schristos     for (i = 0; i < NKVHASH; i++) {
905a53f50b9Schristos       k = m->kvhash[i];
906a53f50b9Schristos       while (k) {
907a53f50b9Schristos 	int retval;
908a53f50b9Schristos 
909a53f50b9Schristos 	/* XXX: this code was recently ported, and must be tested -Erez */
910a53f50b9Schristos 	retval = regexec(&k->re, key, 0, NULL, 0);
911a53f50b9Schristos 	if (retval == 0) {	/* succeeded */
912a53f50b9Schristos 	  break;
913a53f50b9Schristos 	} else {		/* failed to match, log error */
914a53f50b9Schristos 	  char errstr[256];
915a53f50b9Schristos 
916a53f50b9Schristos 	  errstr[0] = '\0';
917a53f50b9Schristos 	  regerror(retval, &k->re, errstr, 256);
918a53f50b9Schristos 	  plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s",
919a53f50b9Schristos 	       key, k->key, errstr);
920a53f50b9Schristos 	}
921a53f50b9Schristos 	k = k->next;
922a53f50b9Schristos       }
923a53f50b9Schristos       if (k)
924a53f50b9Schristos 	break;
925a53f50b9Schristos     }
926a53f50b9Schristos   }
927a53f50b9Schristos #endif /* HAVE_REGEXEC */
928a53f50b9Schristos 
929a53f50b9Schristos   /*
930a53f50b9Schristos    * If found then take a copy
931a53f50b9Schristos    */
932a53f50b9Schristos   if (k) {
933a53f50b9Schristos     if (k->val)
934*31bdb48aSchristos       *pval = xstrdup(k->val);
935a53f50b9Schristos     else
936a53f50b9Schristos       error = ENOENT;
937a53f50b9Schristos   } else if (m->alloc >= MAPC_ALL) {
938a53f50b9Schristos     /*
939a53f50b9Schristos      * If the entire map is cached then this
940a53f50b9Schristos      * key does not exist.
941a53f50b9Schristos      */
942a53f50b9Schristos     error = ENOENT;
943a53f50b9Schristos   } else {
944a53f50b9Schristos     /*
945a53f50b9Schristos      * Otherwise search the map.  If we are
946a53f50b9Schristos      * in incremental mode then add the key
947a53f50b9Schristos      * to the cache.
948a53f50b9Schristos      */
949a53f50b9Schristos     error = search_map(m, key, pval);
950a53f50b9Schristos     if (!error && m->alloc == MAPC_INC)
951*31bdb48aSchristos       mapc_add_kv(m, xstrdup(key), xstrdup(*pval));
952a53f50b9Schristos   }
953a53f50b9Schristos 
954a53f50b9Schristos   /*
955a53f50b9Schristos    * If an error, and a wildcard exists,
956a53f50b9Schristos    * and the key is not internal then
957a53f50b9Schristos    * return a copy of the wildcard.
958a53f50b9Schristos    */
959a53f50b9Schristos   if (error > 0) {
960a53f50b9Schristos     if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
961a53f50b9Schristos       char wildname[MAXPATHLEN];
962a53f50b9Schristos       char *subp;
963a53f50b9Schristos       if (*key == '/')
964a53f50b9Schristos 	return error;
965a53f50b9Schristos       /*
966a53f50b9Schristos        * Keep chopping sub-directories from the RHS
967a53f50b9Schristos        * and replacing with "/ *" and repeat the lookup.
968a53f50b9Schristos        * For example:
969a53f50b9Schristos        * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
970a53f50b9Schristos        */
971a53f50b9Schristos       xstrlcpy(wildname, key, sizeof(wildname));
972a53f50b9Schristos       while (error && (subp = strrchr(wildname, '/'))) {
973a53f50b9Schristos 	/*
974a53f50b9Schristos 	 * sizeof space left in subp is sizeof wildname minus what's left
975a53f50b9Schristos 	 * after the strchr above returned a pointer inside wildname into
976a53f50b9Schristos 	 * subp.
977a53f50b9Schristos 	 */
978a53f50b9Schristos 	xstrlcpy(subp, "/*", sizeof(wildname) - (subp - wildname));
979a53f50b9Schristos 	dlog("mapc recurses on %s", wildname);
980a53f50b9Schristos 	error = mapc_meta_search(m, wildname, pval, MREC_PART);
981a53f50b9Schristos 	if (error)
982a53f50b9Schristos 	  *subp = '\0';
983a53f50b9Schristos       }
984a53f50b9Schristos 
985a53f50b9Schristos       if (error > 0 && m->wildcard) {
986*31bdb48aSchristos 	*pval = xstrdup(m->wildcard);
987a53f50b9Schristos 	error = 0;
988a53f50b9Schristos       }
989a53f50b9Schristos     }
990a53f50b9Schristos   }
991a53f50b9Schristos   return error;
992a53f50b9Schristos }
993a53f50b9Schristos 
994a53f50b9Schristos 
995a53f50b9Schristos int
mapc_search(mnt_map * m,char * key,char ** pval)996a53f50b9Schristos mapc_search(mnt_map *m, char *key, char **pval)
997a53f50b9Schristos {
998a53f50b9Schristos   return mapc_meta_search(m, key, pval, MREC_FULL);
999a53f50b9Schristos }
1000a53f50b9Schristos 
1001a53f50b9Schristos 
1002a53f50b9Schristos /*
1003a53f50b9Schristos  * Get map cache in sync with physical representation
1004a53f50b9Schristos  */
1005a53f50b9Schristos static void
mapc_sync(mnt_map * m)1006a53f50b9Schristos mapc_sync(mnt_map *m)
1007a53f50b9Schristos {
1008a53f50b9Schristos   int need_mtime_update = 0;
1009a53f50b9Schristos 
1010a53f50b9Schristos   if (m->alloc == MAPC_ROOT)
1011a53f50b9Schristos     return;			/* nothing to do */
1012a53f50b9Schristos 
1013a53f50b9Schristos   /* do not clear map if map service is down */
1014a53f50b9Schristos   if (m->isup) {
1015a53f50b9Schristos     if (!((*m->isup)(m, m->map_name))) {
1016a53f50b9Schristos       plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name);
1017a53f50b9Schristos       return;
1018a53f50b9Schristos     }
1019a53f50b9Schristos   }
1020a53f50b9Schristos 
1021a53f50b9Schristos   if (m->alloc >= MAPC_ALL) {
1022a53f50b9Schristos     /* mapc_reload_map() always works */
1023a53f50b9Schristos     need_mtime_update = mapc_reload_map(m);
1024a53f50b9Schristos   } else {
1025a53f50b9Schristos     mapc_clear(m);
1026a53f50b9Schristos     /*
1027a53f50b9Schristos      * Attempt to find the wildcard entry
1028a53f50b9Schristos      */
1029a53f50b9Schristos     mapc_find_wildcard(m);
1030a53f50b9Schristos     need_mtime_update = 1;	/* because mapc_clear always works */
1031a53f50b9Schristos   }
1032a53f50b9Schristos 
1033a53f50b9Schristos   /*
1034a53f50b9Schristos    * To be safe, update the mtime of the mnt_map's own node, so that the
1035a53f50b9Schristos    * kernel will flush all of its cached entries.
1036a53f50b9Schristos    */
1037a53f50b9Schristos   if (need_mtime_update && m->cfm) {
1038a53f50b9Schristos     am_node *mp = find_ap(m->cfm->cfm_dir);
1039a53f50b9Schristos     if (mp) {
1040a53f50b9Schristos       clocktime(&mp->am_fattr.na_mtime);
1041a53f50b9Schristos     } else {
1042a53f50b9Schristos       plog(XLOG_ERROR, "cannot find map %s to update its mtime",
1043a53f50b9Schristos 	   m->cfm->cfm_dir);
1044a53f50b9Schristos     }
1045a53f50b9Schristos   }
1046a53f50b9Schristos }
1047a53f50b9Schristos 
1048a53f50b9Schristos 
1049a53f50b9Schristos /*
1050a53f50b9Schristos  * Reload all the maps
1051a53f50b9Schristos  * Called when Amd gets hit by a SIGHUP.
1052a53f50b9Schristos  */
1053a53f50b9Schristos void
mapc_reload(void)1054a53f50b9Schristos mapc_reload(void)
1055a53f50b9Schristos {
1056a53f50b9Schristos   mnt_map *m;
1057a53f50b9Schristos 
1058a53f50b9Schristos   /*
1059a53f50b9Schristos    * For all the maps,
1060a53f50b9Schristos    * Throw away the existing information.
1061a53f50b9Schristos    * Do a reload
1062a53f50b9Schristos    * Find the wildcard
1063a53f50b9Schristos    */
1064a53f50b9Schristos   ITER(m, mnt_map, &map_list_head)
1065a53f50b9Schristos     mapc_sync(m);
1066a53f50b9Schristos }
1067a53f50b9Schristos 
1068a53f50b9Schristos 
1069a53f50b9Schristos /*
1070a53f50b9Schristos  * Root map.
1071a53f50b9Schristos  * The root map is used to bootstrap amd.
1072a53f50b9Schristos  * All the require top-level mounts are added
1073a53f50b9Schristos  * into the root map and then the map is iterated
1074a53f50b9Schristos  * and a lookup is done on all the mount points.
1075a53f50b9Schristos  * This causes the top level mounts to be automounted.
1076a53f50b9Schristos  */
1077a53f50b9Schristos static int
root_init(mnt_map * m,char * map,time_t * tp)1078a53f50b9Schristos root_init(mnt_map *m, char *map, time_t *tp)
1079a53f50b9Schristos {
1080a53f50b9Schristos   *tp = clocktime(NULL);
1081a53f50b9Schristos   return STREQ(map, ROOT_MAP) ? 0 : ENOENT;
1082a53f50b9Schristos }
1083a53f50b9Schristos 
1084a53f50b9Schristos 
1085a53f50b9Schristos /*
1086a53f50b9Schristos  * Add a new entry to the root map
1087a53f50b9Schristos  *
1088a53f50b9Schristos  * dir - directory (key)
1089a53f50b9Schristos  * opts - mount options
1090a53f50b9Schristos  * map - map name
1091a53f50b9Schristos  * cfm - optional amd configuration file map section structure
1092a53f50b9Schristos  */
1093a53f50b9Schristos void
root_newmap(const char * dir,const char * opts,const char * map,const cf_map_t * cfm)1094a53f50b9Schristos root_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm)
1095a53f50b9Schristos {
1096a53f50b9Schristos   char str[MAXPATHLEN];
1097a53f50b9Schristos 
1098a53f50b9Schristos   /*
1099a53f50b9Schristos    * First make sure we have a root map to talk about...
1100a53f50b9Schristos    */
1101a53f50b9Schristos   if (!root_map)
1102a53f50b9Schristos     root_map = mapc_find(ROOT_MAP, "mapdefault", NULL, NULL);
1103a53f50b9Schristos 
1104a53f50b9Schristos   /*
1105a53f50b9Schristos    * Then add the entry...
1106a53f50b9Schristos    */
1107a53f50b9Schristos 
1108a53f50b9Schristos   /*
1109a53f50b9Schristos    * Here I plug in the code to process other amd.conf options like
1110a53f50b9Schristos    * map_type, search_path, and flags (browsable_dirs, mount_type).
1111a53f50b9Schristos    */
1112a53f50b9Schristos 
1113a53f50b9Schristos   if (cfm) {
1114a53f50b9Schristos     if (map) {
1115a53f50b9Schristos       xsnprintf(str, sizeof(str),
1116a53f50b9Schristos 		"cache:=mapdefault;type:=toplvl;mount_type:=%s;fs:=\"%s\"",
1117a53f50b9Schristos 		cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "nfs",
1118a53f50b9Schristos 		get_full_path(map, cfm->cfm_search_path, cfm->cfm_type));
1119a53f50b9Schristos       if (opts && opts[0] != '\0') {
1120a53f50b9Schristos 	xstrlcat(str, ";", sizeof(str));
1121a53f50b9Schristos 	xstrlcat(str, opts, sizeof(str));
1122a53f50b9Schristos       }
1123a53f50b9Schristos       if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL)
1124a53f50b9Schristos 	xstrlcat(str, ";opts:=rw,fullybrowsable", sizeof(str));
1125a53f50b9Schristos       if (cfm->cfm_flags & CFM_BROWSABLE_DIRS)
1126a53f50b9Schristos 	xstrlcat(str, ";opts:=rw,browsable", sizeof(str));
1127a53f50b9Schristos       if (cfm->cfm_type) {
1128a53f50b9Schristos 	xstrlcat(str, ";maptype:=", sizeof(str));
1129a53f50b9Schristos 	xstrlcat(str, cfm->cfm_type, sizeof(str));
1130a53f50b9Schristos       }
1131a53f50b9Schristos     } else {
1132a53f50b9Schristos       xstrlcpy(str, opts, sizeof(str));
1133a53f50b9Schristos     }
1134a53f50b9Schristos   } else {
1135a53f50b9Schristos     if (map)
1136a53f50b9Schristos       xsnprintf(str, sizeof(str),
1137a53f50b9Schristos 		"cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
1138a53f50b9Schristos 		map, opts ? opts : "");
1139a53f50b9Schristos     else
1140a53f50b9Schristos       xstrlcpy(str, opts, sizeof(str));
1141a53f50b9Schristos   }
1142*31bdb48aSchristos   mapc_repl_kv(root_map, xstrdup(dir), xstrdup(str));
1143a53f50b9Schristos }
1144a53f50b9Schristos 
1145a53f50b9Schristos 
1146a53f50b9Schristos int
mapc_keyiter(mnt_map * m,key_fun * fn,opaque_t arg)1147a53f50b9Schristos mapc_keyiter(mnt_map *m, key_fun *fn, opaque_t arg)
1148a53f50b9Schristos {
1149a53f50b9Schristos   int i;
1150a53f50b9Schristos   int c = 0;
1151a53f50b9Schristos 
1152a53f50b9Schristos   for (i = 0; i < NKVHASH; i++) {
1153a53f50b9Schristos     kv *k = m->kvhash[i];
1154a53f50b9Schristos     while (k) {
1155a53f50b9Schristos       (*fn) (k->key, arg);
1156a53f50b9Schristos       k = k->next;
1157a53f50b9Schristos       c++;
1158a53f50b9Schristos     }
1159a53f50b9Schristos   }
1160a53f50b9Schristos 
1161a53f50b9Schristos   return c;
1162a53f50b9Schristos }
1163a53f50b9Schristos 
1164a53f50b9Schristos 
1165a53f50b9Schristos /*
1166a53f50b9Schristos  * Iterate on the root map and call (*fn)() on the key of all the nodes.
1167a53f50b9Schristos  * Returns the number of entries in the root map.
1168a53f50b9Schristos  */
1169a53f50b9Schristos int
root_keyiter(key_fun * fn,opaque_t arg)1170a53f50b9Schristos root_keyiter(key_fun *fn, opaque_t arg)
1171a53f50b9Schristos {
1172a53f50b9Schristos   if (root_map) {
1173a53f50b9Schristos     int c = mapc_keyiter(root_map, fn, arg);
1174a53f50b9Schristos     return c;
1175a53f50b9Schristos   }
1176a53f50b9Schristos 
1177a53f50b9Schristos   return 0;
1178a53f50b9Schristos }
1179a53f50b9Schristos 
1180a53f50b9Schristos 
1181a53f50b9Schristos /*
1182a53f50b9Schristos  * Error map
1183a53f50b9Schristos  */
1184a53f50b9Schristos static int
error_init(mnt_map * m,char * map,time_t * tp)1185a53f50b9Schristos error_init(mnt_map *m, char *map, time_t *tp)
1186a53f50b9Schristos {
1187a53f50b9Schristos   plog(XLOG_USER, "No source data for map %s", map);
1188a53f50b9Schristos   *tp = 0;
1189a53f50b9Schristos 
1190a53f50b9Schristos   return 0;
1191a53f50b9Schristos }
1192a53f50b9Schristos 
1193a53f50b9Schristos 
1194a53f50b9Schristos static int
error_search(mnt_map * m,char * map,char * key,char ** pval,time_t * tp)1195a53f50b9Schristos error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
1196a53f50b9Schristos {
1197a53f50b9Schristos   return ENOENT;
1198a53f50b9Schristos }
1199a53f50b9Schristos 
1200a53f50b9Schristos 
1201a53f50b9Schristos static int
error_reload(mnt_map * m,char * map,add_fn * fn)1202a53f50b9Schristos error_reload(mnt_map *m, char *map, add_fn *fn)
1203a53f50b9Schristos {
1204a53f50b9Schristos   return ENOENT;
1205a53f50b9Schristos }
1206a53f50b9Schristos 
1207a53f50b9Schristos 
1208a53f50b9Schristos static int
error_mtime(mnt_map * m,char * map,time_t * tp)1209a53f50b9Schristos error_mtime(mnt_map *m, char *map, time_t *tp)
1210a53f50b9Schristos {
1211a53f50b9Schristos   *tp = 0;
1212a53f50b9Schristos 
1213a53f50b9Schristos   return 0;
1214a53f50b9Schristos }
1215a53f50b9Schristos 
1216a53f50b9Schristos 
1217a53f50b9Schristos /*
1218a53f50b9Schristos  * Return absolute path of map, searched in a type-specific path.
1219a53f50b9Schristos  * Note: uses a static buffer for returned data.
1220a53f50b9Schristos  */
1221a53f50b9Schristos static const char *
get_full_path(const char * map,const char * path,const char * type)1222a53f50b9Schristos get_full_path(const char *map, const char *path, const char *type)
1223a53f50b9Schristos {
1224a53f50b9Schristos   char component[MAXPATHLEN], *str;
1225a53f50b9Schristos   static char full_path[MAXPATHLEN];
1226a53f50b9Schristos   int len;
1227a53f50b9Schristos 
1228a53f50b9Schristos   /* for now, only file-type search paths are implemented */
1229a53f50b9Schristos   if (type && !STREQ(type, "file"))
1230a53f50b9Schristos     return map;
1231a53f50b9Schristos 
1232a53f50b9Schristos   /* if null map, return it */
1233a53f50b9Schristos   if (!map)
1234a53f50b9Schristos     return map;
1235a53f50b9Schristos 
1236a53f50b9Schristos   /* if map includes a '/', return it (absolute or relative path) */
1237a53f50b9Schristos   if (strchr(map, '/'))
1238a53f50b9Schristos     return map;
1239a53f50b9Schristos 
1240a53f50b9Schristos   /* if path is empty, return map */
1241a53f50b9Schristos   if (!path)
1242a53f50b9Schristos     return map;
1243a53f50b9Schristos 
1244a53f50b9Schristos   /* now break path into components, and search in each */
1245a53f50b9Schristos   xstrlcpy(component, path, sizeof(component));
1246a53f50b9Schristos 
1247a53f50b9Schristos   str = strtok(component, ":");
1248a53f50b9Schristos   do {
1249a53f50b9Schristos     xstrlcpy(full_path, str, sizeof(full_path));
1250a53f50b9Schristos     len = strlen(full_path);
1251a53f50b9Schristos     if (full_path[len - 1] != '/') /* add trailing "/" if needed */
1252a53f50b9Schristos       xstrlcat(full_path, "/", sizeof(full_path));
1253a53f50b9Schristos     xstrlcat(full_path, map, sizeof(full_path));
1254a53f50b9Schristos     if (access(full_path, R_OK) == 0)
1255a53f50b9Schristos       return full_path;
1256a53f50b9Schristos     str = strtok(NULL, ":");
1257a53f50b9Schristos   } while (str);
1258a53f50b9Schristos 
1259a53f50b9Schristos   return map;			/* if found nothing, return map */
1260a53f50b9Schristos }
1261