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 (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(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
104 lose:
105 close(fd);
106 return false;
107 }
108
109
110 static 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 */
140 char *
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