1 /* $NetBSD: paths.c,v 1.40 2009/05/19 20:44:52 christos 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.40 2009/05/19 20:44:52 christos 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>
55 #include <sys/resource.h>
56 #include <machine/cpu.h>
61 static Search_Path
*_rtld_find_path(Search_Path
*, const char *, size_t);
62 static Search_Path
**_rtld_append_path(Search_Path
**, Search_Path
**,
63 const char *, const char *, const char *);
64 static void _rtld_process_mapping(Library_Xform
**, const char *,
66 static char *exstrdup(const char *, const char *);
67 static const char *getstr(const char **, const char *, const char *);
68 static const char *getcstr(const char **, const char *, const char *);
69 static const char *getword(const char **, const char *, const char *);
70 static int matchstr(const char *, const char *, const char *);
72 static const char WS
[] = " \t\n";
75 * Like xstrdup(), but takes end of string as a argument.
78 exstrdup(const char *bp
, const char *ep
)
83 cp
= xmalloc(len
+ 1);
90 * Like strsep(), but takes end of string and doesn't put any NUL. To
91 * detect empty string, compare `*p' and return value.
94 getstr(const char **p
, const char *ep
, const char *delim
)
96 const char *cp
= *p
, *q
, *r
;
102 for (q
= cp
; q
< ep
; q
++)
103 for (r
= delim
; *r
!= 0; r
++)
113 * Like getstr() above, but delim[] is complemented.
116 getcstr(const char **p
, const char *ep
, const char *delim
)
118 const char *cp
= *p
, *q
, *r
;
124 for (q
= cp
; q
< ep
; q
++)
125 for (r
= delim
; *r
!= *q
; r
++)
135 getword(const char **p
, const char *ep
, const char *delim
)
138 (void)getcstr(p
, ep
, delim
);
141 * Now, we're looking non-delim, or end of string.
144 return (getstr(p
, ep
, delim
));
148 * Match `bp' against NUL terminated string pointed by `p'.
151 matchstr(const char *p
, const char *bp
, const char *ep
)
156 if ((c
= *p
++) == 0 || c
!= *bp
++)
163 _rtld_find_path(Search_Path
*path
, const char *pathstr
, size_t pathlen
)
166 for (; path
!= NULL
; path
= path
->sp_next
) {
167 if (pathlen
== path
->sp_pathlen
&&
168 memcmp(path
->sp_path
, pathstr
, pathlen
) == 0)
174 static Search_Path
**
175 _rtld_append_path(Search_Path
**head_p
, Search_Path
**path_p
,
176 const char *execname
, const char *bp
, const char *ep
)
179 char epath
[MAXPATHLEN
];
182 len
= _rtld_expand_path(epath
, sizeof(epath
), execname
, bp
, ep
);
186 if (_rtld_find_path(*head_p
, bp
, ep
- bp
) != NULL
)
189 path
= NEW(Search_Path
);
190 path
->sp_pathlen
= len
;
191 path
->sp_path
= exstrdup(epath
, epath
+ len
);
192 path
->sp_next
= (*path_p
);
194 path_p
= &path
->sp_next
;
196 dbg((" added path \"%s\"", path
->sp_path
));
201 _rtld_add_paths(const char *execname
, Search_Path
**path_p
, const char *pathstr
)
203 Search_Path
**head_p
= path_p
;
208 if (pathstr
[0] == ':') {
210 * Leading colon means append to current path
212 while ((*path_p
) != NULL
)
213 path_p
= &(*path_p
)->sp_next
;
218 const char *bp
= pathstr
;
219 const char *ep
= strchr(bp
, ':');
221 ep
= &pathstr
[strlen(pathstr
)];
223 path_p
= _rtld_append_path(head_p
, path_p
, execname
, bp
, ep
);
232 * Process library mappings of the form:
233 * <library_name> <machdep_variable> <value,...:library_name,...> ...
236 _rtld_process_mapping(Library_Xform
**lib_p
, const char *bp
, const char *ep
)
238 Library_Xform
*hwptr
= NULL
;
239 const char *ptr
, *key
, *ekey
, *lib
, *elib
, *l
;
242 dbg((" processing mapping \"%.*s\"", (int)(ep
- bp
), bp
));
244 if ((ptr
= getword(&bp
, ep
, WS
)) == NULL
|| ptr
== bp
)
247 dbg((" library \"%.*s\"", (int)(bp
- ptr
), ptr
));
249 hwptr
= xmalloc(sizeof(*hwptr
));
250 memset(hwptr
, 0, sizeof(*hwptr
));
251 hwptr
->name
= exstrdup(ptr
, bp
);
255 if ((ptr
= getword(&bp
, ep
, WS
)) == NULL
|| ptr
== bp
) {
256 xwarnx("missing sysctl variable name");
260 dbg((" sysctl \"%.*s\"", (int)(bp
- ptr
), ptr
));
262 hwptr
->ctlname
= exstrdup(ptr
, bp
);
264 for (i
= 0; bp
++, (ptr
= getword(&bp
, ep
, WS
)) != NULL
;) {
265 dbg((" ptr = %.*s", (int)(bp
- ptr
), ptr
));
269 if (i
== RTLD_MAX_ENTRY
) {
271 xwarnx("maximum library entries exceeded `%s'",
275 if ((key
= getstr(&ptr
, bp
, ":")) == NULL
) {
276 xwarnx("missing sysctl variable value for `%s'",
281 if ((lib
= getstr(&ptr
, bp
, ":")) == NULL
) {
282 xwarnx("missing sysctl library list for `%s'",
286 elib
= ptr
; /* No need to advance */
287 for (j
= 0; (l
= getstr(&lib
, elib
, ",")) != NULL
;
289 if (j
== RTLD_MAX_LIBRARY
) {
290 xwarnx("maximum library entries exceeded `%s'",
294 dbg((" library \"%.*s\"", (int)(lib
- l
), l
));
295 hwptr
->entry
[i
].library
[j
] = exstrdup(l
, lib
);
298 xwarnx("No library map entries for `%s/%.*s'",
299 hwptr
->name
, (int)(bp
- ptr
), ptr
);
303 for (; (l
= getstr(&key
, ekey
, ",")) != NULL
; i
++, key
++) {
305 * Allow empty key (it is valid as string
306 * value). Thus, we loop at least once and
307 * `i' is incremented.
310 dbg((" key \"%.*s\"", (int)(key
- l
), l
));
311 if (i
== RTLD_MAX_ENTRY
)
314 (void)memcpy(hwptr
->entry
[i
].library
,
315 hwptr
->entry
[j
].library
,
316 sizeof(hwptr
->entry
[j
].library
));
317 hwptr
->entry
[i
].value
= exstrdup(l
, key
);
322 xwarnx("No library entries for `%s'", hwptr
->name
);
326 hwptr
->next
= *lib_p
;
338 _rtld_process_hints(const char *execname
, Search_Path
**path_p
,
339 Library_Xform
**lib_p
, const char *fname
)
343 /* Minix doesn't support MAP_SHARED. */
347 char *buf
, small
[128];
348 const char *b
, *ep
, *ptr
;
351 Search_Path
**head_p
= path_p
;
352 if ((fd
= open(fname
, O_RDONLY
)) == -1) {
357 /* Try to avoid mmap/stat on the file. */
360 sz
= read(fd
, buf
, sizeof(small
));
362 xwarn("read: %s", fname
);
366 if (sz
>= (ssize_t
)sizeof(small
)) {
367 if (fstat(fd
, &st
) == -1) {
369 xwarn("fstat: %s", fname
);
374 sz
= (ssize_t
) st
.st_size
;
376 buf
= mmap(0, sz
, PROT_READ
, MAP_SHARED
|MAP_FILE
, fd
, 0);
377 if (buf
== MAP_FAILED
) {
378 xwarn("mmap: %s", fname
);
385 while ((*path_p
) != NULL
)
386 path_p
= &(*path_p
)->sp_next
;
388 for (b
= buf
, ep
= buf
+ sz
; b
< ep
; b
++) {
389 (void)getcstr(&b
, ep
, WS
);
393 ptr
= getstr(&b
, ep
, "\n#");
396 * Since '/' != '\n' and != '#', we know ptr <
397 * b. And we will stop when b[-1] == '/'.
399 while (b
[-1] == ' ' || b
[-1] == '\t')
401 path_p
= _rtld_append_path(head_p
, path_p
, execname
,
404 _rtld_process_mapping(lib_p
, ptr
, b
);
407 * b points one of ' ', \t, \n, # or equal to ep. So,
408 * make sure we are at newline or end of string.
410 (void)getstr(&b
, ep
, "\n");
414 (void)munmap(buf
, sz
);
419 /* Basic name -> sysctl MIB translation */
421 _rtld_sysctl(const char *name
, void *oldp
, size_t *oldlen
)
423 const char *node
, *ep
;
424 struct sysctlnode query
, *result
, *newresult
;
425 int mib
[CTL_MAXNAME
], r
;
426 size_t res_size
, n
, i
;
429 /* Start with 16 entries, will grow it up as needed. */
430 res_size
= 16 * sizeof(struct sysctlnode
);
431 result
= xmalloc(res_size
);
435 ep
= name
+ strlen(name
);
438 while (*name
== '/' || *name
== '.')
443 mib
[miblen
] = CTL_QUERY
;
444 memset(&query
, 0, sizeof(query
));
445 query
.sysctl_flags
= SYSCTL_VERSION
;
448 if (sysctl(mib
, miblen
+ 1, result
, &n
, &query
,
449 sizeof(query
)) == -1) {
454 newresult
= xrealloc(result
, res_size
);
455 if (newresult
== NULL
)
458 if (sysctl(mib
, miblen
+ 1, result
, &n
, &query
,
459 sizeof(query
)) == -1)
462 n
/= sizeof(struct sysctlnode
);
464 node
= getstr(&name
, ep
, "./");
466 for (i
= 0; i
< n
; i
++)
467 if (matchstr(result
[i
].sysctl_name
, node
, name
)) {
468 mib
[miblen
] = result
[i
].sysctl_num
;
472 } while (name
< ep
&& miblen
<= CTL_MAXNAME
);
474 if (name
< ep
|| i
== ~0ul)
476 r
= SYSCTL_TYPE(result
[i
].sysctl_flags
);
479 if (sysctl(mib
, miblen
, oldp
, oldlen
, NULL
, 0) == -1)