search.c revision 1.8 1 /* $NetBSD: search.c,v 1.8 1999/10/25 13:57:12 kleink Exp $ */
2
3 /*
4 * Copyright 1996 Matt Thomas <matt (at) 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 (at) 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 */
64 static bool _rtld_check_library __P((const char *));
65 static char *_rtld_search_library_path __P((const char *, size_t, const char *,
66 size_t));
67
68 static 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(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
87 ehdr.e_ident[EI_CLASS] != ELFCLASS)
88 goto lose;
89
90 switch (ehdr.e_machine) {
91 ELFDEFNNAME(MACHDEP_ID_CASES)
92 default:
93 goto lose;
94 }
95
96 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
97 ehdr.e_version != EV_CURRENT ||
98 ehdr.e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS) ||
99 ehdr.e_type != ET_DYN)
100 goto lose;
101
102 close(fd);
103 return true;
104
105 lose:
106 close(fd);
107 return false;
108 }
109
110
111 static char *
112 _rtld_search_library_path(name, namelen, dir, dirlen)
113 const char *name;
114 size_t namelen;
115 const char *dir;
116 size_t dirlen;
117 {
118 char *pathname;
119
120 pathname = xmalloc(dirlen + 1 + namelen + 1);
121 (void)strncpy(pathname, dir, dirlen);
122 pathname[dirlen] = '/';
123 strcpy(pathname + dirlen + 1, name);
124
125 dbg((" Trying \"%s\"", pathname));
126 if (_rtld_check_library(pathname)) /* We found it */
127 return pathname;
128
129 free(pathname);
130 return NULL;
131 }
132
133 /*
134 * Find the library with the given name, and return its full pathname.
135 * The returned string is dynamically allocated. Generates an error
136 * message and returns NULL if the library cannot be found.
137 *
138 * If the second argument is non-NULL, then it refers to an already-
139 * loaded shared object, whose library search path will be searched.
140 */
141 char *
142 _rtld_find_library(name, refobj)
143 const char *name;
144 const Obj_Entry *refobj;
145 {
146 Search_Path *sp;
147 char *pathname;
148 int namelen;
149
150 if (strchr(name, '/') != NULL) { /* Hard coded pathname */
151 if (name[0] != '/' && !_rtld_trust) {
152 _rtld_error(
153 "Absolute pathname required for shared object \"%s\"",
154 name);
155 return NULL;
156 }
157 #ifdef SVR4_LIBDIR
158 if (strncmp(name, SVR4_LIBDIR, SVR4_LIBDIRLEN) == 0
159 && name[SVR4_LIBDIRLEN] == '/') { /* In "/usr/lib" */
160 /*
161 * Map hard-coded "/usr/lib" onto our ELF library
162 * directory.
163 */
164 pathname = xmalloc(strlen(name) + LIBDIRLEN -
165 SVR4_LIBDIRLEN + 1);
166 (void)strcpy(pathname, LIBDIR);
167 (void)strcpy(pathname + LIBDIRLEN, name +
168 SVR4_LIBDIRLEN);
169 return pathname;
170 }
171 #endif /* SVR4_LIBDIR */
172 return xstrdup(name);
173 }
174 dbg((" Searching for \"%s\" (%p)", name, refobj));
175
176 namelen = strlen(name);
177
178 for (sp = _rtld_paths; 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 if (refobj != NULL)
184 for (sp = refobj->rpaths; sp != NULL; sp = sp->sp_next)
185 if ((pathname = _rtld_search_library_path(name,
186 namelen, sp->sp_path, sp->sp_pathlen)) != NULL)
187 return (pathname);
188
189 for (sp = _rtld_default_paths; sp != NULL; sp = sp->sp_next)
190 if ((pathname = _rtld_search_library_path(name, namelen,
191 sp->sp_path, sp->sp_pathlen)) != NULL)
192 return (pathname);
193
194 #if 0
195 if ((refobj != NULL &&
196 (pathname = _rtld_search_library_path(name,
197 refobj->rpath)) != NULL) ||
198 (pathname = _rtld_search_library_path(name,
199 ld_library_path)) != NULL
200 #ifdef SVR4_LIBDIR
201 LOSE !
202 ||(pathname = _rtld_search_library_path(name, SVR4_LIBDIR)) != NULL
203 #endif
204 )
205 return pathname;
206 #endif
207
208 _rtld_error("Shared object \"%s\" not found", name);
209 return NULL;
210 }
211