/* $NetBSD: search.c,v 1.16 2002/11/14 21:07:46 nathanw Exp $ */ /* * Copyright 1996 Matt Thomas * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Polstra. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Dynamic linker for ELF. * * John Polstra . */ #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "rtld.h" /* * Data declarations. */ Search_Path *_rtld_invalid_paths; static Obj_Entry *_rtld_search_library_path __P((const char *, size_t, const char *, size_t, int)); static Obj_Entry * _rtld_search_library_path(name, namelen, dir, dirlen, mode) const char *name; size_t namelen; const char *dir; size_t dirlen; int mode; { char *pathname; size_t pathnamelen; Obj_Entry *obj; Search_Path *sp; pathnamelen = dirlen + 1 + namelen; for (sp = _rtld_invalid_paths; sp != NULL; sp = sp->sp_next) { if (sp->sp_pathlen == pathnamelen && !memcmp(name, sp->sp_path + dirlen + 1, namelen) && !memcmp(dir, sp->sp_path, dirlen)) { return NULL; } } pathname = xmalloc(pathnamelen + 1); (void)strncpy(pathname, dir, dirlen); pathname[dirlen] = '/'; strcpy(pathname + dirlen + 1, name); dbg((" Trying \"%s\"", pathname)); obj = _rtld_load_object(pathname, mode); if (obj == NULL) { Search_Path *path; path = NEW(Search_Path); path->sp_pathlen = pathnamelen; path->sp_path = pathname; path->sp_next = _rtld_invalid_paths; _rtld_invalid_paths = path; } return obj; } /* * Find the library with the given name, and return its full pathname. * The returned string is dynamically allocated. Generates an error * message and returns NULL if the library cannot be found. * * If the second argument is non-NULL, then it refers to an already- * loaded shared object, whose library search path will be searched. */ Obj_Entry * _rtld_load_library(name, refobj, mode) const char *name; const Obj_Entry *refobj; int mode; { char tmperror[512], *tmperrorp; Search_Path *sp; char *pathname; int namelen; Obj_Entry *obj; if (strchr(name, '/') != NULL) { /* Hard coded pathname */ if (name[0] != '/' && !_rtld_trust) { _rtld_error( "absolute pathname required for shared object \"%s\"", name); return NULL; } pathname = xstrdup(name); goto found; } dbg((" Searching for \"%s\" (%p)", name, refobj)); tmperrorp = _rtld_dlerror(); if (tmperrorp != NULL) { strncpy(tmperror, tmperrorp, sizeof tmperror); tmperrorp = tmperror; } namelen = strlen(name); for (sp = _rtld_paths; sp != NULL; sp = sp->sp_next) if ((obj = _rtld_search_library_path(name, namelen, sp->sp_path, sp->sp_pathlen, mode)) != NULL) goto pathfound; if (refobj != NULL) for (sp = refobj->rpaths; sp != NULL; sp = sp->sp_next) if ((obj = _rtld_search_library_path(name, namelen, sp->sp_path, sp->sp_pathlen, mode)) != NULL) goto pathfound; for (sp = _rtld_default_paths; sp != NULL; sp = sp->sp_next) if ((obj = _rtld_search_library_path(name, namelen, sp->sp_path, sp->sp_pathlen, mode)) != NULL) goto pathfound; _rtld_error("Shared object \"%s\" not found", name); return NULL; pathfound: /* * Successfully found a library; restore the dlerror state as it was * before _rtld_load_library() was called (any failed call to * _rtld_search_library_path() will set the dlerror state, but if the * library was eventually found, then the error state should not * change. */ if (tmperrorp) _rtld_error("%s", tmperror); else (void)_rtld_dlerror(); return obj; found: obj = _rtld_load_object(pathname, mode); if (obj == NULL) free(pathname); return obj; }