sod.c revision 1.14
1/*	$OpenBSD: sod.c,v 1.14 2002/07/12 20:18:30 drahn Exp $	*/
2
3/*
4 * Copyright (c) 1993 Paul Kranenburg
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Paul Kranenburg.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include <sys/types.h>
35#include <sys/syslimits.h>
36#include <stdio.h>
37#include <fcntl.h>
38#include <nlist.h>
39#include <link.h>
40#include <machine/exec.h>
41#include <sys/mman.h>
42#include <string.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <syscall.h>
46
47#include "archdep.h"
48#include "util.h"
49#include "sod.h"
50
51#define PAGSIZ	__LDPGSZ
52int _dl_hinthash(char *cp, int vmajor, int vminor);
53
54/*
55 * Populate sod struct for dlopen's call to map_object
56 */
57void
58_dl_build_sod(name, sodp)
59	const char	*name;
60	struct sod	*sodp;
61{
62	unsigned int	tuplet;
63	int		major, minor;
64	char		*realname, *tok, *etok, *cp;
65
66	/* default is an absolute or relative path */
67	sodp->sod_name = (long)_dl_strdup(name);    /* strtok is destructive */
68	sodp->sod_library = 0;
69	sodp->sod_major = sodp->sod_minor = 0;
70
71	/* does it look like /^lib/ ? */
72	if (_dl_strncmp((char *)sodp->sod_name, "lib", 3) != 0)
73		return;
74
75	/* is this a filename? */
76	if (_dl_strchr((char *)sodp->sod_name, '/'))
77		return;
78
79	/* skip over 'lib' */
80	cp = (char *)sodp->sod_name + 3;
81
82	/* dot guardian */
83	if ((_dl_strchr(cp, '.') == NULL) || (*(cp+_dl_strlen(cp)-1) == '.'))
84		return;
85
86	/* default */
87	major = minor = -1;
88
89	realname = NULL;
90	/* loop through name - parse skipping name */
91	for (tuplet = 0; (tok = strsep(&cp, ".")) != NULL; tuplet++) {
92		switch (tuplet) {
93		case 0:
94			/* removed 'lib' and extensions from name */
95			realname = tok;
96			break;
97		case 1:
98			/* 'so' extension */
99			if (_dl_strcmp(tok, "so") != 0)
100				goto backout;
101			break;
102		case 2:
103			/* major version extension */
104			major = strtol(tok, &etok, 10);
105			if (*tok == '\0' || *etok != '\0')
106				goto backout;
107			break;
108		case 3:
109			/* minor version extension */
110			minor = strtol(tok, &etok, 10);
111			if (*tok == '\0' || *etok != '\0')
112				goto backout;
113			break;
114		/* if we get here, it must be weird */
115		default:
116			goto backout;
117		}
118	}
119	if (realname == NULL) {
120		goto backout;
121	}
122	cp = (char *)sodp->sod_name;
123	sodp->sod_name = (long)_dl_strdup(realname);
124	_dl_free(cp);
125	sodp->sod_library = 1;
126	sodp->sod_major = major;
127	sodp->sod_minor = minor;
128	return;
129
130backout:
131	_dl_free((char *)sodp->sod_name);
132	sodp->sod_name = (long)_dl_strdup(name);
133}
134
135static int			hfd;
136static long			hsize;
137static struct hints_header	*hheader = NULL;
138static struct hints_bucket	*hbuckets;
139static char			*hstrtab;
140char				*_dl_hint_search_path = NULL;
141
142#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1)
143
144void
145_dl_maphints()
146{
147	caddr_t		addr;
148
149	if ((hfd = _dl_open(_PATH_LD_HINTS, O_RDONLY)) < 0) {
150		hheader = (struct hints_header *)-1;
151		return;
152	}
153
154	hsize = PAGSIZ;
155	addr = (void *) _dl_mmap(0, hsize, PROT_READ, MAP_PRIVATE, hfd, 0);
156
157	if (addr == MAP_FAILED) {
158		_dl_close(hfd);
159		hheader = (struct hints_header *)-1;
160		return;
161	}
162
163	hheader = (struct hints_header *)addr;
164	if (HH_BADMAG(*hheader)) {
165		_dl_munmap(addr, hsize);
166		_dl_close(hfd);
167		hheader = (struct hints_header *)-1;
168		return;
169	}
170
171	if (hheader->hh_version != LD_HINTS_VERSION_1 &&
172	    hheader->hh_version != LD_HINTS_VERSION_2) {
173		_dl_munmap(addr, hsize);
174		_dl_close(hfd);
175		hheader = (struct hints_header *)-1;
176		return;
177	}
178
179	if (hheader->hh_ehints > hsize) {
180		if ((caddr_t)_dl_mmap(addr+hsize, hheader->hh_ehints - hsize,
181		    PROT_READ, MAP_PRIVATE|MAP_FIXED,
182		    hfd, hsize) != (caddr_t)(addr+hsize)) {
183			_dl_munmap((caddr_t)hheader, hsize);
184			_dl_close(hfd);
185			hheader = (struct hints_header *)-1;
186			return;
187		}
188	}
189
190	hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
191	hstrtab = (char *)(addr + hheader->hh_strtab);
192	if (hheader->hh_version >= LD_HINTS_VERSION_2)
193		_dl_hint_search_path = hstrtab + hheader->hh_dirlist;
194
195	/* close the file descriptor, leaving the hints mapped */
196	_dl_close(hfd);
197}
198
199char *
200_dl_findhint(name, major, minor, prefered_path)
201	char	*name;
202	int	major, minor;
203	char	*prefered_path;
204{
205	struct hints_bucket	*bp;
206
207	/* If not mapped, and we have not tried before, try to map the
208	 * hints, if previous attempts failed hheader is -1 and we
209	 * do not wish to retry it.
210	 */
211	if (hheader == NULL)
212		_dl_maphints();
213
214	/* if it failed to map, return failure */
215	if (!(HINTS_VALID))
216		return NULL;
217
218	bp = hbuckets + (_dl_hinthash(name, major, minor) % hheader->hh_nbucket);
219
220	while (1) {
221		/* Sanity check */
222		if (bp->hi_namex >= hheader->hh_strtab_sz) {
223			_dl_printf("Bad name index: %#x\n", bp->hi_namex);
224			_dl_exit(7);
225			break;
226		}
227		if (bp->hi_pathx >= hheader->hh_strtab_sz) {
228			_dl_printf("Bad path index: %#x\n", bp->hi_pathx);
229			_dl_exit(7);
230			break;
231		}
232
233		if (_dl_strcmp(name, hstrtab + bp->hi_namex) == 0) {
234			/* It's `name', check version numbers */
235			if (bp->hi_major == major &&
236			    (bp->hi_ndewey < 2 || bp->hi_minor >= minor)) {
237				if (prefered_path == NULL ||
238				    _dl_strncmp(prefered_path,
239				    hstrtab + bp->hi_pathx,
240				    _dl_strlen(prefered_path)) == 0)
241					return hstrtab + bp->hi_pathx;
242			}
243		}
244
245		if (bp->hi_next == -1)
246			break;
247
248		/* Move on to next in bucket */
249		bp = &hbuckets[bp->hi_next];
250	}
251
252	/* No hints available for name */
253	return NULL;
254}
255int
256_dl_hinthash(cp, vmajor, vminor)
257	char	*cp;
258	int	vmajor, vminor;
259{
260	int	k = 0;
261
262	while (*cp)
263		k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
264
265	k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
266	if (hheader->hh_version == LD_HINTS_VERSION_1)
267		k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
268
269	return k;
270}
271