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