search.c revision 1.6
1/*	$NetBSD: search.c,v 1.6 1999/10/21 21:15:04 erh Exp $	 */
2
3/*
4 * Copyright 1996 Matt Thomas <matt@3am-software.com>
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 John Polstra.
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 * Dynamic linker for ELF.
35 *
36 * John Polstra <jdp@polstra.com>.
37 */
38
39#include <err.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <stdarg.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47#include <sys/types.h>
48#include <sys/mman.h>
49#include <sys/stat.h>
50#include <dirent.h>
51
52#include "debug.h"
53#include "rtld.h"
54
55/*
56 * Data declarations.
57 */
58static bool _rtld_check_library __P((const char *));
59static char *_rtld_search_library_path __P((const char *, size_t, const char *,
60    size_t));
61
62static bool
63_rtld_check_library(pathname)
64	const char *pathname;
65{
66	struct stat mystat;
67	Elf_Ehdr ehdr;
68	int fd;
69
70	if (stat(pathname, &mystat) == -1 || !S_ISREG(mystat.st_mode))
71		return false;
72
73	if ((fd = open(pathname, O_RDONLY)) == -1)
74		return false;
75
76	if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
77		goto lose;
78
79	/* Elf_e_ident includes class */
80	if (memcmp(Elf_e_ident, ehdr.e_ident, Elf_e_siz) != 0)
81		goto lose;
82
83	switch (ehdr.e_machine) {
84		ELFDEFNNAME(MACHDEP_ID_CASES)
85	default:
86		goto lose;
87	}
88
89	if (ehdr.e_ident[Elf_ei_version] != Elf_ev_current ||
90	    ehdr.e_version != Elf_ev_current ||
91	    ehdr.e_ident[Elf_ei_data] != ELFDEFNNAME(MACHDEP_ENDIANNESS) ||
92	    ehdr.e_type != Elf_et_dyn)
93		goto lose;
94
95	close(fd);
96	return true;
97
98lose:
99	close(fd);
100	return false;
101}
102
103
104static char *
105_rtld_search_library_path(name, namelen, dir, dirlen)
106	const char *name;
107	size_t namelen;
108	const char *dir;
109	size_t dirlen;
110{
111	char *pathname;
112
113	pathname = xmalloc(dirlen + 1 + namelen + 1);
114	(void)strncpy(pathname, dir, dirlen);
115	pathname[dirlen] = '/';
116	strcpy(pathname + dirlen + 1, name);
117
118	dbg(("  Trying \"%s\"", pathname));
119	if (_rtld_check_library(pathname))	/* We found it */
120		return pathname;
121
122	free(pathname);
123	return NULL;
124}
125
126/*
127 * Find the library with the given name, and return its full pathname.
128 * The returned string is dynamically allocated.  Generates an error
129 * message and returns NULL if the library cannot be found.
130 *
131 * If the second argument is non-NULL, then it refers to an already-
132 * loaded shared object, whose library search path will be searched.
133 */
134char *
135_rtld_find_library(name, refobj)
136	const char *name;
137	const Obj_Entry *refobj;
138{
139	Search_Path *sp;
140	char *pathname;
141	int namelen;
142
143	if (strchr(name, '/') != NULL) {	/* Hard coded pathname */
144		if (name[0] != '/' && !_rtld_trust) {
145			_rtld_error(
146			"Absolute pathname required for shared object \"%s\"",
147			    name);
148			return NULL;
149		}
150#ifdef SVR4_LIBDIR
151		if (strncmp(name, SVR4_LIBDIR, SVR4_LIBDIRLEN) == 0
152		    && name[SVR4_LIBDIRLEN] == '/') {	/* In "/usr/lib" */
153			/*
154			 * Map hard-coded "/usr/lib" onto our ELF library
155			 * directory.
156			 */
157			pathname = xmalloc(strlen(name) + LIBDIRLEN -
158			    SVR4_LIBDIRLEN + 1);
159			(void)strcpy(pathname, LIBDIR);
160			(void)strcpy(pathname + LIBDIRLEN, name +
161			    SVR4_LIBDIRLEN);
162			return pathname;
163		}
164#endif /* SVR4_LIBDIR */
165		return xstrdup(name);
166	}
167	dbg((" Searching for \"%s\" (%p)", name, refobj));
168
169	namelen = strlen(name);
170
171	for (sp = _rtld_paths; sp != NULL; sp = sp->sp_next)
172		if ((pathname = _rtld_search_library_path(name, namelen,
173		    sp->sp_path, sp->sp_pathlen)) != NULL)
174			return (pathname);
175
176	if (refobj != NULL)
177		for (sp = refobj->rpaths; sp != NULL; sp = sp->sp_next)
178			if ((pathname = _rtld_search_library_path(name,
179			    namelen, sp->sp_path, sp->sp_pathlen)) != NULL)
180				return (pathname);
181
182	for (sp = _rtld_default_paths; sp != NULL; sp = sp->sp_next)
183		if ((pathname = _rtld_search_library_path(name, namelen,
184		    sp->sp_path, sp->sp_pathlen)) != NULL)
185			return (pathname);
186
187#if 0
188	if ((refobj != NULL &&
189	    (pathname = _rtld_search_library_path(name,
190	    refobj->rpath)) != NULL) ||
191	    (pathname = _rtld_search_library_path(name,
192	    ld_library_path)) != NULL
193#ifdef SVR4_LIBDIR
194	    LOSE !
195	    ||(pathname = _rtld_search_library_path(name, SVR4_LIBDIR)) != NULL
196#endif
197	    )
198		return pathname;
199#endif
200
201	_rtld_error("Shared object \"%s\" not found", name);
202	return NULL;
203}
204