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 *);
65 static void _rtld_process_mapping(Library_Xform
**, const char *,
67 #endif /* !defined(__minix) */
68 static char *exstrdup(const char *, const char *);
70 static const char *getstr(const char **, const char *, const char *);
71 static const char *getcstr(const char **, const char *, const char *);
72 static const char *getword(const char **, const char *, const char *);
73 static int matchstr(const char *, const char *, const char *);
74 #endif /* !defined(__minix) */
76 static const char WS
[] = " \t\n";
79 * Like xstrdup(), but takes end of string as a argument.
82 exstrdup(const char *bp
, const char *ep
)
87 cp
= xmalloc(len
+ 1);
95 * Like strsep(), but takes end of string and doesn't put any NUL. To
96 * detect empty string, compare `*p' and return value.
99 getstr(const char **p
, const char *ep
, const char *delim
)
101 const char *cp
= *p
, *q
, *r
;
107 for (q
= cp
; q
< ep
; q
++)
108 for (r
= delim
; *r
!= 0; r
++)
118 * Like getstr() above, but delim[] is complemented.
121 getcstr(const char **p
, const char *ep
, const char *delim
)
123 const char *cp
= *p
, *q
, *r
;
129 for (q
= cp
; q
< ep
; q
++)
130 for (r
= delim
; *r
!= *q
; r
++)
140 getword(const char **p
, const char *ep
, const char *delim
)
143 (void)getcstr(p
, ep
, delim
);
146 * Now, we're looking non-delim, or end of string.
149 return (getstr(p
, ep
, delim
));
153 * Match `bp' against NUL terminated string pointed by `p'.
156 matchstr(const char *p
, const char *bp
, const char *ep
)
161 if ((c
= *p
++) == 0 || c
!= *bp
++)
166 #endif /* !defined(__minix) */
169 _rtld_find_path(Search_Path
*path
, const char *pathstr
, size_t pathlen
)
172 for (; path
!= NULL
; path
= path
->sp_next
) {
173 if (pathlen
== path
->sp_pathlen
&&
174 memcmp(path
->sp_path
, pathstr
, pathlen
) == 0)
180 static Search_Path
**
181 _rtld_append_path(Search_Path
**head_p
, Search_Path
**path_p
,
182 const char *execname
, const char *bp
, const char *ep
)
185 char epath
[MAXPATHLEN
];
188 len
= _rtld_expand_path(epath
, sizeof(epath
), execname
, bp
, ep
);
192 if (_rtld_find_path(*head_p
, bp
, ep
- bp
) != NULL
)
195 path
= NEW(Search_Path
);
196 path
->sp_pathlen
= len
;
197 path
->sp_path
= exstrdup(epath
, epath
+ len
);
198 path
->sp_next
= (*path_p
);
200 path_p
= &path
->sp_next
;
202 dbg((" added path \"%s\"", path
->sp_path
));
207 _rtld_add_paths(const char *execname
, Search_Path
**path_p
, const char *pathstr
)
209 Search_Path
**head_p
= path_p
;
214 if (pathstr
[0] == ':') {
216 * Leading colon means append to current path
218 while ((*path_p
) != NULL
)
219 path_p
= &(*path_p
)->sp_next
;
224 const char *bp
= pathstr
;
225 const char *ep
= strchr(bp
, ':');
227 ep
= &pathstr
[strlen(pathstr
)];
229 path_p
= _rtld_append_path(head_p
, path_p
, execname
, bp
, ep
);
237 #if !defined(__minix)
239 * Process library mappings of the form:
240 * <library_name> <machdep_variable> <value,...:library_name,...> ...
243 _rtld_process_mapping(Library_Xform
**lib_p
, const char *bp
, const char *ep
)
245 Library_Xform
*hwptr
= NULL
;
246 const char *ptr
, *key
, *ekey
, *lib
, *elib
, *l
;
249 dbg((" processing mapping \"%.*s\"", (int)(ep
- bp
), bp
));
251 if ((ptr
= getword(&bp
, ep
, WS
)) == NULL
|| ptr
== bp
)
254 dbg((" library \"%.*s\"", (int)(bp
- ptr
), ptr
));
256 hwptr
= xmalloc(sizeof(*hwptr
));
257 memset(hwptr
, 0, sizeof(*hwptr
));
258 hwptr
->name
= exstrdup(ptr
, bp
);
262 if ((ptr
= getword(&bp
, ep
, WS
)) == NULL
|| ptr
== bp
) {
263 xwarnx("missing sysctl variable name");
267 dbg((" sysctl \"%.*s\"", (int)(bp
- ptr
), ptr
));
269 hwptr
->ctlname
= exstrdup(ptr
, bp
);
271 for (i
= 0; bp
++, (ptr
= getword(&bp
, ep
, WS
)) != NULL
;) {
272 dbg((" ptr = %.*s", (int)(bp
- ptr
), ptr
));
276 if (i
== RTLD_MAX_ENTRY
) {
278 xwarnx("maximum library entries exceeded `%s'",
282 if ((key
= getstr(&ptr
, bp
, ":")) == NULL
) {
283 xwarnx("missing sysctl variable value for `%s'",
288 if ((lib
= getstr(&ptr
, bp
, ":")) == NULL
) {
289 xwarnx("missing sysctl library list for `%s'",
293 elib
= ptr
; /* No need to advance */
294 for (j
= 0; (l
= getstr(&lib
, elib
, ",")) != NULL
;
296 if (j
== RTLD_MAX_LIBRARY
) {
297 xwarnx("maximum library entries exceeded `%s'",
301 dbg((" library \"%.*s\"", (int)(lib
- l
), l
));
302 hwptr
->entry
[i
].library
[j
] = exstrdup(l
, lib
);
305 xwarnx("No library map entries for `%s/%.*s'",
306 hwptr
->name
, (int)(bp
- ptr
), ptr
);
310 for (; (l
= getstr(&key
, ekey
, ",")) != NULL
; i
++, key
++) {
312 * Allow empty key (it is valid as string
313 * value). Thus, we loop at least once and
314 * `i' is incremented.
317 dbg((" key \"%.*s\"", (int)(key
- l
), l
));
318 if (i
== RTLD_MAX_ENTRY
)
321 (void)memcpy(hwptr
->entry
[i
].library
,
322 hwptr
->entry
[j
].library
,
323 sizeof(hwptr
->entry
[j
].library
));
324 hwptr
->entry
[i
].value
= exstrdup(l
, key
);
329 xwarnx("No library entries for `%s'", hwptr
->name
);
333 hwptr
->next
= *lib_p
;
343 #endif /* !defined(__minix) */
346 _rtld_process_hints(const char *execname
, Search_Path
**path_p
,
347 Library_Xform
**lib_p
, const char *fname
)
351 /* Minix doesn't support MAP_SHARED. */
355 char *buf
, small
[128];
356 const char *b
, *ep
, *ptr
;
359 Search_Path
**head_p
= path_p
;
361 if ((fd
= open(fname
, O_RDONLY
)) == -1) {
366 /* Try to avoid mmap/stat on the file. */
369 sz
= read(fd
, buf
, sizeof(small
));
371 xwarn("read: %s", fname
);
375 if (sz
>= (ssize_t
)sizeof(small
)) {
376 if (fstat(fd
, &st
) == -1) {
378 xwarn("fstat: %s", fname
);
383 sz
= (ssize_t
) st
.st_size
;
385 buf
= mmap(0, sz
, PROT_READ
, MAP_SHARED
|MAP_FILE
, fd
, 0);
386 if (buf
== MAP_FAILED
) {
387 xwarn("mmap: %s", fname
);
394 while ((*path_p
) != NULL
)
395 path_p
= &(*path_p
)->sp_next
;
397 for (b
= buf
, ep
= buf
+ sz
; b
< ep
; b
++) {
398 (void)getcstr(&b
, ep
, WS
);
402 ptr
= getstr(&b
, ep
, "\n#");
405 * Since '/' != '\n' and != '#', we know ptr <
406 * b. And we will stop when b[-1] == '/'.
408 while (b
[-1] == ' ' || b
[-1] == '\t')
410 path_p
= _rtld_append_path(head_p
, path_p
, execname
,
413 _rtld_process_mapping(lib_p
, ptr
, b
);
416 * b points one of ' ', \t, \n, # or equal to ep. So,
417 * make sure we are at newline or end of string.
419 (void)getstr(&b
, ep
, "\n");
423 (void)munmap(buf
, sz
);
428 /* Basic name -> sysctl MIB translation */
430 _rtld_sysctl(const char *name
, void *oldp
, size_t *oldlen
)
432 const char *node
, *ep
;
433 struct sysctlnode query
, *result
, *newresult
;
434 int mib
[CTL_MAXNAME
], r
;
435 size_t res_size
, n
, i
;
438 /* Start with 16 entries, will grow it up as needed. */
439 res_size
= 16 * sizeof(struct sysctlnode
);
440 result
= xmalloc(res_size
);
444 ep
= name
+ strlen(name
);
447 while (*name
== '/' || *name
== '.')
452 mib
[miblen
] = CTL_QUERY
;
453 memset(&query
, 0, sizeof(query
));
454 query
.sysctl_flags
= SYSCTL_VERSION
;
457 if (sysctl(mib
, miblen
+ 1, result
, &n
, &query
,
458 sizeof(query
)) == -1) {
463 newresult
= xrealloc(result
, res_size
);
464 if (newresult
== NULL
)
467 if (sysctl(mib
, miblen
+ 1, result
, &n
, &query
,
468 sizeof(query
)) == -1)
471 n
/= sizeof(struct sysctlnode
);
473 node
= getstr(&name
, ep
, "./");
475 for (i
= 0; i
< n
; i
++)
476 if (matchstr(result
[i
].sysctl_name
, node
, name
)) {
477 mib
[miblen
] = result
[i
].sysctl_num
;
481 } while (name
< ep
&& miblen
<= CTL_MAXNAME
);
483 if (name
< ep
|| i
== ~0ul)
485 r
= SYSCTL_TYPE(result
[i
].sysctl_flags
);
488 if (sysctl(mib
, miblen
, oldp
, oldlen
, NULL
, 0) == -1)