source: roaraudio/roarclients/roarpluginrunner.c @ 5517:287ced72ce95

Last change on this file since 5517:287ced72ce95 was 5517:287ced72ce95, checked in by phi, 12 years ago

Fixed detection of dynamic loader on *BSD.

File size: 14.2 KB
Line 
1//roarpluginrunner.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2012
5 *
6 *  This file is part of roarclients a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26int g_verbose = 0;
27#define ROAR_DBG_INFOVAR g_verbose
28
29#include <roaraudio.h>
30
31enum action {
32 RUN,
33 RUN_AS_APPLICATION,
34 EXPLAIN
35};
36
37static struct roar_dl_librarypara * g_para = NULL;
38
39static void usage (const char * progname) {
40 fprintf(stderr, "Usage: %s [OPTIONS]... PLUGIN\n", progname);
41
42 fprintf(stderr, "\nOptions:\n\n");
43
44 fprintf(stderr, " -h --help               - This help.\n"
45                 " -v --verbose            - Be verbose. Can be used multiple times.\n"
46                 "    --server SERVER      - Set default server to SERVER.\n"
47                 "    --run                - Run plugin.\n"
48                 "    --run-as-application - Same as --run except all tailing arguments are\n"
49                 "                           passed to the plugin.\n"
50                 "    --explain            - Explain plugin.\n"
51                 "    --appname NAME       - Sets the appname.\n"
52                 "    --abiversion ABI     - Set the ABI version.\n"
53                 "    --args ARGS          - Set plugin arguments.\n"
54        );
55}
56
57static int do_run(const char * name) {
58 struct roar_plugincontainer * cont = roar_plugincontainer_new(g_para);
59 int err;
60
61 if ( cont == NULL )
62  return -1;
63
64 if ( roar_plugincontainer_load(cont, name, NULL) == -1 ) {
65  err = roar_error;
66  roar_plugincontainer_unref(cont);
67  roar_error = err;
68  return -1;
69 }
70
71 roar_plugincontainer_appsched_trigger(cont, ROAR_DL_APPSCHED_INIT);
72
73 while (roar_plugincontainer_appsched_trigger(cont, ROAR_DL_APPSCHED_WAIT) == 0)
74  roar_plugincontainer_appsched_trigger(cont, ROAR_DL_APPSCHED_UPDATE);
75
76 roar_plugincontainer_appsched_trigger(cont, ROAR_DL_APPSCHED_UPDATE);
77 roar_plugincontainer_appsched_trigger(cont, ROAR_DL_APPSCHED_FREE);
78
79 roar_plugincontainer_unref(cont);
80 return 0;
81}
82
83static const char * _ptr2str(const void * p) {
84#if defined(ROAR_HAVE_H_DLFCN) && defined(ROAR_HAVE_DLADDR)
85 static char buf[80];
86 Dl_info info;
87#else
88 static char buf[24];
89#endif
90
91 if ( p == NULL )
92  return "<not set>";
93
94#if defined(ROAR_HAVE_H_DLFCN) && defined(ROAR_HAVE_DLADDR)
95 if ( dladdr(p, &info) != 0 ) {
96  if ( p == info.dli_saddr ) {
97   snprintf(buf, sizeof(buf), "%p <%s in \"%s\">", p, info.dli_sname, info.dli_fname);
98   return buf;
99  }
100 }
101#endif
102
103 snprintf(buf, sizeof(buf), "%p", p);
104
105 return buf;
106}
107
108static const char * _ptrrange2str(const void * p, size_t len) {
109 static char buf[80];
110
111 if ( p == NULL )
112  return "<not set>";
113
114 if ( len == 0 )
115  return _ptr2str(p);
116
117 snprintf(buf, sizeof(buf), "%p-%p", p, p + len);
118
119 return buf;
120}
121
122static int do_explain(const char * name) {
123 struct roar_dl_lhandle * lhandle = roar_dl_open(name, ROAR_DL_FLAG_LAZY|ROAR_DL_FLAG_PLUGINPATH, 0, g_para);
124 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
125 struct roar_dl_libraryinst * lib;
126 int libok = 0, libnameok = 0, libdepok = 0;
127 int tmp;
128 int i;
129 size_t iter;
130 char c;
131
132 if ( lhandle == NULL )
133  return -1;
134
135 func = roar_dl_getsym(lhandle, "_roaraudio_library_init", -1);
136 if ( func == NULL ) {
137  fprintf(stderr, "Warning: Not a RA lib: %s\n", name);
138  roar_dl_unref(lhandle);
139  return 0;
140 }
141
142 lib = func(g_para);
143 if ( lib == NULL ) {
144  fprintf(stderr, "Warning: Can not RA init: %s: %s\n", name, roar_error2str(roar_error));
145  roar_dl_unref(lhandle);
146  return 0;
147 }
148
149 if ( lib->version == ROAR_DL_LIBINST_VERSION && lib->len == sizeof(*lib) ) {
150  libok = 1;
151 }
152
153 printf("lib                     = %s\n", _ptr2str(lib));
154 if ( g_verbose || !libok ) {
155  printf("|-> version             = %i (%smatch)\n", lib->version, lib->version == ROAR_DL_LIBINST_VERSION ? "" : "no ");
156  printf("%c-> len                 = %zu (%smatch)\n", libok ? '|' : '\\', lib->len, lib->len == sizeof(*lib) ? "" : "no ");
157 }
158
159 if ( libok ) {
160  if ( g_verbose || lib->unload != NULL )
161   printf("|-> unload              = %s\n", _ptr2str(lib->unload));
162  printf("|-> func                = {");
163  i = 0;
164  while (i < ROAR_DL_FN_MAX) {
165   for (tmp = 0; i < ROAR_DL_FN_MAX; i++) {
166    if ( lib->func[i] != NULL ) {
167     break;
168    }
169    tmp++;
170   }
171   if (tmp)
172    printf("%i x <not set>%s", tmp, i < (ROAR_DL_FN_MAX-1) ? ", " : "");
173
174   if ( i < ROAR_DL_FN_MAX ) {
175    printf("[%i] = %s%s", i, _ptr2str(lib->func[i]), i < (ROAR_DL_FN_MAX-1) ? ", " : "");
176    i++;
177   }
178  }
179
180  printf("}\n");
181  printf("|-> libname             = %s\n", _ptr2str(lib->libname));
182  if ( lib->libname != NULL ) {
183   if ( lib->libname->version == ROAR_DL_LIBNAME_VERSION && lib->libname->len == sizeof(*(lib->libname)) ) {
184    libnameok = 1;
185   }
186   if ( g_verbose || !libnameok ) {
187    printf("|   |-> version         = %i (%smatch)\n", lib->libname->version,
188                                                       lib->libname->version == ROAR_DL_LIBNAME_VERSION ? "" : "no ");
189    printf("|   %c-> len             = %zu (%smatch)\n", libnameok ? '|' : '\\', lib->libname->len,
190                                                         lib->libname->len == sizeof(*(lib->libname)) ? "" : "no ");
191   }
192
193   if ( libnameok ) {
194#define _ps(k,name) \
195    tmp = (lib->libname->name) != NULL; \
196    if ( tmp || g_verbose || (k) == '\\' ) \
197    printf("|   %c-> %-15s = %s%s%s\n", (k), #name, tmp ? "\"" : "", \
198                                    tmp ? (lib->libname->name) : "<not set>", tmp ? "\"" : "");
199
200    _ps('|', name);
201    _ps('|', libname);
202    _ps('|', libversion);
203    _ps('|', abiversion);
204    _ps('|', description);
205    _ps('|', contact);
206    _ps('|', authors);
207    _ps('\\', license);
208#undef _ps
209   }
210  }
211  if ( g_verbose || lib->global_data_pointer != NULL )
212   printf("|-> global_data_len     = %zu\n", lib->global_data_len);
213  if ( g_verbose || lib->global_data_init != NULL )
214   printf("|-> global_data_init    = %s\n", _ptrrange2str(lib->global_data_init, lib->global_data_len));
215  if ( g_verbose || lib->global_data_pointer != NULL )
216   printf("|-> global_data_pointer = %s\n", _ptr2str(lib->global_data_pointer));
217
218  if ( lib->libdep != NULL && lib->libdep_len ) {
219   printf("|-> libdep              = %s\n", _ptr2str(lib->libdep));
220   for (iter = 0; iter < lib->libdep_len; iter++) {
221    printf("|   %c-> Table entry %zu   = %p\n", iter == (lib->libdep_len-1) ? '\\' : '|', iter, &(lib->libdep[iter]));
222    c = iter == (lib->libdep_len-1) ? ' ' : '|';
223    if ( lib->libdep[iter].version == ROAR_DL_LIBDEP_VERSION &&
224         lib->libdep[iter].len     == sizeof(struct roar_dl_librarydep) ) {
225     libdepok = 1;
226    } else {
227     libdepok = 0;
228    }
229    if ( g_verbose || !libdepok ) {
230     printf("|   %c   |-> version     = %i (%smatch)\n", c, lib->libdep[iter].version,
231                                                         lib->libdep[iter].version == ROAR_DL_LIBDEP_VERSION ? "" : "no ");
232     printf("|   %c   %c-> len         = %zu (%smatch)\n", c, libdepok ? '|' : '\\',
233                                                        lib->libdep[iter].len,
234                                                        lib->libdep[iter].len == sizeof(struct roar_dl_librarydep) ?
235                                                        "" : "no ");
236    }
237
238    if ( libdepok ) {
239     printf("|   %c   |-> flags       = 0x%.8lX\n", c, (unsigned long int)lib->libdep[iter].flags);
240#define _ps(k,name) \
241    tmp = (lib->libdep[iter].name) != NULL; \
242    if ( tmp || g_verbose || (k) == '\\' ) \
243    printf("|   %c   %c-> %-11s = %s%s%s\n", c, (k), #name, tmp ? "\"" : "", \
244                                    tmp ? (lib->libdep[iter].name) : "<not set>", tmp ? "\"" : "");
245     _ps('|', name);
246     _ps('|', libname);
247     _ps('\\', abiversion);
248#undef _ps
249    }
250   }
251   printf("|-> libdep_len          = %zu\n", lib->libdep_len);
252  } else if ( (lib->libdep == NULL && lib->libdep_len) || (lib->libdep != NULL && !lib->libdep_len) ) {
253   printf("|-> libdep              = %s (invalid)\n", _ptr2str(lib->libdep));
254   printf("|-> libdep_len          = %zu (invalid)\n", lib->libdep_len);
255  }
256  if ( g_verbose || lib->appsched != NULL ) {
257   printf("|-> appsched            = %s\n", _ptr2str(lib->appsched));
258   if ( lib->appsched != NULL ) {
259    if ( g_verbose || lib->appsched->init != NULL )
260     printf("|   |-> init            = %s\n", _ptr2str(lib->appsched->init));
261    if ( g_verbose || lib->appsched->free != NULL )
262     printf("|   |-> free            = %s\n", _ptr2str(lib->appsched->free));
263    if ( g_verbose || lib->appsched->update != NULL )
264     printf("|   |-> update          = %s\n", _ptr2str(lib->appsched->update));
265    if ( g_verbose || lib->appsched->tick != NULL )
266     printf("|   |-> tick            = %s\n", _ptr2str(lib->appsched->tick));
267    printf("|   \\-> wait            = %s\n", _ptr2str(lib->appsched->wait));
268   }
269  }
270#define _ps(k,name) \
271    tmp = (lib->name) != NULL; \
272    if ( tmp || g_verbose || (k) == '\\' ) \
273    printf("%c-> %-19s = %s%s%s\n", (k), #name, tmp ? "\"" : "", \
274                                    tmp ? (lib->name) : "<not set>", tmp ? "\"" : "");
275  _ps('|', host_appname);
276  _ps('\\', host_abiversion);
277#undef _ps
278 }
279
280 roar_dl_unref(lhandle);
281 return 0;
282}
283
284static int do_plugin(enum action action, const char * name) {
285 switch (action) {
286  case EXPLAIN:
287    return do_explain(name);
288   break;
289  case RUN:
290  case RUN_AS_APPLICATION:
291    return do_run(name);
292   break;
293  default:
294    roar_err_set(ROAR_ERROR_BADRQC);
295    return -1;
296   break;
297 }
298}
299
300static inline void _clear_para(void) {
301 if ( g_para == NULL )
302  return;
303
304 roar_dl_para_unref(g_para);
305 g_para = NULL;
306}
307
308static inline int _add_para(struct roar_dl_librarypara * para, const char * pluginargs, size_t argc, char * argv[]) {
309 struct roar_keyval * kv;
310 ssize_t argslen, argvlen;
311 ssize_t arglen;
312 ssize_t pluginargc;
313 size_t argv_phys = argc;
314 size_t i;
315 int error;
316 char * sp, * c;
317 int after_parser_end;
318
319 if ( pluginargs == NULL )
320  pluginargs = "";
321
322 argslen = roar_mm_strlen(pluginargs) + 1 /* tailing '\0' */;
323
324 after_parser_end = 0;
325 argvlen = 0;
326 for (i = 0; i < argv_phys; i++) {
327  arglen   = roar_mm_strlen(argv[i]);
328  argvlen += arglen;
329  if ( !after_parser_end ) {
330   if ( !strcmp(argv[i], "--") ) {
331    after_parser_end = 1;
332    argc--;
333   } else if ( arglen > 1 && argv[i][0] == '-' && !(arglen > 2 && argv[i][1] == '-') ) {
334    argc += arglen - 2;
335   }
336  }
337 }
338 argvlen += argc; // the '\0's.
339
340 para->args_store = roar_mm_malloc(argslen+argvlen);
341 if ( para == NULL )
342  return -1;
343
344 memcpy(para->args_store, pluginargs, argslen);
345
346 pluginargc = roar_keyval_split(&kv, para->args_store, NULL, NULL, 1);
347 if ( pluginargc == -1 ) {
348  error = roar_error;
349  roar_mm_free(para->args_store);
350  para->args_store = NULL;
351  roar_error = error;
352  return -1;
353 }
354
355 para->argv = roar_mm_malloc((pluginargc+argc)*sizeof(struct roar_keyval));
356 if ( para->argv == NULL ) {
357  error = roar_error;
358  roar_mm_free(kv);
359  roar_mm_free(para->args_store);
360  para->args_store = NULL;
361  roar_error = error;
362  return -1;
363 }
364
365 para->argc = pluginargc + argc;
366
367 memcpy(para->argv, kv, pluginargc*sizeof(struct roar_keyval));
368 roar_mm_free(kv);
369
370 sp = para->args_store + argslen;
371 kv = para->argv + pluginargc;
372
373 after_parser_end = 0;
374 for (i = 0; i < argv_phys; i++) {
375  arglen = roar_mm_strlen(argv[i]) + 1;
376  if ( after_parser_end || !(arglen > 2 && argv[i][0] == '-' && !(arglen > 3 && argv[i][1] == '-')) )
377   memcpy(sp, argv[i], arglen);
378
379  if ( !after_parser_end && !strcmp(argv[i], "--") ) {
380   after_parser_end = 1;
381   continue;
382  } else if ( !after_parser_end && arglen > 3 && sp[0] == '-' && sp[1] == '-' ) {
383   kv->key = sp + 2;
384   kv->value = NULL;
385   for (c = sp + 2; *c; c++) {
386    if (*c == '=') {
387     *c = 0;
388     c++;
389     kv->value = c;
390     break;
391    }
392   }
393  } else if ( !after_parser_end && arglen > 2 && argv[i][0] == '-' ) {
394   for (c = argv[i] + 1; *c; c++) {
395    printf("*c=%c\n", *c);
396    sp[0] = *c;
397    sp[1] = 0;
398    kv->key = sp;
399    kv->value = NULL;
400    sp += 2;
401    kv++;
402   }
403   continue;
404  } else {
405   kv->key = NULL;
406   kv->value = sp;
407  }
408
409  sp += arglen;
410  kv++;
411 }
412
413 return 0;
414}
415
416int main (int argc, char * argv[]) {
417 const char * appname    = "roarpluginrunner " ROAR_VSTR_ROARAUDIO;
418 const char * abiversion = "1.0beta0";
419 const char * pluginargs = NULL;
420 enum action action = RUN;
421 int ret = 0;
422 int i;
423 char * k;
424
425 for (i = 1; i < argc; i++) {
426  k = argv[i];
427
428  if ( !strcmp(k, "-h") || !strcmp(k, "--help") ) {
429   usage(argv[0]);
430   return 0;
431  } else if ( !strcmp(k, "--run") ) {
432   action = RUN;
433  } else if ( !strcmp(k, "--run-as-application") ) {
434   action = RUN_AS_APPLICATION;
435  } else if ( !strcmp(k, "--explain") ) {
436   action = EXPLAIN;
437  } else if ( !strcmp(k, "-v") || !strcmp(k, "--verbose") ) {
438   g_verbose++;
439  } else if ( !strcmp(k, "--server") ) {
440   roar_libroar_set_server(argv[++i]);
441  } else if ( !strcmp(k, "--appname") ) {
442   appname = argv[++i];
443   _clear_para();
444  } else if ( !strcmp(k, "--abiversion") ) {
445   abiversion = argv[++i];
446   _clear_para();
447  } else if ( !strcmp(k, "--args") ) {
448   pluginargs = argv[++i];
449   _clear_para();
450  } else {
451   if ( g_para == NULL )
452    g_para = roar_dl_para_new(action == RUN_AS_APPLICATION ? NULL : pluginargs, NULL, appname, abiversion);
453   if ( action == RUN_AS_APPLICATION && _add_para(g_para, pluginargs, argc - i - 1, &(argv[i+1])) == -1 ) {
454    fprintf(stderr, "Error parsing plugin arguments: %s\n", roar_error2str(roar_error));
455   } else {
456    roar_err_set(ROAR_ERROR_NONE);
457    if ( do_plugin(action, k) == -1 ) {
458     fprintf(stderr, "Error loading plugin: %s\n",
459                     roar_error != ROAR_ERROR_NONE ? roar_error2str(roar_error) : roar_dl_errstr(NULL));
460     ret = 1;
461    }
462   }
463   if ( action == RUN_AS_APPLICATION )
464    break; // end looping over arguments
465  }
466 }
467
468 _clear_para();
469
470 return ret;
471}
472
473//ll
Note: See TracBrowser for help on using the repository browser.