/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Dl.c,v 3.10.2.1 1998/09/27 04:33:36 dawes Exp $ */ /* * Copyright 1995 by Frederic Lepied, France. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Frederic Lepied not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Frederic Lepied makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * FREDERIC LEPIED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL FREDERIC LEPIED BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * */ /* $XConsortium: xf86Dl.c /main/10 1996/12/28 15:40:19 kaleb $ */ #include /* for Error() */ #include #define NO_OSLIB_PROTOTYPES #include "xf86_OSlib.h" #include "xf86Version.h" #include "xf86.h" #include "xf86_Config.h" #include "xf86Priv.h" #if defined(CSRG_BASED) && !defined(__ELF__) #define PREPEND_UNDERSCORE #endif #ifdef RTLD_NOW #define DLOPEN_FLAGS RTLD_NOW /* Linux, SVR4 */ #else #ifdef DL_LAZY #define DLOPEN_FLAGS DL_LAZY /* NetBSD */ #else #define DLOPEN_FLAGS 1 /* FreeBSD */ #endif #endif typedef int (*InitModule)( #if NeedFunctionPrototypes unsigned long /* server_version */ #endif ); void* xf86LoadModule(const char * file, const char * path) { void *module = NULL; char *dir_elem, *path_elem, *keep; /* allocate a copy even for the absolute path, for consistency in * error reporting/recovery. */ keep = dir_elem = (char *) xcalloc(1, strlen(path) + 1); strcpy(dir_elem, path); /* absolute path */ if (file[0] == '/') { module = dlopen((char *)file, DLOPEN_FLAGS); } else { /* look for file in path */ struct stat stat_buf; dir_elem = strtok(dir_elem, ","); while (!module && (dir_elem != NULL)) { /* only allow fully specified path */ if (*dir_elem == '/') { if (dir_elem[strlen(dir_elem) - 1] == '/') { path_elem = (char*) xcalloc(1, strlen(file) + strlen(dir_elem) + 1); strcpy(path_elem, dir_elem); } else { path_elem = (char*) xcalloc(1, strlen(file) + strlen(dir_elem) + 2); strcpy(path_elem, dir_elem); path_elem[strlen(dir_elem)] = '/'; path_elem[strlen(dir_elem)+1] = '\0'; } strcat(path_elem, file); if ((stat(path_elem, &stat_buf) == 0) && ((S_IFMT & stat_buf.st_mode) == S_IFREG)) { module = dlopen(path_elem, DLOPEN_FLAGS); } xfree(path_elem); } if (!module) { dir_elem = strtok(NULL, ","); } } } if (!module) { const char *err = dlerror(); ErrorF("%s: %s\n", file, err ? err : "Unknown error loading module"); } else { #ifdef PREPEND_UNDERSCORE #ifndef DLSYM_BUG InitModule init_module = (InitModule)dlsym(module, "_init_module"); #else /* Work around a bug (?) in dlsym() which finds the symbols globally, instead of inside the specified object. Here we name the init func after the module's file name */ InitModule init_module; char *init_module_name; const char *module_name, *p; int l; if (file[0] == '/') { module_name = strrchr(file, '/') + 1; } else { module_name = &file[0]; } /* remove file suffix */ p = index(module_name, '.'); if (p != NULL) { l = p - module_name; } else { l = strlen(module_name); } /* build the symbol name */ init_module_name = (char *)xalloc(7+l); strcpy(init_module_name, "_init_"); strncpy(init_module_name + 6, module_name, l); init_module_name[6+l] = '\0'; init_module = (InitModule)dlsym(module, init_module_name); xfree(init_module_name); #endif /* DLSYM_BUG */ #else InitModule init_module = (InitModule)dlsym(module, "init_module"); #endif if (init_module) { if (!(*init_module)(XF86_VERSION_CURRENT)) { ErrorF("Warning: the module %s doesn't match server " "version%s\n", file, XF86_VERSION); } else { if (xf86Verbose) if (file[0] == '/') ErrorF("%s module %s successfully loaded\n", XCONFIG_GIVEN, file); else ErrorF("%s module %s successfully loaded from %s\n", XCONFIG_GIVEN, file, dir_elem); } } else { ErrorF("Unable to find init hook in module %s\n", file); xfree(keep); return NULL; } } xfree(keep); return module; } /* end of xf86dl.c */