ldivmod, uldivmod: fix qdivrem calls
[minix.git] / libexec / ld.elf_so / paths.c
blob799e2983f4c0beff6eb12e6ebb8768ff44be94d5
1 /* $NetBSD: paths.c,v 1.40 2009/05/19 20:44:52 christos Exp $ */
3 /*
4 * Copyright 1996 Matt Thomas <matt@3am-software.com>
5 * Copyright 2002 Charles M. Hannum <root@ihack.net>
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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>
32 #ifndef lint
33 __RCSID("$NetBSD: paths.c,v 1.40 2009/05/19 20:44:52 christos Exp $");
34 #endif /* not lint */
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/sysctl.h>
47 #include <sys/mman.h>
48 #include <sys/stat.h>
49 #include <sys/gmon.h>
50 #include <sys/socket.h>
51 #include <sys/mount.h>
52 #ifndef __minix
53 #include <sys/mbuf.h>
54 #endif
55 #include <sys/resource.h>
56 #include <machine/cpu.h>
58 #include "debug.h"
59 #include "rtld.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 #if !defined(__minix)
65 static void _rtld_process_mapping(Library_Xform **, const char *,
66 const char *);
67 #endif /* !defined(__minix) */
68 static char *exstrdup(const char *, const char *);
69 #if !defined(__minix)
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.
81 static char *
82 exstrdup(const char *bp, const char *ep)
84 char *cp;
85 size_t len = ep - bp;
87 cp = xmalloc(len + 1);
88 memcpy(cp, bp, len);
89 cp[len] = '\0';
90 return (cp);
93 #if !defined(__minix)
95 * Like strsep(), but takes end of string and doesn't put any NUL. To
96 * detect empty string, compare `*p' and return value.
98 static const char *
99 getstr(const char **p, const char *ep, const char *delim)
101 const char *cp = *p, *q, *r;
103 if (ep < cp)
104 /* End of string */
105 return (NULL);
107 for (q = cp; q < ep; q++)
108 for (r = delim; *r != 0; r++)
109 if (*r == *q)
110 goto done;
112 done:
113 *p = q;
114 return (cp);
118 * Like getstr() above, but delim[] is complemented.
120 static const char *
121 getcstr(const char **p, const char *ep, const char *delim)
123 const char *cp = *p, *q, *r;
125 if (ep < cp)
126 /* End of string */
127 return (NULL);
129 for (q = cp; q < ep; q++)
130 for (r = delim; *r != *q; r++)
131 if (*r == 0)
132 goto done;
134 done:
135 *p = q;
136 return (cp);
139 static const char *
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'.
155 static int
156 matchstr(const char *p, const char *bp, const char *ep)
158 int c;
160 while (bp < ep)
161 if ((c = *p++) == 0 || c != *bp++)
162 return (0);
164 return (*p == 0);
166 #endif /* !defined(__minix) */
168 static Search_Path *
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)
175 return path;
177 return NULL;
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)
184 Search_Path *path;
185 char epath[MAXPATHLEN];
186 size_t len;
188 len = _rtld_expand_path(epath, sizeof(epath), execname, bp, ep);
189 if (len == 0)
190 return path_p;
192 if (_rtld_find_path(*head_p, bp, ep - bp) != NULL)
193 return path_p;
195 path = NEW(Search_Path);
196 path->sp_pathlen = len;
197 path->sp_path = exstrdup(epath, epath + len);
198 path->sp_next = (*path_p);
199 (*path_p) = path;
200 path_p = &path->sp_next;
202 dbg((" added path \"%s\"", path->sp_path));
203 return path_p;
206 void
207 _rtld_add_paths(const char *execname, Search_Path **path_p, const char *pathstr)
209 Search_Path **head_p = path_p;
211 if (pathstr == NULL)
212 return;
214 if (pathstr[0] == ':') {
216 * Leading colon means append to current path
218 while ((*path_p) != NULL)
219 path_p = &(*path_p)->sp_next;
220 pathstr++;
223 for (;;) {
224 const char *bp = pathstr;
225 const char *ep = strchr(bp, ':');
226 if (ep == NULL)
227 ep = &pathstr[strlen(pathstr)];
229 path_p = _rtld_append_path(head_p, path_p, execname, bp, ep);
231 if (ep[0] == '\0')
232 break;
233 pathstr = ep + 1;
237 #if !defined(__minix)
239 * Process library mappings of the form:
240 * <library_name> <machdep_variable> <value,...:library_name,...> ...
242 static void
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;
247 int i, j;
249 dbg((" processing mapping \"%.*s\"", (int)(ep - bp), bp));
251 if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp)
252 return;
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);
260 bp++;
262 if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp) {
263 xwarnx("missing sysctl variable name");
264 goto cleanup;
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));
273 if (ptr == bp)
274 continue;
276 if (i == RTLD_MAX_ENTRY) {
277 no_more:
278 xwarnx("maximum library entries exceeded `%s'",
279 hwptr->name);
280 goto cleanup;
282 if ((key = getstr(&ptr, bp, ":")) == NULL) {
283 xwarnx("missing sysctl variable value for `%s'",
284 hwptr->name);
285 goto cleanup;
287 ekey = ptr++;
288 if ((lib = getstr(&ptr, bp, ":")) == NULL) {
289 xwarnx("missing sysctl library list for `%s'",
290 hwptr->name);
291 goto cleanup;
293 elib = ptr; /* No need to advance */
294 for (j = 0; (l = getstr(&lib, elib, ",")) != NULL;
295 j++, lib++) {
296 if (j == RTLD_MAX_LIBRARY) {
297 xwarnx("maximum library entries exceeded `%s'",
298 hwptr->name);
299 goto cleanup;
301 dbg((" library \"%.*s\"", (int)(lib - l), l));
302 hwptr->entry[i].library[j] = exstrdup(l, lib);
304 if (j == 0) {
305 xwarnx("No library map entries for `%s/%.*s'",
306 hwptr->name, (int)(bp - ptr), ptr);
307 goto cleanup;
309 j = i;
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)
319 goto no_more;
320 if (i != j)
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);
328 if (i == 0) {
329 xwarnx("No library entries for `%s'", hwptr->name);
330 goto cleanup;
333 hwptr->next = *lib_p;
334 *lib_p = hwptr;
336 return;
338 cleanup:
339 if (hwptr->name)
340 xfree(hwptr->name);
341 xfree(hwptr);
343 #endif /* !defined(__minix) */
345 void
346 _rtld_process_hints(const char *execname, Search_Path **path_p,
347 Library_Xform **lib_p, const char *fname)
350 #ifdef __minix
351 /* Minix doesn't support MAP_SHARED. */
352 return;
353 #else
354 int fd;
355 char *buf, small[128];
356 const char *b, *ep, *ptr;
357 struct stat st;
358 ssize_t sz;
359 Search_Path **head_p = path_p;
361 if ((fd = open(fname, O_RDONLY)) == -1) {
362 /* Don't complain */
363 return;
366 /* Try to avoid mmap/stat on the file. */
367 buf = small;
368 buf[0] = '\0';
369 sz = read(fd, buf, sizeof(small));
370 if (sz == -1) {
371 xwarn("read: %s", fname);
372 (void)close(fd);
373 return;
375 if (sz >= (ssize_t)sizeof(small)) {
376 if (fstat(fd, &st) == -1) {
377 /* Complain */
378 xwarn("fstat: %s", fname);
379 (void)close(fd);
380 return;
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);
388 (void)close(fd);
389 return;
392 (void)close(fd);
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);
399 if (b == ep)
400 break;
402 ptr = getstr(&b, ep, "\n#");
403 if (*ptr == '/') {
405 * Since '/' != '\n' and != '#', we know ptr <
406 * b. And we will stop when b[-1] == '/'.
408 while (b[-1] == ' ' || b[-1] == '\t')
409 b--;
410 path_p = _rtld_append_path(head_p, path_p, execname,
411 ptr, b);
412 } else
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");
422 if (buf != small)
423 (void)munmap(buf, sz);
424 #endif
427 #ifndef __minix
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;
436 u_int miblen = 0;
438 /* Start with 16 entries, will grow it up as needed. */
439 res_size = 16 * sizeof(struct sysctlnode);
440 result = xmalloc(res_size);
441 if (result == NULL)
442 return (-1);
444 ep = name + strlen(name);
445 do {
446 i = ~0ul;
447 while (*name == '/' || *name == '.')
448 name++;
449 if (name >= ep)
450 break;
452 mib[miblen] = CTL_QUERY;
453 memset(&query, 0, sizeof(query));
454 query.sysctl_flags = SYSCTL_VERSION;
456 n = res_size;
457 if (sysctl(mib, miblen + 1, result, &n, &query,
458 sizeof(query)) == -1) {
459 if (errno != ENOMEM)
460 goto bad;
461 /* Grow up result */
462 res_size = n;
463 newresult = xrealloc(result, res_size);
464 if (newresult == NULL)
465 goto bad;
466 result = newresult;
467 if (sysctl(mib, miblen + 1, result, &n, &query,
468 sizeof(query)) == -1)
469 goto bad;
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;
478 miblen++;
479 break;
481 } while (name < ep && miblen <= CTL_MAXNAME);
483 if (name < ep || i == ~0ul)
484 goto bad;
485 r = SYSCTL_TYPE(result[i].sysctl_flags);
487 xfree(result);
488 if (sysctl(mib, miblen, oldp, oldlen, NULL, 0) == -1)
489 return (-1);
490 return r;
492 bad:
493 xfree(result);
494 return (-1);
496 #endif