//roarpluginrunner.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2012 * * This file is part of roarclients 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. * * RoarAudio 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. * */ int g_verbose = 0; #define ROAR_DBG_INFOVAR g_verbose #include enum action { RUN, EXPLAIN }; static struct roar_dl_librarypara * g_para = NULL; static void usage (const char * progname) { fprintf(stderr, "Usage: %s [OPTIONS]... PLUGIN\n", progname); fprintf(stderr, "\nOptions:\n\n"); fprintf(stderr, " -h --help - This help.\n" " -v --verbose - Be verbose. Can be used multiple times.\n" " --server SERVER - Set default server to SERVER.\n" " --run - Run plugin.\n" " --explain - Explain plugin.\n" " --appname NAME - Sets the appname.\n" " --abiversion ABI - Set the ABI version.\n" " --args ARGS - Set plugin arguments.\n" ); } static int do_run(const char * name) { struct roar_dl_lhandle * lhandle = roar_dl_open(name, ROAR_DL_FLAG_DEFAULTS, 1, g_para); if ( lhandle == NULL ) return -1; roar_dl_appsched_trigger(lhandle, ROAR_DL_APPSCHED_INIT); while (roar_dl_appsched_trigger(lhandle, ROAR_DL_APPSCHED_WAIT) == 0) roar_dl_appsched_trigger(lhandle, ROAR_DL_APPSCHED_UPDATE); roar_dl_appsched_trigger(lhandle, ROAR_DL_APPSCHED_UPDATE); roar_dl_appsched_trigger(lhandle, ROAR_DL_APPSCHED_FREE); roar_dl_unref(lhandle); return 0; } static const char * _ptr2str(const void * p) { #if defined(ROAR_HAVE_LIBDL) && defined(ROAR_HAVE_DLADDR) static char buf[80]; Dl_info info; #else static char buf[24]; #endif if ( p == NULL ) return ""; #if defined(ROAR_HAVE_LIBDL) && defined(ROAR_HAVE_DLADDR) if ( dladdr(p, &info) != 0 ) { if ( p == info.dli_saddr ) { snprintf(buf, sizeof(buf), "%p <%s in \"%s\">", p, info.dli_sname, info.dli_fname); return buf; } } #endif snprintf(buf, sizeof(buf), "%p", p); return buf; } static const char * _ptrrange2str(const void * p, size_t len) { static char buf[80]; if ( p == NULL ) return ""; if ( len == 0 ) return _ptr2str(p); snprintf(buf, sizeof(buf), "%p-%p", p, p + len); return buf; } static int do_explain(const char * name) { struct roar_dl_lhandle * lhandle = roar_dl_open(name, ROAR_DL_FLAG_LAZY, 0, NULL); struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para); struct roar_dl_libraryinst * lib; int libok = 0, libnameok = 0, libdepok = 0; int tmp; int i; size_t iter; char c; if ( lhandle == NULL ) return -1; func = roar_dl_getsym(lhandle, "_roaraudio_library_init", -1); if ( func == NULL ) { fprintf(stderr, "Warning: Not a RA lib: %s\n", name); roar_dl_unref(lhandle); return 0; } lib = func(g_para); if ( lib == NULL ) { fprintf(stderr, "Warning: Can not RA init: %s: %s\n", name, roar_error2str(roar_error)); roar_dl_unref(lhandle); return 0; } if ( lib->version == ROAR_DL_LIBINST_VERSION && lib->len == sizeof(*lib) ) { libok = 1; } printf("lib = %s\n", _ptr2str(lib)); if ( g_verbose || !libok ) { printf("|-> version = %i (%smatch)\n", lib->version, lib->version == ROAR_DL_LIBINST_VERSION ? "" : "no "); printf("%c-> len = %zu (%smatch)\n", libok ? '|' : '\\', lib->len, lib->len == sizeof(*lib) ? "" : "no "); } if ( libok ) { if ( g_verbose || lib->unload != NULL ) printf("|-> unload = %s\n", _ptr2str(lib->unload)); printf("|-> func = {"); i = 0; while (i < ROAR_DL_FN_MAX) { for (tmp = 0; i < ROAR_DL_FN_MAX; i++) { if ( lib->func[i] != NULL ) { break; } tmp++; } if (tmp) printf("%i x %s", tmp, i < (ROAR_DL_FN_MAX-1) ? ", " : ""); if ( i < ROAR_DL_FN_MAX ) { printf("[%i] = %s%s", i, _ptr2str(lib->func[i]), i < (ROAR_DL_FN_MAX-1) ? ", " : ""); i++; } } printf("}\n"); printf("|-> libname = %s\n", _ptr2str(lib->libname)); if ( lib->libname != NULL ) { if ( lib->libname->version == ROAR_DL_LIBNAME_VERSION && lib->libname->len == sizeof(*(lib->libname)) ) { libnameok = 1; } if ( g_verbose || !libnameok ) { printf("| |-> version = %i (%smatch)\n", lib->libname->version, lib->libname->version == ROAR_DL_LIBNAME_VERSION ? "" : "no "); printf("| %c-> len = %zu (%smatch)\n", libnameok ? '|' : '\\', lib->libname->len, lib->libname->len == sizeof(*(lib->libname)) ? "" : "no "); } if ( libnameok ) { #define _ps(k,name) \ tmp = (lib->libname->name) != NULL; \ if ( tmp || g_verbose || (k) == '\\' ) \ printf("| %c-> %-15s = %s%s%s\n", (k), #name, tmp ? "\"" : "", \ tmp ? (lib->libname->name) : "", tmp ? "\"" : ""); _ps('|', name); _ps('|', libname); _ps('|', libversion); _ps('|', abiversion); _ps('|', description); _ps('|', contact); _ps('|', authors); _ps('\\', license); #undef _ps } } if ( g_verbose || lib->global_data_pointer != NULL ) printf("|-> global_data_len = %zu\n", lib->global_data_len); if ( g_verbose || lib->global_data_init != NULL ) printf("|-> global_data_init = %s\n", _ptrrange2str(lib->global_data_init, lib->global_data_len)); if ( g_verbose || lib->global_data_pointer != NULL ) printf("|-> global_data_pointer = %s\n", _ptr2str(lib->global_data_pointer)); if ( lib->libdep != NULL && lib->libdep_len ) { printf("|-> libdep = %s\n", _ptr2str(lib->libdep)); for (iter = 0; iter < lib->libdep_len; iter++) { printf("| %c-> Table entry %zu = %p\n", iter == (lib->libdep_len-1) ? '\\' : '|', iter, &(lib->libdep[iter])); c = iter == (lib->libdep_len-1) ? ' ' : '|'; if ( lib->libdep[iter].version == ROAR_DL_LIBDEP_VERSION && lib->libdep[iter].len == sizeof(struct roar_dl_librarydep) ) { libdepok = 1; } else { libdepok = 0; } if ( g_verbose || !libdepok ) { printf("| %c |-> version = %i (%smatch)\n", c, lib->libdep[iter].version, lib->libdep[iter].version == ROAR_DL_LIBDEP_VERSION ? "" : "no "); printf("| %c %c-> len = %zu (%smatch)\n", c, libdepok ? '|' : '\\', lib->libdep[iter].len, lib->libdep[iter].len == sizeof(struct roar_dl_librarydep) ? "" : "no "); } if ( libdepok ) { printf("| %c |-> flags = 0x%.8lX\n", c, (unsigned long int)lib->libdep[iter].flags); #define _ps(k,name) \ tmp = (lib->libdep[iter].name) != NULL; \ if ( tmp || g_verbose || (k) == '\\' ) \ printf("| %c %c-> %-11s = %s%s%s\n", c, (k), #name, tmp ? "\"" : "", \ tmp ? (lib->libdep[iter].name) : "", tmp ? "\"" : ""); _ps('|', name); _ps('|', libname); _ps('\\', abiversion); #undef _ps } } printf("|-> libdep_len = %zu\n", lib->libdep_len); } else if ( (lib->libdep == NULL && lib->libdep_len) || (lib->libdep != NULL && !lib->libdep_len) ) { printf("|-> libdep = %s (invalid)\n", _ptr2str(lib->libdep)); printf("|-> libdep_len = %zu (invalid)\n", lib->libdep_len); } if ( g_verbose || lib->appsched != NULL ) { printf("|-> appsched = %s\n", _ptr2str(lib->appsched)); if ( lib->appsched != NULL ) { if ( g_verbose || lib->appsched->init != NULL ) printf("| |-> init = %s\n", _ptr2str(lib->appsched->init)); if ( g_verbose || lib->appsched->free != NULL ) printf("| |-> free = %s\n", _ptr2str(lib->appsched->free)); if ( g_verbose || lib->appsched->update != NULL ) printf("| |-> update = %s\n", _ptr2str(lib->appsched->update)); if ( g_verbose || lib->appsched->tick != NULL ) printf("| |-> tick = %s\n", _ptr2str(lib->appsched->tick)); printf("| \\-> wait = %s\n", _ptr2str(lib->appsched->wait)); } } #define _ps(k,name) \ tmp = (lib->name) != NULL; \ if ( tmp || g_verbose || (k) == '\\' ) \ printf("%c-> %-19s = %s%s%s\n", (k), #name, tmp ? "\"" : "", \ tmp ? (lib->name) : "", tmp ? "\"" : ""); _ps('|', host_appname); _ps('\\', host_abiversion); #undef _ps } roar_dl_unref(lhandle); return 0; } static int do_plugin(enum action action, const char * name) { switch (action) { case EXPLAIN: return do_explain(name); break; case RUN: return do_run(name); break; default: roar_err_set(ROAR_ERROR_BADRQC); return -1; break; } } static inline void _clear_para(void) { if ( g_para == NULL ) return; roar_dl_para_unref(g_para); g_para = NULL; } int main (int argc, char * argv[]) { const char * appname = "roarpluginrunner " ROAR_VSTR_ROARAUDIO; const char * abiversion = "1.0beta0"; const char * pluginargs = NULL; enum action action = RUN; int ret = 0; int i; char * k; for (i = 1; i < argc; i++) { k = argv[i]; if ( !strcmp(k, "-h") || !strcmp(k, "--help") ) { usage(argv[0]); return 0; } else if ( !strcmp(k, "--run") ) { action = RUN; } else if ( !strcmp(k, "--explain") ) { action = EXPLAIN; } else if ( !strcmp(k, "-v") || !strcmp(k, "--verbose") ) { g_verbose++; } else if ( !strcmp(k, "--server") ) { roar_libroar_set_server(argv[++i]); } else if ( !strcmp(k, "--appname") ) { appname = argv[++i]; _clear_para(); } else if ( !strcmp(k, "--abiversion") ) { abiversion = argv[++i]; _clear_para(); } else if ( !strcmp(k, "--args") ) { pluginargs = argv[++i]; _clear_para(); } else { if ( g_para == NULL ) g_para = roar_dl_para_new(pluginargs, NULL, appname, abiversion); roar_err_set(ROAR_ERROR_NONE); if ( do_plugin(action, k) == -1 ) { fprintf(stderr, "Error loading plugin: %s\n", roar_error != ROAR_ERROR_NONE ? roar_error2str(roar_error) : roar_dl_errstr(NULL)); ret = 1; } } } _clear_para(); return ret; } //ll