sod.c revision 1.15
1343171Sdim/*	$OpenBSD: sod.c,v 1.15 2002/07/29 22:43:36 art Exp $	*/
2343171Sdim
3353358Sdim/*
4353358Sdim * Copyright (c) 1993 Paul Kranenburg
5353358Sdim * All rights reserved.
6343171Sdim *
7343171Sdim * Redistribution and use in source and binary forms, with or without
8343171Sdim * modification, are permitted provided that the following conditions
9343171Sdim * are met:
10343171Sdim * 1. Redistributions of source code must retain the above copyright
11343171Sdim *    notice, this list of conditions and the following disclaimer.
12343171Sdim * 2. Redistributions in binary form must reproduce the above copyright
13343171Sdim *    notice, this list of conditions and the following disclaimer in the
14343171Sdim *    documentation and/or other materials provided with the distribution.
15343171Sdim * 3. All advertising materials mentioning features or use of this software
16343171Sdim *    must display the following acknowledgement:
17343171Sdim *	This product includes software developed by Paul Kranenburg.
18343171Sdim * 4. The name of the author may not be used to endorse or promote products
19343171Sdim *    derived from this software without specific prior written permission
20343171Sdim *
21343171Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22343171Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23343171Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24343171Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25343171Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26343171Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27343171Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28343171Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29343171Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30343171Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31343171Sdim *
32343171Sdim */
33343171Sdim
34343171Sdim#include <sys/types.h>
35343171Sdim#include <sys/syslimits.h>
36343171Sdim#include <stdio.h>
37343171Sdim#include <fcntl.h>
38343171Sdim#include <nlist.h>
39343171Sdim#include <link.h>
40343171Sdim#include <machine/exec.h>
41343171Sdim#include <sys/mman.h>
42343171Sdim#include <string.h>
43343171Sdim#include <stdlib.h>
44343171Sdim#include <unistd.h>
45343171Sdim#include <syscall.h>
46343171Sdim
47343171Sdim#include "archdep.h"
48343171Sdim#include "util.h"
49343171Sdim#include "sod.h"
50343171Sdim
51343171Sdim#define PAGSIZ	__LDPGSZ
52343171Sdimint _dl_hinthash(char *cp, int vmajor, int vminor);
53343171Sdim
54343171Sdim/*
55343171Sdim * Populate sod struct for dlopen's call to map_object
56343171Sdim */
57343171Sdimvoid
58343171Sdim_dl_build_sod(name, sodp)
59343171Sdim	const char	*name;
60343171Sdim	struct sod	*sodp;
61343171Sdim{
62343171Sdim	unsigned int	tuplet;
63343171Sdim	int		major, minor;
64343171Sdim	char		*realname, *tok, *etok, *cp;
65343171Sdim
66343171Sdim	/* default is an absolute or relative path */
67343171Sdim	sodp->sod_name = (long)_dl_strdup(name);    /* strtok is destructive */
68343171Sdim	sodp->sod_library = 0;
69343171Sdim	sodp->sod_major = sodp->sod_minor = 0;
70343171Sdim
71343171Sdim	/* does it look like /^lib/ ? */
72343171Sdim	if (_dl_strncmp((char *)sodp->sod_name, "lib", 3) != 0)
73343171Sdim		return;
74343171Sdim
75343171Sdim	/* is this a filename? */
76343171Sdim	if (_dl_strchr((char *)sodp->sod_name, '/'))
77343171Sdim		return;
78343171Sdim
79343171Sdim	/* skip over 'lib' */
80343171Sdim	cp = (char *)sodp->sod_name + 3;
81343171Sdim
82343171Sdim	/* dot guardian */
83343171Sdim	if ((_dl_strchr(cp, '.') == NULL) || (*(cp+_dl_strlen(cp)-1) == '.'))
84353358Sdim		return;
85343171Sdim
86343171Sdim	/* default */
87343171Sdim	major = minor = -1;
88343171Sdim
89343171Sdim	realname = NULL;
90343171Sdim	/* loop through name - parse skipping name */
91343171Sdim	for (tuplet = 0; (tok = strsep(&cp, ".")) != NULL; tuplet++) {
92343171Sdim		switch (tuplet) {
93343171Sdim		case 0:
94343171Sdim			/* removed 'lib' and extensions from name */
95343171Sdim			realname = tok;
96343171Sdim			break;
97343171Sdim		case 1:
98343171Sdim			/* 'so' extension */
99343171Sdim			if (_dl_strcmp(tok, "so") != 0)
100343171Sdim				goto backout;
101343171Sdim			break;
102343171Sdim		case 2:
103343171Sdim			/* major version extension */
104343171Sdim			major = strtol(tok, &etok, 10);
105343171Sdim			if (*tok == '\0' || *etok != '\0')
106343171Sdim				goto backout;
107343171Sdim			break;
108343171Sdim		case 3:
109343171Sdim			/* minor version extension */
110343171Sdim			minor = strtol(tok, &etok, 10);
111343171Sdim			if (*tok == '\0' || *etok != '\0')
112343171Sdim				goto backout;
113343171Sdim			break;
114343171Sdim		/* if we get here, it must be weird */
115343171Sdim		default:
116343171Sdim			goto backout;
117343171Sdim		}
118343171Sdim	}
119343171Sdim	if (realname == NULL) {
120343171Sdim		goto backout;
121343171Sdim	}
122343171Sdim	cp = (char *)sodp->sod_name;
123343171Sdim	sodp->sod_name = (long)_dl_strdup(realname);
124343171Sdim	_dl_free(cp);
125343171Sdim	sodp->sod_library = 1;
126343171Sdim	sodp->sod_major = major;
127343171Sdim	sodp->sod_minor = minor;
128343171Sdim	return;
129343171Sdim
130343171Sdimbackout:
131343171Sdim	_dl_free((char *)sodp->sod_name);
132343171Sdim	sodp->sod_name = (long)_dl_strdup(name);
133343171Sdim}
134343171Sdim
135343171Sdimstatic int			hfd;
136343171Sdimstatic long			hsize;
137343171Sdimstatic struct hints_header	*hheader = NULL;
138343171Sdimstatic struct hints_bucket	*hbuckets;
139343171Sdimstatic char			*hstrtab;
140343171Sdimchar				*_dl_hint_search_path = NULL;
141343171Sdim
142343171Sdim#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1)
143343171Sdim
144343171Sdimvoid
145343171Sdim_dl_maphints()
146343171Sdim{
147343171Sdim	caddr_t		addr;
148343171Sdim
149343171Sdim	if ((hfd = _dl_open(_PATH_LD_HINTS, O_RDONLY)) < 0) {
150343171Sdim		hheader = (struct hints_header *)-1;
151343171Sdim		return;
152343171Sdim	}
153343171Sdim
154343171Sdim	hsize = PAGSIZ;
155343171Sdim	addr = (void *) _dl_mmap(0, hsize, PROT_READ, MAP_PRIVATE, hfd, 0);
156343171Sdim
157343171Sdim	if (addr == MAP_FAILED) {
158343171Sdim		_dl_close(hfd);
159353358Sdim		hheader = (struct hints_header *)-1;
160343171Sdim		return;
161343171Sdim	}
162353358Sdim
163343171Sdim	hheader = (struct hints_header *)addr;
164343171Sdim	if (HH_BADMAG(*hheader)) {
165343171Sdim		_dl_munmap(addr, hsize);
166343171Sdim		_dl_close(hfd);
167343171Sdim		hheader = (struct hints_header *)-1;
168343171Sdim		return;
169360784Sdim	}
170360784Sdim
171343171Sdim	if (hheader->hh_version != LD_HINTS_VERSION_1 &&
172343171Sdim	    hheader->hh_version != LD_HINTS_VERSION_2) {
173343171Sdim		_dl_munmap(addr, hsize);
174353358Sdim		_dl_close(hfd);
175343171Sdim		hheader = (struct hints_header *)-1;
176343171Sdim		return;
177343171Sdim	}
178343171Sdim
179343171Sdim	if (hheader->hh_ehints > hsize) {
180343171Sdim		if ((caddr_t)_dl_mmap(addr+hsize, hheader->hh_ehints - hsize,
181343171Sdim		    PROT_READ, MAP_PRIVATE|MAP_FIXED,
182343171Sdim		    hfd, hsize) != (caddr_t)(addr+hsize)) {
183343171Sdim			_dl_munmap((caddr_t)hheader, hsize);
184353358Sdim			_dl_close(hfd);
185343171Sdim			hheader = (struct hints_header *)-1;
186343171Sdim			return;
187360784Sdim		}
188360784Sdim	}
189353358Sdim
190343171Sdim	hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
191343171Sdim	hstrtab = (char *)(addr + hheader->hh_strtab);
192343171Sdim	if (hheader->hh_version >= LD_HINTS_VERSION_2)
193343171Sdim		_dl_hint_search_path = hstrtab + hheader->hh_dirlist;
194343171Sdim
195343171Sdim	/* close the file descriptor, leaving the hints mapped */
196343171Sdim	_dl_close(hfd);
197343171Sdim}
198343171Sdim
199343171Sdimchar *
200343171Sdim_dl_findhint(name, major, minor, prefered_path)
201343171Sdim	char	*name;
202343171Sdim	int	major, minor;
203343171Sdim	char	*prefered_path;
204353358Sdim{
205353358Sdim	struct hints_bucket	*bp;
206343171Sdim
207343171Sdim	/*
208343171Sdim	 * If not mapped, and we have not tried before, try to map the
209343171Sdim	 * hints, if previous attempts failed hheader is -1 and we
210343171Sdim	 * do not wish to retry it.
211343171Sdim	 */
212343171Sdim	if (hheader == NULL)
213		_dl_maphints();
214
215	/* if it failed to map, return failure */
216	if (!(HINTS_VALID))
217		return NULL;
218
219	bp = hbuckets + (_dl_hinthash(name, major, minor) % hheader->hh_nbucket);
220
221	while (1) {
222		/* Sanity check */
223		if (bp->hi_namex >= hheader->hh_strtab_sz) {
224			_dl_printf("Bad name index: %#x\n", bp->hi_namex);
225			_dl_exit(7);
226			break;
227		}
228		if (bp->hi_pathx >= hheader->hh_strtab_sz) {
229			_dl_printf("Bad path index: %#x\n", bp->hi_pathx);
230			_dl_exit(7);
231			break;
232		}
233
234		if (_dl_strcmp(name, hstrtab + bp->hi_namex) == 0) {
235			/* It's `name', check version numbers */
236			if (bp->hi_major == major &&
237			    (bp->hi_ndewey < 2 || bp->hi_minor >= minor)) {
238				if (prefered_path == NULL ||
239				    _dl_strncmp(prefered_path,
240				    hstrtab + bp->hi_pathx,
241				    _dl_strlen(prefered_path)) == 0)
242					return hstrtab + bp->hi_pathx;
243			}
244		}
245
246		if (bp->hi_next == -1)
247			break;
248
249		/* Move on to next in bucket */
250		bp = &hbuckets[bp->hi_next];
251	}
252
253	/* No hints available for name */
254	return NULL;
255}
256int
257_dl_hinthash(cp, vmajor, vminor)
258	char	*cp;
259	int	vmajor, vminor;
260{
261	int	k = 0;
262
263	while (*cp)
264		k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
265
266	k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
267	if (hheader->hh_version == LD_HINTS_VERSION_1)
268		k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
269
270	return k;
271}
272