//roardl.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011 * * This file is part of libroar a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * NOTE for everyone want's to change something and send patches: * read README and HACKING! There a addition information on * the license of this document you need to read before you send * any patches. * * NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc * or libpulse*: * The libs libroaresd, libroararts and libroarpulse link this lib * and are therefore GPL. Because of this it may be illigal to use * them with any software that uses libesd, libartsc or libpulse*. */ #include "libroar.h" #if defined(ROAR_HAVE_LIBDL) && !defined(RTLD_NEXT) #define RTLD_NEXT ((void *) -1L) #endif struct roar_dl_lhandle { struct roar_dl_librarypara * para; struct roar_dl_libraryinst * lib; #if defined(ROAR_HAVE_LIBDL) void * handle; #endif }; struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv, const char * appname, const char * abiversion) { struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara)); ssize_t argc; int err; if ( ret == NULL ) return NULL; memset(ret, 0, sizeof(struct roar_dl_librarypara)); ret->version = ROAR_DL_LIBPARA_VERSION; ret->len = sizeof(struct roar_dl_librarypara); ret->refc = 1; ret->argc = 0; ret->argv = NULL; ret->args_store = NULL; ret->binargv = binargv; ret->appname = appname; ret->abiversion = abiversion; if ( args != NULL ) { ret->args_store = roar_mm_strdup(args); if ( ret->args_store == NULL ) { err = roar_error; roar_mm_free(ret); roar_error = err; return NULL; } argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 0); if ( argc == -1 ) { err = roar_error; roar_mm_free(ret->args_store); roar_mm_free(ret); roar_error = err; return NULL; } ret->argc = argc; } return ret; } int roar_dl_para_ref (struct roar_dl_librarypara * para) { if ( para == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } para->refc++; return 0; } int roar_dl_para_unref (struct roar_dl_librarypara * para) { if ( para == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } para->refc--; if ( para->refc == 0 ) { if ( para->args_store != NULL ) { roar_mm_free(para->args_store); roar_mm_free(para->argv); } roar_mm_free(para); } return 0; } int roar_dl_para_check_version (struct roar_dl_librarypara * para, const char * appname, const char * abiversion) { if ( para == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } // check if both appnames are NULL or non-NULL. if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) { roar_err_set(ROAR_ERROR_BADVERSION); return -1; } // check if the appname matches if given. if ( para->appname != NULL && !!strcmp(para->appname, appname) ) { roar_err_set(ROAR_ERROR_BADVERSION); return -1; } // check if both ABI versions are NULL or non-NULL. if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) { roar_err_set(ROAR_ERROR_BADVERSION); return -1; } // check if the ABI versions matches if given. if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) { roar_err_set(ROAR_ERROR_BADVERSION); return -1; } return 0; } #if defined(ROAR_HAVE_LIBDL) static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) { if ( lhandle == ROAR_DL_HANDLE_DEFAULT ) return RTLD_DEFAULT; if ( lhandle == ROAR_DL_HANDLE_NEXT ) return RTLD_NEXT; return lhandle->handle; } #endif struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags, int ra_init, struct roar_dl_librarypara * para) { struct roar_dl_lhandle * ret = NULL; int err; // early errors just return. if ( flags != ROAR_DL_FLAG_DEFAUTS ) { roar_err_set(ROAR_ERROR_NOTSUP); return NULL; } if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL ) return NULL; memset(ret, 0, sizeof(struct roar_dl_lhandle)); #if defined(ROAR_HAVE_LIBDL) flags = RTLD_NOW; #ifdef RTLD_DEEPBIND flags |= RTLD_DEEPBIND; #endif ret->handle = dlopen(filename, flags); if ( ret->handle == NULL ) { roar_mm_free(ret); return NULL; } #else roar_mm_free(ret); roar_err_set(ROAR_ERROR_NOSYS); return NULL; #endif ret->para = para; if ( ra_init ) { if ( roar_dl_ra_init(ret, NULL, para) == -1 ) { err = roar_error; ROAR_WARN("roar_dl_open(filename='%s', flags=%i, ra_init=%i, para=%p): Can not init RA lib: %s", filename, flags, ra_init, para, roar_error2str(err)); #if defined(ROAR_HAVE_LIBDL) dlclose(ret->handle); #endif roar_mm_free(ret); roar_error = err; return NULL; } } if ( para != NULL ) roar_dl_para_ref(para); return ret; } int roar_dl_close(struct roar_dl_lhandle * lhandle) { int ret = -1; if ( lhandle == ROAR_DL_HANDLE_DEFAULT || lhandle == ROAR_DL_HANDLE_NEXT ) { roar_err_set(ROAR_ERROR_BADFH); return -1; } if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) lhandle->lib->unload(lhandle->para, lhandle->lib); #if defined(ROAR_HAVE_LIBDL) ret = dlclose(_roardl2ldl(lhandle)); #else ret = -1; #endif if ( lhandle->para != NULL ) roar_dl_para_unref(lhandle->para); roar_mm_free(lhandle); return ret; } void * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) { #if defined(ROAR_HAVE_LIBDL) void * ret = dlsym(_roardl2ldl(lhandle), sym); (void)type; ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret); return ret; #else return NULL; #endif } int roar_dl_ra_init(struct roar_dl_lhandle * lhandle, const char * prefix, struct roar_dl_librarypara * para) { #define _SUFFIX "_roaraudio_library_init" char name[80] = _SUFFIX; struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para); struct roar_dl_libraryinst * lib; int i; if ( (void*)lhandle < (void*)128 ) { if ( prefix == NULL ) return -1; } else { if ( para == NULL ) para = lhandle->para; } if ( prefix != NULL ) { roar_mm_strscpy(name, "_"); roar_mm_strscat(name, prefix); roar_mm_strscat(name, _SUFFIX); } ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name); if ( (func = roar_dl_getsym(lhandle, name, -1)) == NULL ) return -1; ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func); lib = func(para); if ( lib == NULL ) return -1; if ( lib->version != ROAR_DL_LIBINST_VERSION ) return -1; if ( sizeof(struct roar_dl_libraryinst) > lib->len ) return -1; if ( !((void*)lhandle < (void*)128) ) { lhandle->lib = lib; } for (i = 0; i < ROAR_DL_FN_MAX; i++) { if ( lib->func[i] != NULL ) lib->func[i](para, lib); } return 0; } const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) { #if defined(ROAR_HAVE_LIBDL) (void)lhandle; return dlerror(); #else return NULL; #endif } struct roar_dl_librarypara * roar_dl_getpara(struct roar_dl_lhandle * lhandle) { if ( (void*)lhandle < (void*)128 ) { roar_err_set(ROAR_ERROR_NOTSUP); return NULL; } if ( lhandle->para == NULL ) { roar_err_set(ROAR_ERROR_NOENT); return NULL; } if ( roar_dl_para_ref(lhandle->para) == -1 ) return NULL; return lhandle->para; } const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) { if ( (void*)lhandle < (void*)128 ) { roar_err_set(ROAR_ERROR_NOTSUP); return NULL; } if ( lhandle->lib == NULL ) { roar_err_set(ROAR_ERROR_BADLIB); return NULL; } if ( lhandle->lib->libname == NULL ) { roar_err_set(ROAR_ERROR_NOENT); return NULL; } if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) { roar_err_set(ROAR_ERROR_BADVERSION); return NULL; } if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) { roar_err_set(ROAR_ERROR_HOLE); return NULL; } return lhandle->lib->libname; } //ll