xref: /netbsd-src/libexec/ld.elf_so/paths.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: paths.c,v 1.26 2003/06/05 10:41:32 simonb Exp $	 */
2 
3 /*
4  * Copyright 1996 Matt Thomas <matt@3am-software.com>
5  * Copyright 2002 Charles M. Hannum <root@ihack.net>
6  * All rights reserved.
7  *
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.
18  *
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.
29  */
30 
31 
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/sysctl.h>
43 #include <sys/mman.h>
44 #include <sys/stat.h>
45 #include <sys/gmon.h>
46 #include <sys/socket.h>
47 #include <sys/mount.h>
48 #include <sys/mbuf.h>
49 #include <sys/resource.h>
50 #include <machine/cpu.h>
51 
52 #include "debug.h"
53 #include "rtld.h"
54 
55 static Search_Path *_rtld_find_path __P((Search_Path *, const char *, size_t));
56 static Search_Path **_rtld_append_path __P((Search_Path **, Search_Path **,
57     const char *, size_t));
58 static void _rtld_process_mapping __P((Library_Xform **, char *, size_t));
59 
60 static Search_Path *
61 _rtld_find_path(path, pathstr, pathlen)
62 	Search_Path *path;
63 	const char *pathstr;
64 	size_t pathlen;
65 {
66 
67 	for (; path != NULL; path = path->sp_next) {
68 		if (pathlen == path->sp_pathlen &&
69 		    memcmp(path->sp_path, pathstr, pathlen) == 0)
70 			return path;
71 	}
72 	return NULL;
73 }
74 
75 static Search_Path **
76 _rtld_append_path(head_p, path_p, bp, len)
77 	Search_Path **head_p, **path_p;
78 	const char *bp;
79 	size_t len;
80 {
81 	char *cp;
82 	Search_Path *path;
83 
84 	if (_rtld_find_path(*head_p, bp, len) != NULL)
85 		return path_p;
86 
87 	path = NEW(Search_Path);
88 	path->sp_pathlen = len;
89 	cp = xmalloc(len + 1);
90 	memcpy(cp, bp, len);
91 	cp[len] = '\0';
92 	path->sp_path = cp;
93 	path->sp_next = (*path_p);
94 	(*path_p) = path;
95 	path_p = &path->sp_next;
96 
97 	dbg((" added path \"%s\"", path->sp_path));
98 	return path_p;
99 }
100 
101 void
102 _rtld_add_paths(path_p, pathstr)
103 	Search_Path **path_p;
104 	const char *pathstr;
105 {
106 	Search_Path **head_p = path_p;
107 
108 	if (pathstr == NULL)
109 		return;
110 
111 	if (pathstr[0] == ':') {
112 		/*
113 		 * Leading colon means append to current path
114 		 */
115 		while ((*path_p) != NULL)
116 			path_p = &(*path_p)->sp_next;
117 		pathstr++;
118 	}
119 
120 	for (;;) {
121 		const char *bp = pathstr;
122 		const char *ep = strchr(bp, ':');
123 		if (ep == NULL)
124 			ep = &pathstr[strlen(pathstr)];
125 
126 		path_p = _rtld_append_path(head_p, path_p, bp, ep - bp);
127 
128 		if (ep[0] == '\0')
129 			break;
130 		pathstr = ep + 1;
131 	}
132 }
133 
134 
135 struct sysctldesc {
136 	const char *name;
137 	int type;
138 };
139 
140 struct list {
141 	const struct sysctldesc *ctl;
142 	int numentries;
143 };
144 
145 #ifdef CTL_MACHDEP_NAMES
146 static const struct sysctldesc ctl_machdep[] = CTL_MACHDEP_NAMES;
147 #endif
148 static const struct sysctldesc ctl_toplvl[] = CTL_NAMES;
149 
150 const struct list toplevel[] = {
151 	{ 0, 0 },
152 	{ ctl_toplvl, CTL_MAXID },
153 	{ 0, -1 },
154 };
155 
156 const struct list secondlevel[] = {
157 	{ 0, 0 },			/* CTL_UNSPEC */
158 	{ 0, KERN_MAXID },		/* CTL_KERN */
159 	{ 0, VM_MAXID },		/* CTL_VM */
160 	{ 0, VFS_MAXID },		/* CTL_VFS */
161 	{ 0, NET_MAXID },		/* CTL_NET */
162 	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
163 	{ 0, HW_MAXID },		/* CTL_HW */
164 #ifdef CTL_MACHDEP_NAMES
165 	{ ctl_machdep, CPU_MAXID },	/* CTL_MACHDEP */
166 #else
167 	{ 0, 0 },			/* CTL_MACHDEP */
168 #endif
169 	{ 0, USER_MAXID },		/* CTL_USER_NAMES */
170 	{ 0, DDBCTL_MAXID },		/* CTL_DDB_NAMES */
171 	{ 0, 2 },			/* dummy name */
172 	{ 0, -1 },
173 };
174 
175 const struct list *lists[] = {
176 	toplevel,
177 	secondlevel,
178 	0
179 };
180 
181 #define CTL_MACHDEP_SIZE (sizeof(ctl_machdep) / sizeof(ctl_machdep[0]))
182 
183 /*
184  * Process library mappings of the form:
185  *	<library_name>	<machdep_variable> <value,...:library_name,...> ...
186  */
187 static void
188 _rtld_process_mapping(lib_p, bp, len)
189 	Library_Xform **lib_p;
190 	char *bp;
191 	size_t len;
192 {
193 	static const char WS[] = " \t\n";
194 	Library_Xform *hwptr = NULL;
195 	char *ptr, *key, *lib, *l;
196 	int i, j, k;
197 
198 	dbg((" processing mapping \"%s\"", bp));
199 
200 	if ((ptr = strsep(&bp, WS)) == NULL)
201 		return;
202 
203 	dbg((" library \"%s\"", ptr));
204 
205 	hwptr = xmalloc(sizeof(*hwptr));
206 	memset(hwptr, 0, sizeof(*hwptr));
207 	hwptr->name = xstrdup(ptr);
208 
209 	while ((ptr = strsep(&bp, WS)) != NULL)
210 		if (*ptr != '\0')
211 			break;
212 	if (ptr == NULL) {
213 		xwarnx("missing sysctl variable name");
214 		goto cleanup;
215 	}
216 
217 	dbg((" sysctl \"%s\"", ptr));
218 
219 	for (i = 0; (l = strsep(&ptr, ".")) != NULL; i++) {
220 
221 		if (lists[i] == NULL || i >= RTLD_MAX_CTL) {
222 			xwarnx("sysctl nesting too deep");
223 			goto cleanup;
224 		}
225 
226 		for (j = 1; lists[i][j].numentries != -1; j++) {
227 
228 			if (lists[i][j].ctl == NULL)
229 				continue;
230 
231 			for (k = 1; k < lists[i][j].numentries; k++) {
232 				if (strcmp(lists[i][j].ctl[k].name, l) == 0)
233 					break;
234 			}
235 
236 			if (lists[i][j].numentries == -1) {
237 				xwarnx("unknown sysctl variable name `%s'", l);
238 				goto cleanup;
239 			}
240 
241 			hwptr->ctl[hwptr->ctlmax] = k;
242 			hwptr->ctltype[hwptr->ctlmax++] =
243 			    lists[i][j].ctl[k].type;
244 		}
245 	}
246 
247 	for (i = 0; i < hwptr->ctlmax; i++)
248 		dbg((" sysctl %d, %d", hwptr->ctl[i], hwptr->ctltype[i]));
249 
250 	for (i = 0; (ptr = strsep(&bp, WS)) != NULL; i++) {
251 		if (*ptr == '\0') {
252 			/* back up index and continue */
253 			i--;
254 			continue;
255 		}
256 		if (i == RTLD_MAX_ENTRY) {
257 no_more:
258 			xwarnx("maximum library entries exceeded `%s'",
259 			    hwptr->name);
260 			goto cleanup;
261 		}
262 		if ((key = strsep(&ptr, ":")) == NULL) {
263 			xwarnx("missing sysctl variable value for `%s'",
264 			    hwptr->name);
265 			goto cleanup;
266 		}
267 		if ((lib = strsep(&ptr, ":")) == NULL) {
268 			xwarnx("missing sysctl library list for `%s'",
269 			    hwptr->name);
270 			goto cleanup;
271 		}
272 		for (j = 0; (l = strsep(&lib, ",")) != NULL; j++) {
273 			if (j == RTLD_MAX_LIBRARY) {
274 				xwarnx("maximum library entries exceeded `%s'",
275 				    hwptr->name);
276 				goto cleanup;
277 			}
278 			dbg((" library \"%s\"", l));
279 			hwptr->entry[i].library[j] = xstrdup(l);
280 		}
281 		if (j == 0) {
282 			xwarnx("No library map entries for `%s/%s'",
283 				hwptr->name, ptr);
284 			goto cleanup;
285 		}
286 		j = i;
287 		for (; (l = strsep(&key, ",")) != NULL; i++) {
288 			dbg((" key \"%s\"", l));
289 			if (i == RTLD_MAX_ENTRY)
290 				goto no_more;
291 			if (i != j)
292 				(void)memcpy(hwptr->entry[i].library,
293 				    hwptr->entry[j].library,
294 				    sizeof(hwptr->entry[j].library));
295 			hwptr->entry[i].value = xstrdup(l);
296 		}
297 
298 		if (j != i)
299 			i--;
300 	}
301 
302 	if (i == 0) {
303 		xwarnx("No library entries for `%s'", hwptr->name);
304 		goto cleanup;
305 	}
306 
307 	hwptr->next = *lib_p;
308 	*lib_p = hwptr;
309 
310 	return;
311 
312 cleanup:
313 	if (hwptr->name)
314 		free(hwptr->name);
315 	free(hwptr);
316 }
317 
318 void
319 _rtld_process_hints(path_p, lib_p, fname)
320 	Search_Path **path_p;
321 	Library_Xform **lib_p;
322 	const char *fname;
323 {
324 	int fd;
325 	char *buf, *b, *ebuf;
326 	struct stat st;
327 	size_t sz, len;
328 	Search_Path **head_p = path_p;
329 	int doing_path = 0;
330 
331 	if ((fd = open(fname, O_RDONLY)) == -1) {
332 		/* Don't complain */
333 		return;
334 	}
335 
336 	if (fstat(fd, &st) == -1) {
337 		/* Complain */
338 		xwarn("fstat: %s", fname);
339 		return;
340 	}
341 
342 	sz = (size_t) st.st_size;
343 
344 	buf = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FILE, fd, 0);
345 	if (buf == MAP_FAILED) {
346 		xwarn("fstat: %s", fname);
347 		(void)close(fd);
348 		return;
349 	}
350 	(void)close(fd);
351 
352 	while ((*path_p) != NULL)
353 		path_p = &(*path_p)->sp_next;
354 
355 	for (b = buf, ebuf = buf + sz; b < ebuf; ) {
356 		b += strspn(b, " \t\n");
357 		if (*b == '\0')
358 			break;
359 
360 		len = strcspn(b, "\n#");
361 		if (len == 0) {
362 			b += strcspn(b, "\n");
363 			continue;
364 		}
365 
366 		doing_path = *b == '/';
367 		if (doing_path) {
368 			size_t tmp = len - 1;
369 			while (b[tmp] == '#' || b[tmp] == ' ' || b[tmp] == '\t')
370 				tmp--;
371 			path_p = _rtld_append_path(head_p, path_p, b, tmp + 1);
372 		} else {
373 			char tmp = b[len];
374 			b[len] = '\0';
375 			_rtld_process_mapping(lib_p, b, len);
376 			b[len] = tmp;
377 		}
378 
379 		b += len;
380 	}
381 
382 	(void)munmap(buf, sz);
383 }
384