xref: /minix3/libexec/ld.elf_so/paths.c (revision b3bac6e0e7fa18186e181d0b053df0f1a2294980)
1*84d9c625SLionel Sambuc /*	$NetBSD: paths.c,v 1.41 2013/05/06 08:02:20 skrll Exp $	 */
2e83f7ba2SBen Gras 
3e83f7ba2SBen Gras /*
4e83f7ba2SBen Gras  * Copyright 1996 Matt Thomas <matt@3am-software.com>
5e83f7ba2SBen Gras  * Copyright 2002 Charles M. Hannum <root@ihack.net>
6e83f7ba2SBen Gras  * All rights reserved.
7e83f7ba2SBen Gras  *
8e83f7ba2SBen Gras  * Redistribution and use in source and binary forms, with or without
9e83f7ba2SBen Gras  * modification, are permitted provided that the following conditions
10e83f7ba2SBen Gras  * are met:
11e83f7ba2SBen Gras  * 1. Redistributions of source code must retain the above copyright
12e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer.
13e83f7ba2SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
14e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer in the
15e83f7ba2SBen Gras  *    documentation and/or other materials provided with the distribution.
16e83f7ba2SBen Gras  * 3. The name of the author may not be used to endorse or promote products
17e83f7ba2SBen Gras  *    derived from this software without specific prior written permission.
18e83f7ba2SBen Gras  *
19e83f7ba2SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20e83f7ba2SBen Gras  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21e83f7ba2SBen Gras  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22e83f7ba2SBen Gras  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23e83f7ba2SBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24e83f7ba2SBen Gras  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25e83f7ba2SBen Gras  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26e83f7ba2SBen Gras  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27e83f7ba2SBen Gras  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28e83f7ba2SBen Gras  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29e83f7ba2SBen Gras  */
30e83f7ba2SBen Gras 
31e83f7ba2SBen Gras #include <sys/cdefs.h>
32e83f7ba2SBen Gras #ifndef lint
33*84d9c625SLionel Sambuc __RCSID("$NetBSD: paths.c,v 1.41 2013/05/06 08:02:20 skrll Exp $");
34e83f7ba2SBen Gras #endif /* not lint */
35e83f7ba2SBen Gras 
36e83f7ba2SBen Gras #include <err.h>
37e83f7ba2SBen Gras #include <errno.h>
38e83f7ba2SBen Gras #include <fcntl.h>
39e83f7ba2SBen Gras #include <stdarg.h>
40e83f7ba2SBen Gras #include <stdio.h>
41e83f7ba2SBen Gras #include <stdlib.h>
42e83f7ba2SBen Gras #include <string.h>
43e83f7ba2SBen Gras #include <unistd.h>
44e83f7ba2SBen Gras #include <sys/types.h>
45e83f7ba2SBen Gras #include <sys/param.h>
46e83f7ba2SBen Gras #include <sys/sysctl.h>
47e83f7ba2SBen Gras #include <sys/mman.h>
48e83f7ba2SBen Gras #include <sys/stat.h>
49e83f7ba2SBen Gras #include <sys/gmon.h>
50e83f7ba2SBen Gras #include <sys/socket.h>
51e83f7ba2SBen Gras #include <sys/mount.h>
52e83f7ba2SBen Gras #include <sys/mbuf.h>
53e83f7ba2SBen Gras #include <sys/resource.h>
54e83f7ba2SBen Gras #include <machine/cpu.h>
55e83f7ba2SBen Gras 
56e83f7ba2SBen Gras #include "debug.h"
57e83f7ba2SBen Gras #include "rtld.h"
58e83f7ba2SBen Gras 
59e83f7ba2SBen Gras static Search_Path *_rtld_find_path(Search_Path *, const char *, size_t);
60e83f7ba2SBen Gras static Search_Path **_rtld_append_path(Search_Path **, Search_Path **,
61e83f7ba2SBen Gras     const char *, const char *, const char *);
62e83f7ba2SBen Gras static void _rtld_process_mapping(Library_Xform **, const char *,
63e83f7ba2SBen Gras     const char *);
64e83f7ba2SBen Gras static char *exstrdup(const char *, const char *);
65e83f7ba2SBen Gras static const char *getstr(const char **, const char *, const char *);
66e83f7ba2SBen Gras static const char *getcstr(const char **, const char *, const char *);
67e83f7ba2SBen Gras static const char *getword(const char **, const char *, const char *);
68e83f7ba2SBen Gras static int matchstr(const char *, const char *, const char *);
69e83f7ba2SBen Gras 
70e83f7ba2SBen Gras static const char WS[] = " \t\n";
71e83f7ba2SBen Gras 
72e83f7ba2SBen Gras /*
73e83f7ba2SBen Gras  * Like xstrdup(), but takes end of string as a argument.
74e83f7ba2SBen Gras  */
75e83f7ba2SBen Gras static char *
exstrdup(const char * bp,const char * ep)76e83f7ba2SBen Gras exstrdup(const char *bp, const char *ep)
77e83f7ba2SBen Gras {
78e83f7ba2SBen Gras 	char *cp;
79e83f7ba2SBen Gras 	size_t len = ep - bp;
80e83f7ba2SBen Gras 
81e83f7ba2SBen Gras 	cp = xmalloc(len + 1);
82e83f7ba2SBen Gras 	memcpy(cp, bp, len);
83e83f7ba2SBen Gras 	cp[len] = '\0';
84e83f7ba2SBen Gras 	return (cp);
85e83f7ba2SBen Gras }
86e83f7ba2SBen Gras 
87e83f7ba2SBen Gras /*
88e83f7ba2SBen Gras  * Like strsep(), but takes end of string and doesn't put any NUL.  To
89e83f7ba2SBen Gras  * detect empty string, compare `*p' and return value.
90e83f7ba2SBen Gras  */
91e83f7ba2SBen Gras static const char *
getstr(const char ** p,const char * ep,const char * delim)92e83f7ba2SBen Gras getstr(const char **p, const char *ep, const char *delim)
93e83f7ba2SBen Gras {
94e83f7ba2SBen Gras 	const char *cp = *p, *q, *r;
95e83f7ba2SBen Gras 
96e83f7ba2SBen Gras 	if (ep < cp)
97e83f7ba2SBen Gras 		/* End of string */
98e83f7ba2SBen Gras 		return (NULL);
99e83f7ba2SBen Gras 
100e83f7ba2SBen Gras 	for (q = cp; q < ep; q++)
101e83f7ba2SBen Gras 		for (r = delim; *r != 0; r++)
102e83f7ba2SBen Gras 			if (*r == *q)
103e83f7ba2SBen Gras 				goto done;
104e83f7ba2SBen Gras 
105e83f7ba2SBen Gras done:
106e83f7ba2SBen Gras 	*p = q;
107e83f7ba2SBen Gras 	return (cp);
108e83f7ba2SBen Gras }
109e83f7ba2SBen Gras 
110e83f7ba2SBen Gras /*
111e83f7ba2SBen Gras  * Like getstr() above, but delim[] is complemented.
112e83f7ba2SBen Gras  */
113e83f7ba2SBen Gras static const char *
getcstr(const char ** p,const char * ep,const char * delim)114e83f7ba2SBen Gras getcstr(const char **p, const char *ep, const char *delim)
115e83f7ba2SBen Gras {
116e83f7ba2SBen Gras 	const char *cp = *p, *q, *r;
117e83f7ba2SBen Gras 
118e83f7ba2SBen Gras 	if (ep < cp)
119e83f7ba2SBen Gras 		/* End of string */
120e83f7ba2SBen Gras 		return (NULL);
121e83f7ba2SBen Gras 
122e83f7ba2SBen Gras 	for (q = cp; q < ep; q++)
123e83f7ba2SBen Gras 		for (r = delim; *r != *q; r++)
124e83f7ba2SBen Gras 			if (*r == 0)
125e83f7ba2SBen Gras 				goto done;
126e83f7ba2SBen Gras 
127e83f7ba2SBen Gras done:
128e83f7ba2SBen Gras 	*p = q;
129e83f7ba2SBen Gras 	return (cp);
130e83f7ba2SBen Gras }
131e83f7ba2SBen Gras 
132e83f7ba2SBen Gras static const char *
getword(const char ** p,const char * ep,const char * delim)133e83f7ba2SBen Gras getword(const char **p, const char *ep, const char *delim)
134e83f7ba2SBen Gras {
135e83f7ba2SBen Gras 
136e83f7ba2SBen Gras 	(void)getcstr(p, ep, delim);
137e83f7ba2SBen Gras 
138e83f7ba2SBen Gras 	/*
139e83f7ba2SBen Gras 	 * Now, we're looking non-delim, or end of string.
140e83f7ba2SBen Gras 	 */
141e83f7ba2SBen Gras 
142e83f7ba2SBen Gras 	return (getstr(p, ep, delim));
143e83f7ba2SBen Gras }
144e83f7ba2SBen Gras 
145e83f7ba2SBen Gras /*
146e83f7ba2SBen Gras  * Match `bp' against NUL terminated string pointed by `p'.
147e83f7ba2SBen Gras  */
148e83f7ba2SBen Gras static int
matchstr(const char * p,const char * bp,const char * ep)149e83f7ba2SBen Gras matchstr(const char *p, const char *bp, const char *ep)
150e83f7ba2SBen Gras {
151e83f7ba2SBen Gras 	int c;
152e83f7ba2SBen Gras 
153e83f7ba2SBen Gras 	while (bp < ep)
154e83f7ba2SBen Gras 		if ((c = *p++) == 0 || c != *bp++)
155e83f7ba2SBen Gras 			return (0);
156e83f7ba2SBen Gras 
157e83f7ba2SBen Gras 	return (*p == 0);
158e83f7ba2SBen Gras }
159e83f7ba2SBen Gras 
160e83f7ba2SBen Gras static Search_Path *
_rtld_find_path(Search_Path * path,const char * pathstr,size_t pathlen)161e83f7ba2SBen Gras _rtld_find_path(Search_Path *path, const char *pathstr, size_t pathlen)
162e83f7ba2SBen Gras {
163e83f7ba2SBen Gras 
164e83f7ba2SBen Gras 	for (; path != NULL; path = path->sp_next) {
165e83f7ba2SBen Gras 		if (pathlen == path->sp_pathlen &&
166e83f7ba2SBen Gras 		    memcmp(path->sp_path, pathstr, pathlen) == 0)
167e83f7ba2SBen Gras 			return path;
168e83f7ba2SBen Gras 	}
169e83f7ba2SBen Gras 	return NULL;
170e83f7ba2SBen Gras }
171e83f7ba2SBen Gras 
172e83f7ba2SBen Gras static Search_Path **
_rtld_append_path(Search_Path ** head_p,Search_Path ** path_p,const char * execname,const char * bp,const char * ep)173e83f7ba2SBen Gras _rtld_append_path(Search_Path **head_p, Search_Path **path_p,
174e83f7ba2SBen Gras     const char *execname, const char *bp, const char *ep)
175e83f7ba2SBen Gras {
176e83f7ba2SBen Gras 	Search_Path *path;
177e83f7ba2SBen Gras 	char epath[MAXPATHLEN];
178e83f7ba2SBen Gras 	size_t len;
179e83f7ba2SBen Gras 
180e83f7ba2SBen Gras 	len = _rtld_expand_path(epath, sizeof(epath), execname, bp, ep);
181e83f7ba2SBen Gras 	if (len == 0)
182e83f7ba2SBen Gras 		return path_p;
183e83f7ba2SBen Gras 
184e83f7ba2SBen Gras 	if (_rtld_find_path(*head_p, bp, ep - bp) != NULL)
185e83f7ba2SBen Gras 		return path_p;
186e83f7ba2SBen Gras 
187e83f7ba2SBen Gras 	path = NEW(Search_Path);
188e83f7ba2SBen Gras 	path->sp_pathlen = len;
189e83f7ba2SBen Gras 	path->sp_path = exstrdup(epath, epath + len);
190e83f7ba2SBen Gras 	path->sp_next = (*path_p);
191e83f7ba2SBen Gras 	(*path_p) = path;
192e83f7ba2SBen Gras 	path_p = &path->sp_next;
193e83f7ba2SBen Gras 
194e83f7ba2SBen Gras 	dbg((" added path \"%s\"", path->sp_path));
195e83f7ba2SBen Gras 	return path_p;
196e83f7ba2SBen Gras }
197e83f7ba2SBen Gras 
198e83f7ba2SBen Gras void
_rtld_add_paths(const char * execname,Search_Path ** path_p,const char * pathstr)199e83f7ba2SBen Gras _rtld_add_paths(const char *execname, Search_Path **path_p, const char *pathstr)
200e83f7ba2SBen Gras {
201e83f7ba2SBen Gras 	Search_Path **head_p = path_p;
202e83f7ba2SBen Gras 
203e83f7ba2SBen Gras 	if (pathstr == NULL)
204e83f7ba2SBen Gras 		return;
205e83f7ba2SBen Gras 
206e83f7ba2SBen Gras 	if (pathstr[0] == ':') {
207e83f7ba2SBen Gras 		/*
208e83f7ba2SBen Gras 		 * Leading colon means append to current path
209e83f7ba2SBen Gras 		 */
210e83f7ba2SBen Gras 		while ((*path_p) != NULL)
211e83f7ba2SBen Gras 			path_p = &(*path_p)->sp_next;
212e83f7ba2SBen Gras 		pathstr++;
213e83f7ba2SBen Gras 	}
214e83f7ba2SBen Gras 
215e83f7ba2SBen Gras 	for (;;) {
216e83f7ba2SBen Gras 		const char *bp = pathstr;
217e83f7ba2SBen Gras 		const char *ep = strchr(bp, ':');
218e83f7ba2SBen Gras 		if (ep == NULL)
219e83f7ba2SBen Gras 			ep = &pathstr[strlen(pathstr)];
220e83f7ba2SBen Gras 
221e83f7ba2SBen Gras 		path_p = _rtld_append_path(head_p, path_p, execname, bp, ep);
222e83f7ba2SBen Gras 
223e83f7ba2SBen Gras 		if (ep[0] == '\0')
224e83f7ba2SBen Gras 			break;
225e83f7ba2SBen Gras 		pathstr = ep + 1;
226e83f7ba2SBen Gras 	}
227e83f7ba2SBen Gras }
228e83f7ba2SBen Gras 
229e83f7ba2SBen Gras /*
230e83f7ba2SBen Gras  * Process library mappings of the form:
231e83f7ba2SBen Gras  *	<library_name>	<machdep_variable> <value,...:library_name,...> ...
232e83f7ba2SBen Gras  */
233e83f7ba2SBen Gras static void
_rtld_process_mapping(Library_Xform ** lib_p,const char * bp,const char * ep)234e83f7ba2SBen Gras _rtld_process_mapping(Library_Xform **lib_p, const char *bp, const char *ep)
235e83f7ba2SBen Gras {
236e83f7ba2SBen Gras 	Library_Xform *hwptr = NULL;
237e83f7ba2SBen Gras 	const char *ptr, *key, *ekey, *lib, *elib, *l;
238e83f7ba2SBen Gras 	int i, j;
239e83f7ba2SBen Gras 
240e83f7ba2SBen Gras 	dbg((" processing mapping \"%.*s\"", (int)(ep - bp), bp));
241e83f7ba2SBen Gras 
242e83f7ba2SBen Gras 	if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp)
243e83f7ba2SBen Gras 		return;
244e83f7ba2SBen Gras 
245e83f7ba2SBen Gras 	dbg((" library \"%.*s\"", (int)(bp - ptr), ptr));
246e83f7ba2SBen Gras 
247e83f7ba2SBen Gras 	hwptr = xmalloc(sizeof(*hwptr));
248e83f7ba2SBen Gras 	memset(hwptr, 0, sizeof(*hwptr));
249e83f7ba2SBen Gras 	hwptr->name = exstrdup(ptr, bp);
250e83f7ba2SBen Gras 
251e83f7ba2SBen Gras 	bp++;
252e83f7ba2SBen Gras 
253e83f7ba2SBen Gras 	if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp) {
254e83f7ba2SBen Gras 		xwarnx("missing sysctl variable name");
255e83f7ba2SBen Gras 		goto cleanup;
256e83f7ba2SBen Gras 	}
257e83f7ba2SBen Gras 
258e83f7ba2SBen Gras 	dbg((" sysctl \"%.*s\"", (int)(bp - ptr), ptr));
259e83f7ba2SBen Gras 
260e83f7ba2SBen Gras 	hwptr->ctlname = exstrdup(ptr, bp);
261e83f7ba2SBen Gras 
262e83f7ba2SBen Gras 	for (i = 0; bp++, (ptr = getword(&bp, ep, WS)) != NULL;) {
263e83f7ba2SBen Gras 		dbg((" ptr = %.*s", (int)(bp - ptr), ptr));
264e83f7ba2SBen Gras 		if (ptr == bp)
265e83f7ba2SBen Gras 			continue;
266e83f7ba2SBen Gras 
267e83f7ba2SBen Gras 		if (i == RTLD_MAX_ENTRY) {
268e83f7ba2SBen Gras no_more:
269e83f7ba2SBen Gras 			xwarnx("maximum library entries exceeded `%s'",
270e83f7ba2SBen Gras 			    hwptr->name);
271e83f7ba2SBen Gras 			goto cleanup;
272e83f7ba2SBen Gras 		}
273e83f7ba2SBen Gras 		if ((key = getstr(&ptr, bp, ":")) == NULL) {
274e83f7ba2SBen Gras 			xwarnx("missing sysctl variable value for `%s'",
275e83f7ba2SBen Gras 			    hwptr->name);
276e83f7ba2SBen Gras 			goto cleanup;
277e83f7ba2SBen Gras 		}
278e83f7ba2SBen Gras 		ekey = ptr++;
279e83f7ba2SBen Gras 		if ((lib = getstr(&ptr, bp, ":")) == NULL) {
280e83f7ba2SBen Gras 			xwarnx("missing sysctl library list for `%s'",
281e83f7ba2SBen Gras 			    hwptr->name);
282e83f7ba2SBen Gras 			goto cleanup;
283e83f7ba2SBen Gras 		}
284e83f7ba2SBen Gras 		elib = ptr;		/* No need to advance */
285e83f7ba2SBen Gras 		for (j = 0; (l = getstr(&lib, elib, ",")) != NULL;
286e83f7ba2SBen Gras 		    j++, lib++) {
287e83f7ba2SBen Gras 			if (j == RTLD_MAX_LIBRARY) {
288e83f7ba2SBen Gras 				xwarnx("maximum library entries exceeded `%s'",
289e83f7ba2SBen Gras 				    hwptr->name);
290e83f7ba2SBen Gras 				goto cleanup;
291e83f7ba2SBen Gras 			}
292e83f7ba2SBen Gras 			dbg((" library \"%.*s\"", (int)(lib - l), l));
293e83f7ba2SBen Gras 			hwptr->entry[i].library[j] = exstrdup(l, lib);
294e83f7ba2SBen Gras 		}
295e83f7ba2SBen Gras 		if (j == 0) {
296e83f7ba2SBen Gras 			xwarnx("No library map entries for `%s/%.*s'",
297e83f7ba2SBen Gras 			    hwptr->name, (int)(bp - ptr), ptr);
298e83f7ba2SBen Gras 			goto cleanup;
299e83f7ba2SBen Gras 		}
300e83f7ba2SBen Gras 		j = i;
301e83f7ba2SBen Gras 		for (; (l = getstr(&key, ekey, ",")) != NULL; i++, key++) {
302e83f7ba2SBen Gras 			/*
303e83f7ba2SBen Gras 			 * Allow empty key (it is valid as string
304e83f7ba2SBen Gras 			 * value).  Thus, we loop at least once and
305e83f7ba2SBen Gras 			 * `i' is incremented.
306e83f7ba2SBen Gras 			 */
307e83f7ba2SBen Gras 
308e83f7ba2SBen Gras 			dbg((" key \"%.*s\"", (int)(key - l), l));
309e83f7ba2SBen Gras 			if (i == RTLD_MAX_ENTRY)
310e83f7ba2SBen Gras 				goto no_more;
311e83f7ba2SBen Gras 			if (i != j)
312e83f7ba2SBen Gras 				(void)memcpy(hwptr->entry[i].library,
313e83f7ba2SBen Gras 				    hwptr->entry[j].library,
314e83f7ba2SBen Gras 				    sizeof(hwptr->entry[j].library));
315e83f7ba2SBen Gras 			hwptr->entry[i].value = exstrdup(l, key);
316e83f7ba2SBen Gras 		}
317e83f7ba2SBen Gras 	}
318e83f7ba2SBen Gras 
319e83f7ba2SBen Gras 	if (i == 0) {
320e83f7ba2SBen Gras 		xwarnx("No library entries for `%s'", hwptr->name);
321e83f7ba2SBen Gras 		goto cleanup;
322e83f7ba2SBen Gras 	}
323e83f7ba2SBen Gras 
324e83f7ba2SBen Gras 	hwptr->next = *lib_p;
325e83f7ba2SBen Gras 	*lib_p = hwptr;
326e83f7ba2SBen Gras 
327e83f7ba2SBen Gras 	return;
328e83f7ba2SBen Gras 
329e83f7ba2SBen Gras cleanup:
330e83f7ba2SBen Gras 	if (hwptr->name)
331e83f7ba2SBen Gras 		xfree(hwptr->name);
332e83f7ba2SBen Gras 	xfree(hwptr);
333e83f7ba2SBen Gras }
334e83f7ba2SBen Gras 
335e83f7ba2SBen Gras void
_rtld_process_hints(const char * execname,Search_Path ** path_p,Library_Xform ** lib_p,const char * fname)336e83f7ba2SBen Gras _rtld_process_hints(const char *execname, Search_Path **path_p,
337e83f7ba2SBen Gras     Library_Xform **lib_p, const char *fname)
338e83f7ba2SBen Gras {
339e83f7ba2SBen Gras 	int fd;
340e83f7ba2SBen Gras 	char *buf, small[128];
341e83f7ba2SBen Gras 	const char *b, *ep, *ptr;
342e83f7ba2SBen Gras 	struct stat st;
343e83f7ba2SBen Gras 	ssize_t sz;
344e83f7ba2SBen Gras 	Search_Path **head_p = path_p;
345f14fb602SLionel Sambuc 
346e83f7ba2SBen Gras 	if ((fd = open(fname, O_RDONLY)) == -1) {
347e83f7ba2SBen Gras 		/* Don't complain */
348e83f7ba2SBen Gras 		return;
349e83f7ba2SBen Gras 	}
350e83f7ba2SBen Gras 
351e83f7ba2SBen Gras 	/* Try to avoid mmap/stat on the file. */
352e83f7ba2SBen Gras 	buf = small;
353e83f7ba2SBen Gras 	buf[0] = '\0';
354e83f7ba2SBen Gras 	sz = read(fd, buf, sizeof(small));
355e83f7ba2SBen Gras 	if (sz == -1) {
356e83f7ba2SBen Gras 		xwarn("read: %s", fname);
357e83f7ba2SBen Gras 		(void)close(fd);
358e83f7ba2SBen Gras 		return;
359e83f7ba2SBen Gras 	}
360e83f7ba2SBen Gras 	if (sz >= (ssize_t)sizeof(small)) {
361e83f7ba2SBen Gras 		if (fstat(fd, &st) == -1) {
362e83f7ba2SBen Gras 			/* Complain */
363e83f7ba2SBen Gras 			xwarn("fstat: %s", fname);
364e83f7ba2SBen Gras 			(void)close(fd);
365e83f7ba2SBen Gras 			return;
366e83f7ba2SBen Gras 		}
367e83f7ba2SBen Gras 
368e83f7ba2SBen Gras 		sz = (ssize_t) st.st_size;
369e83f7ba2SBen Gras 
370e83f7ba2SBen Gras 		buf = mmap(0, sz, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
371e83f7ba2SBen Gras 		if (buf == MAP_FAILED) {
372e83f7ba2SBen Gras 			xwarn("mmap: %s", fname);
373e83f7ba2SBen Gras 			(void)close(fd);
374e83f7ba2SBen Gras 			return;
375e83f7ba2SBen Gras 		}
376e83f7ba2SBen Gras 	}
377e83f7ba2SBen Gras 	(void)close(fd);
378e83f7ba2SBen Gras 
379e83f7ba2SBen Gras 	while ((*path_p) != NULL)
380e83f7ba2SBen Gras 		path_p = &(*path_p)->sp_next;
381e83f7ba2SBen Gras 
382e83f7ba2SBen Gras 	for (b = buf, ep = buf + sz; b < ep; b++) {
383e83f7ba2SBen Gras 		(void)getcstr(&b, ep, WS);
384e83f7ba2SBen Gras 		if (b == ep)
385e83f7ba2SBen Gras 			break;
386e83f7ba2SBen Gras 
387e83f7ba2SBen Gras 		ptr = getstr(&b, ep, "\n#");
388e83f7ba2SBen Gras 		if (*ptr == '/') {
389e83f7ba2SBen Gras 			/*
390e83f7ba2SBen Gras 			 * Since '/' != '\n' and != '#', we know ptr <
391e83f7ba2SBen Gras 			 * b.  And we will stop when b[-1] == '/'.
392e83f7ba2SBen Gras 			 */
393e83f7ba2SBen Gras 			while (b[-1] == ' ' || b[-1] == '\t')
394e83f7ba2SBen Gras 				b--;
395e83f7ba2SBen Gras 			path_p = _rtld_append_path(head_p, path_p, execname,
396e83f7ba2SBen Gras 			    ptr, b);
397e83f7ba2SBen Gras 		} else
398e83f7ba2SBen Gras 			_rtld_process_mapping(lib_p, ptr, b);
399e83f7ba2SBen Gras 
400e83f7ba2SBen Gras 		/*
401e83f7ba2SBen Gras 		 * b points one of ' ', \t, \n, # or equal to ep.  So,
402e83f7ba2SBen Gras 		 * make sure we are at newline or end of string.
403e83f7ba2SBen Gras 		 */
404e83f7ba2SBen Gras 		(void)getstr(&b, ep, "\n");
405e83f7ba2SBen Gras 	}
406e83f7ba2SBen Gras 
407e83f7ba2SBen Gras 	if (buf != small)
408e83f7ba2SBen Gras 		(void)munmap(buf, sz);
409e83f7ba2SBen Gras }
410e83f7ba2SBen Gras 
411e83f7ba2SBen Gras /* Basic name -> sysctl MIB translation */
412e83f7ba2SBen Gras int
_rtld_sysctl(const char * name,void * oldp,size_t * oldlen)413e83f7ba2SBen Gras _rtld_sysctl(const char *name, void *oldp, size_t *oldlen)
414e83f7ba2SBen Gras {
415e83f7ba2SBen Gras 	const char *node, *ep;
416e83f7ba2SBen Gras 	struct sysctlnode query, *result, *newresult;
417e83f7ba2SBen Gras 	int mib[CTL_MAXNAME], r;
418e83f7ba2SBen Gras 	size_t res_size, n, i;
419e83f7ba2SBen Gras 	u_int miblen = 0;
420e83f7ba2SBen Gras 
421e83f7ba2SBen Gras 	/* Start with 16 entries, will grow it up as needed. */
422e83f7ba2SBen Gras 	res_size = 16 * sizeof(struct sysctlnode);
423e83f7ba2SBen Gras 	result = xmalloc(res_size);
424e83f7ba2SBen Gras 	if (result == NULL)
425e83f7ba2SBen Gras 		return (-1);
426e83f7ba2SBen Gras 
427e83f7ba2SBen Gras 	ep = name + strlen(name);
428e83f7ba2SBen Gras 	do {
429e83f7ba2SBen Gras 		i = ~0ul;
430e83f7ba2SBen Gras 		while (*name == '/' || *name == '.')
431e83f7ba2SBen Gras 			name++;
432e83f7ba2SBen Gras 		if (name >= ep)
433e83f7ba2SBen Gras 			break;
434e83f7ba2SBen Gras 
435e83f7ba2SBen Gras 		mib[miblen] = CTL_QUERY;
436e83f7ba2SBen Gras 		memset(&query, 0, sizeof(query));
437e83f7ba2SBen Gras 		query.sysctl_flags = SYSCTL_VERSION;
438e83f7ba2SBen Gras 
439e83f7ba2SBen Gras 		n = res_size;
440e83f7ba2SBen Gras 		if (sysctl(mib, miblen + 1, result, &n, &query,
441e83f7ba2SBen Gras 		    sizeof(query)) == -1) {
442e83f7ba2SBen Gras 			if (errno != ENOMEM)
443e83f7ba2SBen Gras 				goto bad;
444e83f7ba2SBen Gras 			/* Grow up result */
445e83f7ba2SBen Gras 			res_size = n;
446e83f7ba2SBen Gras 			newresult = xrealloc(result, res_size);
447e83f7ba2SBen Gras 			if (newresult == NULL)
448e83f7ba2SBen Gras 				goto bad;
449e83f7ba2SBen Gras 			result = newresult;
450e83f7ba2SBen Gras 			if (sysctl(mib, miblen + 1, result, &n, &query,
451e83f7ba2SBen Gras 			    sizeof(query)) == -1)
452e83f7ba2SBen Gras 				goto bad;
453e83f7ba2SBen Gras 		}
454e83f7ba2SBen Gras 		n /= sizeof(struct sysctlnode);
455e83f7ba2SBen Gras 
456e83f7ba2SBen Gras 		node = getstr(&name, ep, "./");
457e83f7ba2SBen Gras 
458e83f7ba2SBen Gras 		for (i = 0; i < n; i++)
459e83f7ba2SBen Gras 			if (matchstr(result[i].sysctl_name, node, name)) {
460e83f7ba2SBen Gras 				mib[miblen] = result[i].sysctl_num;
461e83f7ba2SBen Gras 				miblen++;
462e83f7ba2SBen Gras 				break;
463e83f7ba2SBen Gras 			}
464e83f7ba2SBen Gras 	} while (name < ep && miblen <= CTL_MAXNAME);
465e83f7ba2SBen Gras 
466e83f7ba2SBen Gras 	if (name < ep || i == ~0ul)
467e83f7ba2SBen Gras 		goto bad;
468e83f7ba2SBen Gras 	r = SYSCTL_TYPE(result[i].sysctl_flags);
469e83f7ba2SBen Gras 
470e83f7ba2SBen Gras 	xfree(result);
471e83f7ba2SBen Gras 	if (sysctl(mib, miblen, oldp, oldlen, NULL, 0) == -1)
472e83f7ba2SBen Gras 		return (-1);
473e83f7ba2SBen Gras 	return r;
474e83f7ba2SBen Gras 
475e83f7ba2SBen Gras bad:
476e83f7ba2SBen Gras 	xfree(result);
477e83f7ba2SBen Gras 	return (-1);
478e83f7ba2SBen Gras }
479