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