1 /* $NetBSD: paths.c,v 1.39 2008/06/05 00:03:20 ad Exp $ */
4 * Copyright 1996 Matt Thomas <matt@3am-software.com>
5 * Copyright 2002 Charles M. Hannum <root@ihack.net>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: paths.c,v 1.39 2008/06/05 00:03:20 ad Exp $");
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/sysctl.h>
50 #include <sys/socket.h>
51 #include <sys/mount.h>
53 #include <sys/resource.h>
54 #include <machine/cpu.h>
59 static Search_Path
*_rtld_find_path(Search_Path
*, const char *, size_t);
60 static Search_Path
**_rtld_append_path(Search_Path
**, Search_Path
**,
61 const char *, const char *, const char *);
62 static void _rtld_process_mapping(Library_Xform
**, const char *,
64 static char *exstrdup(const char *, const char *);
65 static const char *getstr(const char **, const char *, const char *);
66 static const char *getcstr(const char **, const char *, const char *);
67 static const char *getword(const char **, const char *, const char *);
68 static int matchstr(const char *, const char *, const char *);
70 static const char WS
[] = " \t\n";
73 * Like xstrdup(), but takes end of string as a argument.
76 exstrdup(const char *bp
, const char *ep
)
81 cp
= xmalloc(len
+ 1);
88 * Like strsep(), but takes end of string and doesn't put any NUL. To
89 * detect empty string, compare `*p' and return value.
92 getstr(const char **p
, const char *ep
, const char *delim
)
94 const char *cp
= *p
, *q
, *r
;
100 for (q
= cp
; q
< ep
; q
++)
101 for (r
= delim
; *r
!= 0; r
++)
111 * Like getstr() above, but delim[] is complemented.
114 getcstr(const char **p
, const char *ep
, const char *delim
)
116 const char *cp
= *p
, *q
, *r
;
122 for (q
= cp
; q
< ep
; q
++)
123 for (r
= delim
; *r
!= *q
; r
++)
133 getword(const char **p
, const char *ep
, const char *delim
)
136 (void)getcstr(p
, ep
, delim
);
139 * Now, we're looking non-delim, or end of string.
142 return (getstr(p
, ep
, delim
));
146 * Match `bp' against NUL terminated string pointed by `p'.
149 matchstr(const char *p
, const char *bp
, const char *ep
)
154 if ((c
= *p
++) == 0 || c
!= *bp
++)
161 _rtld_find_path(Search_Path
*path
, const char *pathstr
, size_t pathlen
)
164 for (; path
!= NULL
; path
= path
->sp_next
) {
165 if (pathlen
== path
->sp_pathlen
&&
166 memcmp(path
->sp_path
, pathstr
, pathlen
) == 0)
172 static Search_Path
**
173 _rtld_append_path(Search_Path
**head_p
, Search_Path
**path_p
,
174 const char *execname
, const char *bp
, const char *ep
)
177 char epath
[MAXPATHLEN
];
180 len
= _rtld_expand_path(epath
, sizeof(epath
), execname
, bp
, ep
);
184 if (_rtld_find_path(*head_p
, bp
, ep
- bp
) != NULL
)
187 path
= NEW(Search_Path
);
188 path
->sp_pathlen
= len
;
189 path
->sp_path
= exstrdup(epath
, epath
+ len
);
190 path
->sp_next
= (*path_p
);
192 path_p
= &path
->sp_next
;
194 dbg((" added path \"%s\"", path
->sp_path
));
199 _rtld_add_paths(const char *execname
, Search_Path
**path_p
, const char *pathstr
)
201 Search_Path
**head_p
= path_p
;
206 if (pathstr
[0] == ':') {
208 * Leading colon means append to current path
210 while ((*path_p
) != NULL
)
211 path_p
= &(*path_p
)->sp_next
;
216 const char *bp
= pathstr
;
217 const char *ep
= strchr(bp
, ':');
219 ep
= &pathstr
[strlen(pathstr
)];
221 path_p
= _rtld_append_path(head_p
, path_p
, execname
, bp
, ep
);
230 * Process library mappings of the form:
231 * <library_name> <machdep_variable> <value,...:library_name,...> ...
234 _rtld_process_mapping(Library_Xform
**lib_p
, const char *bp
, const char *ep
)
236 Library_Xform
*hwptr
= NULL
;
237 const char *ptr
, *key
, *ekey
, *lib
, *elib
, *l
;
240 dbg((" processing mapping \"%.*s\"", (int)(ep
- bp
), bp
));
242 if ((ptr
= getword(&bp
, ep
, WS
)) == NULL
|| ptr
== bp
)
245 dbg((" library \"%.*s\"", (int)(bp
- ptr
), ptr
));
247 hwptr
= xmalloc(sizeof(*hwptr
));
248 memset(hwptr
, 0, sizeof(*hwptr
));
249 hwptr
->name
= exstrdup(ptr
, bp
);
253 if ((ptr
= getword(&bp
, ep
, WS
)) == NULL
|| ptr
== bp
) {
254 xwarnx("missing sysctl variable name");
258 dbg((" sysctl \"%.*s\"", (int)(bp
- ptr
), ptr
));
260 hwptr
->ctlname
= exstrdup(ptr
, bp
);
262 for (i
= 0; bp
++, (ptr
= getword(&bp
, ep
, WS
)) != NULL
;) {
263 dbg((" ptr = %.*s", (int)(bp
- ptr
), ptr
));
267 if (i
== RTLD_MAX_ENTRY
) {
269 xwarnx("maximum library entries exceeded `%s'",
273 if ((key
= getstr(&ptr
, bp
, ":")) == NULL
) {
274 xwarnx("missing sysctl variable value for `%s'",
279 if ((lib
= getstr(&ptr
, bp
, ":")) == NULL
) {
280 xwarnx("missing sysctl library list for `%s'",
284 elib
= ptr
; /* No need to advance */
285 for (j
= 0; (l
= getstr(&lib
, elib
, ",")) != NULL
;
287 if (j
== RTLD_MAX_LIBRARY
) {
288 xwarnx("maximum library entries exceeded `%s'",
292 dbg((" library \"%.*s\"", (int)(lib
- l
), l
));
293 hwptr
->entry
[i
].library
[j
] = exstrdup(l
, lib
);
296 xwarnx("No library map entries for `%s/%.*s'",
297 hwptr
->name
, (int)(bp
- ptr
), ptr
);
301 for (; (l
= getstr(&key
, ekey
, ",")) != NULL
; i
++, key
++) {
303 * Allow empty key (it is valid as string
304 * value). Thus, we loop at least once and
305 * `i' is incremented.
308 dbg((" key \"%.*s\"", (int)(key
- l
), l
));
309 if (i
== RTLD_MAX_ENTRY
)
312 (void)memcpy(hwptr
->entry
[i
].library
,
313 hwptr
->entry
[j
].library
,
314 sizeof(hwptr
->entry
[j
].library
));
315 hwptr
->entry
[i
].value
= exstrdup(l
, key
);
320 xwarnx("No library entries for `%s'", hwptr
->name
);
324 hwptr
->next
= *lib_p
;
336 _rtld_process_hints(const char *execname
, Search_Path
**path_p
,
337 Library_Xform
**lib_p
, const char *fname
)
340 char *buf
, small
[128];
341 const char *b
, *ep
, *ptr
;
344 Search_Path
**head_p
= path_p
;
346 if ((fd
= open(fname
, O_RDONLY
)) == -1) {
351 /* Try to avoid mmap/stat on the file. */
354 sz
= read(fd
, buf
, sizeof(small
));
356 xwarn("read: %s", fname
);
360 if (sz
>= (ssize_t
)sizeof(small
)) {
361 if (fstat(fd
, &st
) == -1) {
363 xwarn("fstat: %s", fname
);
368 sz
= (ssize_t
) st
.st_size
;
370 buf
= mmap(0, sz
, PROT_READ
, MAP_SHARED
|MAP_FILE
, fd
, 0);
371 if (buf
== MAP_FAILED
) {
372 xwarn("mmap: %s", fname
);
379 while ((*path_p
) != NULL
)
380 path_p
= &(*path_p
)->sp_next
;
382 for (b
= buf
, ep
= buf
+ sz
; b
< ep
; b
++) {
383 (void)getcstr(&b
, ep
, WS
);
387 ptr
= getstr(&b
, ep
, "\n#");
390 * Since '/' != '\n' and != '#', we know ptr <
391 * b. And we will stop when b[-1] == '/'.
393 while (b
[-1] == ' ' || b
[-1] == '\t')
395 path_p
= _rtld_append_path(head_p
, path_p
, execname
,
398 _rtld_process_mapping(lib_p
, ptr
, b
);
401 * b points one of ' ', \t, \n, # or equal to ep. So,
402 * make sure we are at newline or end of string.
404 (void)getstr(&b
, ep
, "\n");
408 (void)munmap(buf
, sz
);
411 /* Basic name -> sysctl MIB translation */
413 _rtld_sysctl(const char *name
, void *oldp
, size_t *oldlen
)
415 const char *node
, *ep
;
416 struct sysctlnode query
, *result
, *newresult
;
417 int mib
[CTL_MAXNAME
], r
;
418 size_t res_size
, n
, i
;
421 /* Start with 16 entries, will grow it up as needed. */
422 res_size
= 16 * sizeof(struct sysctlnode
);
423 result
= xmalloc(res_size
);
427 ep
= name
+ strlen(name
);
430 while (*name
== '/' || *name
== '.')
435 mib
[miblen
] = CTL_QUERY
;
436 memset(&query
, 0, sizeof(query
));
437 query
.sysctl_flags
= SYSCTL_VERSION
;
440 if (sysctl(mib
, miblen
+ 1, result
, &n
, &query
,
441 sizeof(query
)) == -1) {
446 newresult
= xrealloc(result
, res_size
);
447 if (newresult
== NULL
)
450 if (sysctl(mib
, miblen
+ 1, result
, &n
, &query
,
451 sizeof(query
)) == -1)
454 n
/= sizeof(struct sysctlnode
);
456 node
= getstr(&name
, ep
, "./");
458 for (i
= 0; i
< n
; i
++)
459 if (matchstr(result
[i
].sysctl_name
, node
, name
)) {
460 mib
[miblen
] = result
[i
].sysctl_num
;
464 } while (name
< ep
&& miblen
<= CTL_MAXNAME
);
466 if (name
< ep
|| i
== ~0ul)
468 r
= SYSCTL_TYPE(result
[i
].sysctl_flags
);
471 if (sysctl(mib
, miblen
, oldp
, oldlen
, NULL
, 0) == -1)