/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "fspr_arch_dso.h" #include "fspr_strings.h" #include "fspr_portable.h" #if APR_HAS_DSO #if !defined(DSO_USE_DLFCN) && !defined(DSO_USE_SHL) && !defined(DSO_USE_DYLD) #error No DSO implementation specified. #endif #ifdef HAVE_STDDEF_H #include #endif #if APR_HAVE_STDLIB_H #include /* malloc(), free() */ #endif #if APR_HAVE_STRING_H #include /* for strerror() on HP-UX */ #endif #if defined(DSO_USE_DYLD) #define DYLD_LIBRARY_HANDLE (void *)-1 #endif APR_DECLARE(fspr_status_t) fspr_os_dso_handle_put(fspr_dso_handle_t **aprdso, fspr_os_dso_handle_t osdso, fspr_pool_t *pool) { *aprdso = fspr_pcalloc(pool, sizeof **aprdso); (*aprdso)->handle = osdso; (*aprdso)->pool = pool; return APR_SUCCESS; } APR_DECLARE(fspr_status_t) fspr_os_dso_handle_get(fspr_os_dso_handle_t *osdso, fspr_dso_handle_t *aprdso) { *osdso = aprdso->handle; return APR_SUCCESS; } static fspr_status_t dso_cleanup(void *thedso) { fspr_dso_handle_t *dso = thedso; if (dso->handle == NULL) return APR_SUCCESS; #if defined(DSO_USE_SHL) shl_unload((shl_t)dso->handle); #elif defined(DSO_USE_DYLD) if (dso->handle != DYLD_LIBRARY_HANDLE) { NSUnLinkModule(dso->handle, FALSE); } #elif defined(DSO_USE_DLFCN) if (dlclose(dso->handle) != 0) return APR_EINIT; #endif dso->handle = NULL; return APR_SUCCESS; } APR_DECLARE(fspr_status_t) fspr_dso_load(fspr_dso_handle_t **res_handle, const char *path, fspr_pool_t *pool) { #if defined(DSO_USE_SHL) shl_t os_handle = shl_load(path, BIND_IMMEDIATE, 0L); #elif defined(DSO_USE_DYLD) NSObjectFileImage image; NSModule os_handle = NULL; NSObjectFileImageReturnCode dsoerr; const char* err_msg = NULL; dsoerr = NSCreateObjectFileImageFromFile(path, &image); if (dsoerr == NSObjectFileImageSuccess) { #if defined(NSLINKMODULE_OPTION_RETURN_ON_ERROR) && defined(NSLINKMODULE_OPTION_NONE) os_handle = NSLinkModule(image, path, NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_NONE); /* If something went wrong, get the errors... */ if (!os_handle) { NSLinkEditErrors errors; int errorNumber; const char *fileName; NSLinkEditError(&errors, &errorNumber, &fileName, &err_msg); } #else os_handle = NSLinkModule(image, path, FALSE); #endif NSDestroyObjectFileImage(image); } else if ((dsoerr == NSObjectFileImageFormat || dsoerr == NSObjectFileImageInappropriateFile) && NSAddLibrary(path) == TRUE) { os_handle = (NSModule)DYLD_LIBRARY_HANDLE; } else { err_msg = "cannot create object file image or add library"; } #elif defined(DSO_USE_DLFCN) #if defined(OSF1) || defined(SEQUENT) || defined(SNI) ||\ (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) ||\ defined(__DragonFly__) void *os_handle = dlopen((char *)path, RTLD_NOW | RTLD_LOCAL); #else int flags = RTLD_NOW | RTLD_LOCAL; void *os_handle; #ifdef _AIX if (strchr(path + 1, '(') && path[strlen(path) - 1] == ')') { /* This special archive.a(dso.so) syntax is required for * the way libtool likes to build shared libraries on AIX. * dlopen() support for such a library requires that the * RTLD_MEMBER flag be enabled. */ flags |= RTLD_MEMBER; } #endif os_handle = dlopen(path, flags); #endif #endif /* DSO_USE_x */ *res_handle = fspr_pcalloc(pool, sizeof(**res_handle)); if(os_handle == NULL) { #if defined(DSO_USE_SHL) (*res_handle)->errormsg = strerror(errno); return APR_EDSOOPEN; #elif defined(DSO_USE_DYLD) (*res_handle)->errormsg = (err_msg) ? err_msg : "link failed"; return APR_EDSOOPEN; #elif defined(DSO_USE_DLFCN) (*res_handle)->errormsg = dlerror(); return APR_EDSOOPEN; #endif } (*res_handle)->handle = (void*)os_handle; (*res_handle)->pool = pool; (*res_handle)->errormsg = NULL; fspr_pool_cleanup_register(pool, *res_handle, dso_cleanup, fspr_pool_cleanup_null); return APR_SUCCESS; } APR_DECLARE(fspr_status_t) fspr_dso_unload(fspr_dso_handle_t *handle) { return fspr_pool_cleanup_run(handle->pool, handle, dso_cleanup); } APR_DECLARE(fspr_status_t) fspr_dso_sym(fspr_dso_handle_sym_t *ressym, fspr_dso_handle_t *handle, const char *symname) { #if defined(DSO_USE_SHL) void *symaddr = NULL; int status; errno = 0; status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_PROCEDURE, &symaddr); if (status == -1 && errno == 0) /* try TYPE_DATA instead */ status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_DATA, &symaddr); if (status == -1) return APR_ESYMNOTFOUND; *ressym = symaddr; return APR_SUCCESS; #elif defined(DSO_USE_DYLD) void *retval = NULL; NSSymbol symbol; char *symname2 = (char*)malloc(sizeof(char)*(strlen(symname)+2)); sprintf(symname2, "_%s", symname); #ifdef NSLINKMODULE_OPTION_PRIVATE if (handle->handle == DYLD_LIBRARY_HANDLE) { symbol = NSLookupAndBindSymbol(symname2); } else { symbol = NSLookupSymbolInModule((NSModule)handle->handle, symname2); } #else symbol = NSLookupAndBindSymbol(symname2); #endif free(symname2); if (symbol == NULL) { handle->errormsg = "undefined symbol"; return APR_ESYMNOTFOUND; } retval = NSAddressOfSymbol(symbol); if (retval == NULL) { handle->errormsg = "cannot resolve symbol"; return APR_ESYMNOTFOUND; } *ressym = retval; return APR_SUCCESS; #elif defined(DSO_USE_DLFCN) #if defined(DLSYM_NEEDS_UNDERSCORE) void *retval; char *symbol = (char*)malloc(sizeof(char)*(strlen(symname)+2)); sprintf(symbol, "_%s", symname); retval = dlsym(handle->handle, symbol); free(symbol); #elif defined(SEQUENT) || defined(SNI) void *retval = dlsym(handle->handle, (char *)symname); #else void *retval = dlsym(handle->handle, symname); #endif /* DLSYM_NEEDS_UNDERSCORE */ if (retval == NULL) { handle->errormsg = dlerror(); return APR_ESYMNOTFOUND; } *ressym = retval; return APR_SUCCESS; #endif /* DSO_USE_x */ } APR_DECLARE(const char *) fspr_dso_error(fspr_dso_handle_t *dso, char *buffer, fspr_size_t buflen) { if (dso->errormsg) { fspr_cpystrn(buffer, dso->errormsg, buflen); return dso->errormsg; } return "No Error"; } #endif