xref: /netbsd-src/libexec/ld.elf_so/paths.c (revision a21e6644478f427f359ffeb0672f3dc904c9fa4f)
1*a21e6644Schristos /*	$NetBSD: paths.c,v 1.42 2016/01/24 01:56:04 christos Exp $	 */
241fe218bScgd 
341fe218bScgd /*
441fe218bScgd  * Copyright 1996 Matt Thomas <matt@3am-software.com>
5ad8ccd62Smycroft  * Copyright 2002 Charles M. Hannum <root@ihack.net>
641fe218bScgd  * All rights reserved.
741fe218bScgd  *
841fe218bScgd  * Redistribution and use in source and binary forms, with or without
941fe218bScgd  * modification, are permitted provided that the following conditions
1041fe218bScgd  * are met:
1141fe218bScgd  * 1. Redistributions of source code must retain the above copyright
1241fe218bScgd  *    notice, this list of conditions and the following disclaimer.
1341fe218bScgd  * 2. Redistributions in binary form must reproduce the above copyright
1441fe218bScgd  *    notice, this list of conditions and the following disclaimer in the
1541fe218bScgd  *    documentation and/or other materials provided with the distribution.
1641fe218bScgd  * 3. The name of the author may not be used to endorse or promote products
1741fe218bScgd  *    derived from this software without specific prior written permission.
1841fe218bScgd  *
1941fe218bScgd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2041fe218bScgd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2141fe218bScgd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2241fe218bScgd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2341fe218bScgd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2441fe218bScgd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2541fe218bScgd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2641fe218bScgd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2741fe218bScgd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2841fe218bScgd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2941fe218bScgd  */
3041fe218bScgd 
312728318eSskrll #include <sys/cdefs.h>
322728318eSskrll #ifndef lint
33*a21e6644Schristos __RCSID("$NetBSD: paths.c,v 1.42 2016/01/24 01:56:04 christos Exp $");
342728318eSskrll #endif /* not lint */
3541fe218bScgd 
3641fe218bScgd #include <err.h>
3741fe218bScgd #include <errno.h>
3841fe218bScgd #include <fcntl.h>
3941fe218bScgd #include <stdarg.h>
4041fe218bScgd #include <stdio.h>
4141fe218bScgd #include <stdlib.h>
4241fe218bScgd #include <string.h>
4341fe218bScgd #include <unistd.h>
4441fe218bScgd #include <sys/types.h>
45ea816c78Schristos #include <sys/param.h>
46ea816c78Schristos #include <sys/sysctl.h>
4741fe218bScgd #include <sys/mman.h>
48fb292d7fSchristos #include <sys/stat.h>
49ea816c78Schristos #include <sys/gmon.h>
50ea816c78Schristos #include <sys/socket.h>
51ea816c78Schristos #include <sys/mount.h>
52ea816c78Schristos #include <sys/resource.h>
53ea816c78Schristos #include <machine/cpu.h>
5441fe218bScgd 
5541fe218bScgd #include "debug.h"
5641fe218bScgd #include "rtld.h"
5741fe218bScgd 
585f573ab6Sskrll static Search_Path *_rtld_find_path(Search_Path *, const char *, size_t);
595f573ab6Sskrll static Search_Path **_rtld_append_path(Search_Path **, Search_Path **,
6004ee85adSchristos     const char *, const char *, const char *);
61f1740378Senami static void _rtld_process_mapping(Library_Xform **, const char *,
62f1740378Senami     const char *);
63f1740378Senami static char *exstrdup(const char *, const char *);
64f1740378Senami static const char *getstr(const char **, const char *, const char *);
65f1740378Senami static const char *getcstr(const char **, const char *, const char *);
66f1740378Senami static const char *getword(const char **, const char *, const char *);
67f1740378Senami static int matchstr(const char *, const char *, const char *);
68f1740378Senami 
69f1740378Senami static const char WS[] = " \t\n";
70f1740378Senami 
71f1740378Senami /*
72f1740378Senami  * Like xstrdup(), but takes end of string as a argument.
73f1740378Senami  */
74f1740378Senami static char *
exstrdup(const char * bp,const char * ep)75f1740378Senami exstrdup(const char *bp, const char *ep)
76f1740378Senami {
77f1740378Senami 	char *cp;
78f1740378Senami 	size_t len = ep - bp;
79f1740378Senami 
80f1740378Senami 	cp = xmalloc(len + 1);
81f1740378Senami 	memcpy(cp, bp, len);
82f1740378Senami 	cp[len] = '\0';
83f1740378Senami 	return (cp);
84f1740378Senami }
85f1740378Senami 
86f1740378Senami /*
87f1740378Senami  * Like strsep(), but takes end of string and doesn't put any NUL.  To
88f1740378Senami  * detect empty string, compare `*p' and return value.
89f1740378Senami  */
90f1740378Senami static const char *
getstr(const char ** p,const char * ep,const char * delim)91f1740378Senami getstr(const char **p, const char *ep, const char *delim)
92f1740378Senami {
93f1740378Senami 	const char *cp = *p, *q, *r;
94f1740378Senami 
95f1740378Senami 	if (ep < cp)
96f1740378Senami 		/* End of string */
97f1740378Senami 		return (NULL);
98f1740378Senami 
99f1740378Senami 	for (q = cp; q < ep; q++)
100f1740378Senami 		for (r = delim; *r != 0; r++)
101f1740378Senami 			if (*r == *q)
102f1740378Senami 				goto done;
103f1740378Senami 
104f1740378Senami done:
105f1740378Senami 	*p = q;
106f1740378Senami 	return (cp);
107f1740378Senami }
108f1740378Senami 
109f1740378Senami /*
110f1740378Senami  * Like getstr() above, but delim[] is complemented.
111f1740378Senami  */
112f1740378Senami static const char *
getcstr(const char ** p,const char * ep,const char * delim)113f1740378Senami getcstr(const char **p, const char *ep, const char *delim)
114f1740378Senami {
115f1740378Senami 	const char *cp = *p, *q, *r;
116f1740378Senami 
117f1740378Senami 	if (ep < cp)
118f1740378Senami 		/* End of string */
119f1740378Senami 		return (NULL);
120f1740378Senami 
121f1740378Senami 	for (q = cp; q < ep; q++)
122f1740378Senami 		for (r = delim; *r != *q; r++)
123f1740378Senami 			if (*r == 0)
124f1740378Senami 				goto done;
125f1740378Senami 
126f1740378Senami done:
127f1740378Senami 	*p = q;
128f1740378Senami 	return (cp);
129f1740378Senami }
130f1740378Senami 
131f1740378Senami static const char *
getword(const char ** p,const char * ep,const char * delim)132f1740378Senami getword(const char **p, const char *ep, const char *delim)
133f1740378Senami {
134f1740378Senami 
135f1740378Senami 	(void)getcstr(p, ep, delim);
136f1740378Senami 
137f1740378Senami 	/*
138f1740378Senami 	 * Now, we're looking non-delim, or end of string.
139f1740378Senami 	 */
140f1740378Senami 
141f1740378Senami 	return (getstr(p, ep, delim));
142f1740378Senami }
143f1740378Senami 
144f1740378Senami /*
145f1740378Senami  * Match `bp' against NUL terminated string pointed by `p'.
146f1740378Senami  */
147f1740378Senami static int
matchstr(const char * p,const char * bp,const char * ep)148f1740378Senami matchstr(const char *p, const char *bp, const char *ep)
149f1740378Senami {
150f1740378Senami 	int c;
151f1740378Senami 
152f1740378Senami 	while (bp < ep)
153f1740378Senami 		if ((c = *p++) == 0 || c != *bp++)
154f1740378Senami 			return (0);
155f1740378Senami 
156f1740378Senami 	return (*p == 0);
157f1740378Senami }
158896c1cceSmrg 
15926475619Schristos static Search_Path *
_rtld_find_path(Search_Path * path,const char * pathstr,size_t pathlen)1605f573ab6Sskrll _rtld_find_path(Search_Path *path, const char *pathstr, size_t pathlen)
16141fe218bScgd {
162a9f5b3f8Ssimonb 
16341fe218bScgd 	for (; path != NULL; path = path->sp_next) {
16426475619Schristos 		if (pathlen == path->sp_pathlen &&
16526475619Schristos 		    memcmp(path->sp_path, pathstr, pathlen) == 0)
16641fe218bScgd 			return path;
16741fe218bScgd 	}
16841fe218bScgd 	return NULL;
16941fe218bScgd }
17041fe218bScgd 
171fb292d7fSchristos static Search_Path **
_rtld_append_path(Search_Path ** head_p,Search_Path ** path_p,const char * execname,const char * bp,const char * ep)1725f573ab6Sskrll _rtld_append_path(Search_Path **head_p, Search_Path **path_p,
17340cfdb5eSchristos     const char *execname, const char *bp, const char *ep)
17441fe218bScgd {
175fb292d7fSchristos 	Search_Path *path;
17604ee85adSchristos 	char epath[MAXPATHLEN];
17704ee85adSchristos 	size_t len;
17804ee85adSchristos 
17940cfdb5eSchristos 	len = _rtld_expand_path(epath, sizeof(epath), execname, bp, ep);
18040cfdb5eSchristos 	if (len == 0)
18104ee85adSchristos 		return path_p;
182fb292d7fSchristos 
183f1740378Senami 	if (_rtld_find_path(*head_p, bp, ep - bp) != NULL)
184fb292d7fSchristos 		return path_p;
18526475619Schristos 
186b615e155Sjunyoung 	path = NEW(Search_Path);
18704ee85adSchristos 	path->sp_pathlen = len;
18804ee85adSchristos 	path->sp_path = exstrdup(epath, epath + len);
18941fe218bScgd 	path->sp_next = (*path_p);
19041fe218bScgd 	(*path_p) = path;
19141fe218bScgd 	path_p = &path->sp_next;
19241fe218bScgd 
19326475619Schristos 	dbg((" added path \"%s\"", path->sp_path));
194fb292d7fSchristos 	return path_p;
19541fe218bScgd }
196fb292d7fSchristos 
197fb292d7fSchristos void
_rtld_add_paths(const char * execname,Search_Path ** path_p,const char * pathstr)19840cfdb5eSchristos _rtld_add_paths(const char *execname, Search_Path **path_p, const char *pathstr)
199fb292d7fSchristos {
200fb292d7fSchristos 	Search_Path **head_p = path_p;
201fb292d7fSchristos 
202fb292d7fSchristos 	if (pathstr == NULL)
203fb292d7fSchristos 		return;
204fb292d7fSchristos 
205fb292d7fSchristos 	if (pathstr[0] == ':') {
206fb292d7fSchristos 		/*
207fb292d7fSchristos 		 * Leading colon means append to current path
208fb292d7fSchristos 		 */
209fb292d7fSchristos 		while ((*path_p) != NULL)
210fb292d7fSchristos 			path_p = &(*path_p)->sp_next;
211fb292d7fSchristos 		pathstr++;
212fb292d7fSchristos 	}
213fb292d7fSchristos 
214fb292d7fSchristos 	for (;;) {
215fb292d7fSchristos 		const char *bp = pathstr;
216fb292d7fSchristos 		const char *ep = strchr(bp, ':');
217fb292d7fSchristos 		if (ep == NULL)
218fb292d7fSchristos 			ep = &pathstr[strlen(pathstr)];
219fb292d7fSchristos 
22040cfdb5eSchristos 		path_p = _rtld_append_path(head_p, path_p, execname, bp, ep);
221fb292d7fSchristos 
22241fe218bScgd 		if (ep[0] == '\0')
22341fe218bScgd 			break;
22441fe218bScgd 		pathstr = ep + 1;
22541fe218bScgd 	}
22641fe218bScgd }
227fb292d7fSchristos 
228ea816c78Schristos /*
229ea816c78Schristos  * Process library mappings of the form:
230ea816c78Schristos  *	<library_name>	<machdep_variable> <value,...:library_name,...> ...
231ea816c78Schristos  */
232ea816c78Schristos static void
_rtld_process_mapping(Library_Xform ** lib_p,const char * bp,const char * ep)233f1740378Senami _rtld_process_mapping(Library_Xform **lib_p, const char *bp, const char *ep)
234ea816c78Schristos {
235ea816c78Schristos 	Library_Xform *hwptr = NULL;
236f1740378Senami 	const char *ptr, *key, *ekey, *lib, *elib, *l;
237d1b3d841Scube 	int i, j;
238ea816c78Schristos 
239f1740378Senami 	dbg((" processing mapping \"%.*s\"", (int)(ep - bp), bp));
240ea816c78Schristos 
241f1740378Senami 	if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp)
242ea816c78Schristos 		return;
243ea816c78Schristos 
244f1740378Senami 	dbg((" library \"%.*s\"", (int)(bp - ptr), ptr));
245ea816c78Schristos 
246ea816c78Schristos 	hwptr = xmalloc(sizeof(*hwptr));
247ea816c78Schristos 	memset(hwptr, 0, sizeof(*hwptr));
248f1740378Senami 	hwptr->name = exstrdup(ptr, bp);
249ea816c78Schristos 
250f1740378Senami 	bp++;
251f1740378Senami 
252f1740378Senami 	if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp) {
2533bc3e6f7Schristos 		xwarnx("missing sysctl variable name");
254ea816c78Schristos 		goto cleanup;
255ea816c78Schristos 	}
256ea816c78Schristos 
257f1740378Senami 	dbg((" sysctl \"%.*s\"", (int)(bp - ptr), ptr));
258ea816c78Schristos 
259d1b3d841Scube 	hwptr->ctlname = exstrdup(ptr, bp);
260ea816c78Schristos 
261f1740378Senami 	for (i = 0; bp++, (ptr = getword(&bp, ep, WS)) != NULL;) {
262f1740378Senami 		dbg((" ptr = %.*s", (int)(bp - ptr), ptr));
263f1740378Senami 		if (ptr == bp)
264ae2c9c22Ssimonb 			continue;
265f1740378Senami 
266ea816c78Schristos 		if (i == RTLD_MAX_ENTRY) {
267ea816c78Schristos no_more:
2683bc3e6f7Schristos 			xwarnx("maximum library entries exceeded `%s'",
269ea816c78Schristos 			    hwptr->name);
270ea816c78Schristos 			goto cleanup;
271ea816c78Schristos 		}
272f1740378Senami 		if ((key = getstr(&ptr, bp, ":")) == NULL) {
2733bc3e6f7Schristos 			xwarnx("missing sysctl variable value for `%s'",
274ea816c78Schristos 			    hwptr->name);
275ea816c78Schristos 			goto cleanup;
276ea816c78Schristos 		}
277f1740378Senami 		ekey = ptr++;
278f1740378Senami 		if ((lib = getstr(&ptr, bp, ":")) == NULL) {
2793bc3e6f7Schristos 			xwarnx("missing sysctl library list for `%s'",
280ea816c78Schristos 			    hwptr->name);
281ea816c78Schristos 			goto cleanup;
282ea816c78Schristos 		}
283f1740378Senami 		elib = ptr;		/* No need to advance */
284f1740378Senami 		for (j = 0; (l = getstr(&lib, elib, ",")) != NULL;
285f1740378Senami 		    j++, lib++) {
286ea816c78Schristos 			if (j == RTLD_MAX_LIBRARY) {
2873bc3e6f7Schristos 				xwarnx("maximum library entries exceeded `%s'",
288ea816c78Schristos 				    hwptr->name);
289ea816c78Schristos 				goto cleanup;
290ea816c78Schristos 			}
291f1740378Senami 			dbg((" library \"%.*s\"", (int)(lib - l), l));
292f1740378Senami 			hwptr->entry[i].library[j] = exstrdup(l, lib);
293ea816c78Schristos 		}
294ea816c78Schristos 		if (j == 0) {
295f1740378Senami 			xwarnx("No library map entries for `%s/%.*s'",
296f1740378Senami 			    hwptr->name, (int)(bp - ptr), ptr);
297ea816c78Schristos 			goto cleanup;
298ea816c78Schristos 		}
299ea816c78Schristos 		j = i;
300f1740378Senami 		for (; (l = getstr(&key, ekey, ",")) != NULL; i++, key++) {
301f1740378Senami 			/*
302f1740378Senami 			 * Allow empty key (it is valid as string
303f1740378Senami 			 * value).  Thus, we loop at least once and
304f1740378Senami 			 * `i' is incremented.
305f1740378Senami 			 */
306f1740378Senami 
307f1740378Senami 			dbg((" key \"%.*s\"", (int)(key - l), l));
308ea816c78Schristos 			if (i == RTLD_MAX_ENTRY)
309ea816c78Schristos 				goto no_more;
310ea816c78Schristos 			if (i != j)
311ea816c78Schristos 				(void)memcpy(hwptr->entry[i].library,
312ea816c78Schristos 				    hwptr->entry[j].library,
313ea816c78Schristos 				    sizeof(hwptr->entry[j].library));
314f1740378Senami 			hwptr->entry[i].value = exstrdup(l, key);
315ea816c78Schristos 		}
316ea816c78Schristos 	}
317ea816c78Schristos 
318ea816c78Schristos 	if (i == 0) {
3193bc3e6f7Schristos 		xwarnx("No library entries for `%s'", hwptr->name);
320ea816c78Schristos 		goto cleanup;
321ea816c78Schristos 	}
322ea816c78Schristos 
323ae2c9c22Ssimonb 	hwptr->next = *lib_p;
324ea816c78Schristos 	*lib_p = hwptr;
325ea816c78Schristos 
326ea816c78Schristos 	return;
327ea816c78Schristos 
328ea816c78Schristos cleanup:
329ea816c78Schristos 	if (hwptr->name)
330bf4b000dSad 		xfree(hwptr->name);
331bf4b000dSad 	xfree(hwptr);
332ea816c78Schristos }
333ea816c78Schristos 
334fb292d7fSchristos void
_rtld_process_hints(const char * execname,Search_Path ** path_p,Library_Xform ** lib_p,const char * fname)33540cfdb5eSchristos _rtld_process_hints(const char *execname, Search_Path **path_p,
33604ee85adSchristos     Library_Xform **lib_p, const char *fname)
337fb292d7fSchristos {
338fb292d7fSchristos 	int fd;
33936b49f84Sad 	char *buf, small[128];
340f1740378Senami 	const char *b, *ep, *ptr;
341fb292d7fSchristos 	struct stat st;
342156176beSad 	ssize_t sz;
343fb292d7fSchristos 	Search_Path **head_p = path_p;
344fb292d7fSchristos 
345fb292d7fSchristos 	if ((fd = open(fname, O_RDONLY)) == -1) {
346fb292d7fSchristos 		/* Don't complain */
347fb292d7fSchristos 		return;
348fb292d7fSchristos 	}
349fb292d7fSchristos 
35036b49f84Sad 	/* Try to avoid mmap/stat on the file. */
35136b49f84Sad 	buf = small;
35236b49f84Sad 	buf[0] = '\0';
353156176beSad 	sz = read(fd, buf, sizeof(small));
354156176beSad 	if (sz == -1) {
35536b49f84Sad 		xwarn("read: %s", fname);
35636b49f84Sad 		(void)close(fd);
35736b49f84Sad 		return;
35836b49f84Sad 	}
359fa64a5bfSchristos 	if (sz >= (ssize_t)sizeof(small)) {
360156176beSad 		if (fstat(fd, &st) == -1) {
361156176beSad 			/* Complain */
362156176beSad 			xwarn("fstat: %s", fname);
363156176beSad 			(void)close(fd);
364156176beSad 			return;
365156176beSad 		}
366156176beSad 
367156176beSad 		sz = (ssize_t) st.st_size;
368156176beSad 
369f1740378Senami 		buf = mmap(0, sz, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
3702f37f423Schristos 		if (buf == MAP_FAILED) {
37163fcb5a0Senami 			xwarn("mmap: %s", fname);
372fb292d7fSchristos 			(void)close(fd);
373fb292d7fSchristos 			return;
374fb292d7fSchristos 		}
37536b49f84Sad 	}
376fb292d7fSchristos 	(void)close(fd);
377fb292d7fSchristos 
378fb292d7fSchristos 	while ((*path_p) != NULL)
379fb292d7fSchristos 		path_p = &(*path_p)->sp_next;
380fb292d7fSchristos 
381f1740378Senami 	for (b = buf, ep = buf + sz; b < ep; b++) {
382f1740378Senami 		(void)getcstr(&b, ep, WS);
383f1740378Senami 		if (b == ep)
384ea816c78Schristos 			break;
385ea816c78Schristos 
386f1740378Senami 		ptr = getstr(&b, ep, "\n#");
387f1740378Senami 		if (*ptr == '/') {
388f1740378Senami 			/*
389f1740378Senami 			 * Since '/' != '\n' and != '#', we know ptr <
390f1740378Senami 			 * b.  And we will stop when b[-1] == '/'.
391f1740378Senami 			 */
392f1740378Senami 			while (b[-1] == ' ' || b[-1] == '\t')
393f1740378Senami 				b--;
39440cfdb5eSchristos 			path_p = _rtld_append_path(head_p, path_p, execname,
39504ee85adSchristos 			    ptr, b);
396f1740378Senami 		} else
397f1740378Senami 			_rtld_process_mapping(lib_p, ptr, b);
3982e853452Sjunyoung 
399f1740378Senami 		/*
400f1740378Senami 		 * b points one of ' ', \t, \n, # or equal to ep.  So,
401f1740378Senami 		 * make sure we are at newline or end of string.
402f1740378Senami 		 */
403f1740378Senami 		(void)getstr(&b, ep, "\n");
40480b0665aSmycroft 	}
405fb292d7fSchristos 
40636b49f84Sad 	if (buf != small)
407fb292d7fSchristos 		(void)munmap(buf, sz);
408fb292d7fSchristos }
409d1b3d841Scube 
410d1b3d841Scube /* Basic name -> sysctl MIB translation */
411d1b3d841Scube int
_rtld_sysctl(const char * name,void * oldp,size_t * oldlen)412d1b3d841Scube _rtld_sysctl(const char *name, void *oldp, size_t *oldlen)
413d1b3d841Scube {
414d1b3d841Scube 	const char *node, *ep;
415d1b3d841Scube 	struct sysctlnode query, *result, *newresult;
416fa64a5bfSchristos 	int mib[CTL_MAXNAME], r;
417fa64a5bfSchristos 	size_t res_size, n, i;
418d1b3d841Scube 	u_int miblen = 0;
419d1b3d841Scube 
420d1b3d841Scube 	/* Start with 16 entries, will grow it up as needed. */
421d1b3d841Scube 	res_size = 16 * sizeof(struct sysctlnode);
422596c6ec5Schristos 	result = xmalloc(res_size);
423d1b3d841Scube 	if (result == NULL)
424d1b3d841Scube 		return (-1);
425d1b3d841Scube 
426d1b3d841Scube 	ep = name + strlen(name);
427d1b3d841Scube 	do {
428fa64a5bfSchristos 		i = ~0ul;
429d1b3d841Scube 		while (*name == '/' || *name == '.')
430d1b3d841Scube 			name++;
431d1b3d841Scube 		if (name >= ep)
432d1b3d841Scube 			break;
433d1b3d841Scube 
434d1b3d841Scube 		mib[miblen] = CTL_QUERY;
435d1b3d841Scube 		memset(&query, 0, sizeof(query));
436d1b3d841Scube 		query.sysctl_flags = SYSCTL_VERSION;
437d1b3d841Scube 
438d1b3d841Scube 		n = res_size;
439d1b3d841Scube 		if (sysctl(mib, miblen + 1, result, &n, &query,
440d1b3d841Scube 		    sizeof(query)) == -1) {
441d1b3d841Scube 			if (errno != ENOMEM)
442d1b3d841Scube 				goto bad;
443d1b3d841Scube 			/* Grow up result */
444d1b3d841Scube 			res_size = n;
445596c6ec5Schristos 			newresult = xrealloc(result, res_size);
446d1b3d841Scube 			if (newresult == NULL)
447d1b3d841Scube 				goto bad;
448d1b3d841Scube 			result = newresult;
449d1b3d841Scube 			if (sysctl(mib, miblen + 1, result, &n, &query,
450d1b3d841Scube 			    sizeof(query)) == -1)
451d1b3d841Scube 				goto bad;
452d1b3d841Scube 		}
453d1b3d841Scube 		n /= sizeof(struct sysctlnode);
454d1b3d841Scube 
455d1b3d841Scube 		node = getstr(&name, ep, "./");
456d1b3d841Scube 
457d1b3d841Scube 		for (i = 0; i < n; i++)
458d1b3d841Scube 			if (matchstr(result[i].sysctl_name, node, name)) {
459d1b3d841Scube 				mib[miblen] = result[i].sysctl_num;
460d1b3d841Scube 				miblen++;
461d1b3d841Scube 				break;
462d1b3d841Scube 			}
463d1b3d841Scube 	} while (name < ep && miblen <= CTL_MAXNAME);
464d1b3d841Scube 
465fa64a5bfSchristos 	if (name < ep || i == ~0ul)
466d1b3d841Scube 		goto bad;
467d1b3d841Scube 	r = SYSCTL_TYPE(result[i].sysctl_flags);
468d1b3d841Scube 
469bf4b000dSad 	xfree(result);
470d1b3d841Scube 	if (sysctl(mib, miblen, oldp, oldlen, NULL, 0) == -1)
471d1b3d841Scube 		return (-1);
472d1b3d841Scube 	return r;
473d1b3d841Scube 
474d1b3d841Scube bad:
475bf4b000dSad 	xfree(result);
476d1b3d841Scube 	return (-1);
477d1b3d841Scube }
478