source: roaraudio/libroar/roardl.c @ 5347:1d76e45ebfd1

Last change on this file since 5347:1d76e45ebfd1 was 5347:1d76e45ebfd1, checked in by phi, 12 years ago

added some support and handling code for libdeps. currently it can be parsed and if there is libdep info in a file loading is canceled because we can not load additional stuff at the moment

File size: 15.4 KB
RevLine 
[3297]1//roardl.c:
2
3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
[3297]5 *
6 *  This file is part of libroar 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 *  libroar 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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[3297]23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
[3367]38#if defined(ROAR_HAVE_LIBDL) && !defined(RTLD_NEXT)
39#define RTLD_NEXT ((void *) -1L)
40#endif
41
[5275]42struct roar_dl_lhandle {
[5317]43 size_t refc; // currently unused.
44 int flags;
45 char * libname; // only used for ROAR_DL_FLAG_STATIC.
[5275]46 struct roar_dl_librarypara * para;
47 struct roar_dl_libraryinst * lib;
[5312]48 struct {
49  struct roar_error_state error_state;
50  void *  global_data;
51  void *  global_data_state;
[5317]52  struct roar_notify_core * notifycore;
[5312]53 } context;
[5275]54#if defined(ROAR_HAVE_LIBDL)
55 void * handle;
56#endif
57};
58
59
60struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
61                                              const char * appname, const char * abiversion) {
62 struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara));
63 ssize_t argc;
64 int err;
65
66 if ( ret == NULL )
67  return NULL;
68
69 memset(ret, 0, sizeof(struct roar_dl_librarypara));
70
71 ret->version    = ROAR_DL_LIBPARA_VERSION;
72 ret->len        = sizeof(struct roar_dl_librarypara);
73 ret->refc       = 1;
74 ret->argc       = 0;
75 ret->argv       = NULL;
76 ret->args_store = NULL;
77 ret->binargv    = binargv;
78 ret->appname    = appname;
79 ret->abiversion = abiversion;
80
81 if ( args != NULL ) {
82  ret->args_store = roar_mm_strdup(args);
83  if ( ret->args_store == NULL ) {
84   err = roar_error;
85   roar_mm_free(ret);
86   roar_error = err;
87   return NULL;
88  }
89
90  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 0);
91  if ( argc == -1 ) {
92   err = roar_error;
93   roar_mm_free(ret->args_store);
94   roar_mm_free(ret);
95   roar_error = err;
96   return NULL;
97  }
98
99  ret->argc = argc;
100 }
101
102 return ret;
103}
104
105int roar_dl_para_ref                    (struct roar_dl_librarypara * para) {
106 if ( para == NULL ) {
107  roar_err_set(ROAR_ERROR_FAULT);
108  return -1;
109 }
110
111 para->refc++;
112
113 return 0;
114}
115
116int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
117 if ( para == NULL ) {
118  roar_err_set(ROAR_ERROR_FAULT);
119  return -1;
120 }
121
122 para->refc--;
123
[5317]124 if ( para->refc )
125  return 0;
126
127 if ( para->notifycore != NULL )
128  roar_notify_core_unref(para->notifycore);
129
130 if ( para->args_store != NULL ) {
131  roar_mm_free(para->args_store);
132  roar_mm_free(para->argv);
[5275]133 }
134
[5317]135 roar_mm_free(para);
136
[5275]137 return 0;
138}
139int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
140                                         const char * appname, const char * abiversion) {
141 if ( para == NULL ) {
142  roar_err_set(ROAR_ERROR_FAULT);
143  return -1;
144 }
145
146 // check if both appnames are NULL or non-NULL.
147 if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) {
148  roar_err_set(ROAR_ERROR_BADVERSION);
149  return -1;
150 }
151
152 // check if the appname matches if given.
153 if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
154  roar_err_set(ROAR_ERROR_BADVERSION);
155  return -1;
156 }
157
158 // check if both ABI versions are NULL or non-NULL.
159 if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) {
160  roar_err_set(ROAR_ERROR_BADVERSION);
161  return -1;
162 }
163
164 // check if the ABI versions matches if given.
165 if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) {
166  roar_err_set(ROAR_ERROR_BADVERSION);
167  return -1;
168 }
169
170 return 0;
171}
172
173
[3297]174#if defined(ROAR_HAVE_LIBDL)
175static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
[5317]176 ROAR_DBG("_roardl2ldl(lhandle=%p) = ?", lhandle);
177
178 if ( lhandle == ROAR_DL_HANDLE_DEFAULT ) {
179  ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_DEFAULT);
[3297]180  return RTLD_DEFAULT;
[5317]181 }
[3297]182
[5317]183 if ( lhandle == ROAR_DL_HANDLE_NEXT ) {
184  ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_NEXT);
[3297]185  return RTLD_NEXT;
[5317]186 }
[3297]187
[5317]188 ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)(lhandle->handle));
[3297]189 return lhandle->handle;
190}
191#endif
192
[5275]193struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
194                                      int ra_init, struct roar_dl_librarypara * para) {
[3298]195 struct roar_dl_lhandle * ret = NULL;
[5317]196#if defined(ROAR_HAVE_LIBDL)
197#ifdef RTLD_DEEPBIND
[5344]198 int libdl_flags = RTLD_DEEPBIND;
[5317]199#else
[5344]200 int libdl_flags = 0;
[5317]201#endif
202#endif
[5275]203 int err;
[3298]204
[5317]205 if ( flags == ROAR_DL_FLAG_DEFAULTS )
206  flags = ROAR_DL_FLAG_NONE;
[3304]207
[5344]208#if defined(ROAR_HAVE_LIBDL)
209 if ( flags & ROAR_DL_FLAG_LAZY ) {
210  libdl_flags |= RTLD_LAZY;
211 } else {
212  libdl_flags |= RTLD_NOW;
213 }
214#endif
215
[3304]216 if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
217  return NULL;
218
219 memset(ret, 0, sizeof(struct roar_dl_lhandle));
220
[5312]221 roar_err_initstore(&(ret->context.error_state));
222
[5317]223 ret->flags = flags;
[5321]224 ret->refc  = 1;
[3366]225
[5317]226 if ( flags & ROAR_DL_FLAG_STATIC ) {
227  if ( filename == NULL ) {
228   ret->libname = NULL;
229  } else {
230   ret->libname = roar_mm_strdup(filename);
231  }
232 } else {
233#if defined(ROAR_HAVE_LIBDL)
234  ret->handle = dlopen(filename, libdl_flags);
[3304]235
[5317]236  if ( ret->handle == NULL ) {
237   ROAR_DBG("roar_dl_open(filename='%s', flags=%i, ra_init=%i, para=%p): Can not load library: %s", filename, flags, ra_init, para, roar_dl_errstr(ret));
238   roar_mm_free(ret);
239   return NULL;
240  }
[3304]241#else
[5317]242  roar_mm_free(ret);
243  roar_err_set(ROAR_ERROR_NOSYS);
244  return NULL;
[3304]245#endif
[5317]246 }
[3304]247
[5275]248 ret->para = para;
[3298]249
250 if ( ra_init ) {
[5275]251  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
252   err = roar_error;
253   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));
254#if defined(ROAR_HAVE_LIBDL)
[5317]255   if ( ret->handle != NULL )
256    dlclose(ret->handle);
[5275]257#endif
258   roar_mm_free(ret);
259   roar_error = err;
260   return NULL;
261  }
[3298]262 }
263
[5275]264 if ( para != NULL )
265  roar_dl_para_ref(para);
266
[3298]267 return ret;
[3297]268}
269
[5321]270int                      roar_dl_ref    (struct roar_dl_lhandle * lhandle) {
271 if ( (void*)lhandle < (void*)128 ) {
[5275]272  roar_err_set(ROAR_ERROR_BADFH);
[3301]273  return -1;
[5275]274 }
[3301]275
[5321]276 lhandle->refc++;
277
278 return 0;
279}
280
281int                      roar_dl_unref  (struct roar_dl_lhandle * lhandle) {
282 int ret = -1;
283
284 if ( (void*)lhandle < (void*)128 ) {
285  roar_err_set(ROAR_ERROR_BADFH);
286  return -1;
287 }
288
289 lhandle->refc++;
290
291 if ( lhandle->refc )
292  return 0;
293
[5317]294 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) {
295  roar_dl_context_restore(lhandle);
[3301]296  lhandle->lib->unload(lhandle->para, lhandle->lib);
[5317]297  roar_dl_context_store(lhandle);
298 }
[3301]299
[3297]300#if defined(ROAR_HAVE_LIBDL)
[5317]301 if ( lhandle->handle == NULL ) {
302  ret = 0;
303 } else {
304  ret = dlclose(_roardl2ldl(lhandle));
305 }
[3297]306#else
[3304]307 ret = -1;
[3297]308#endif
[3304]309
[5312]310 if ( lhandle->context.global_data != NULL )
311  roar_mm_free(lhandle->context.global_data);
312
[5275]313 if ( lhandle->para != NULL )
314  roar_dl_para_unref(lhandle->para);
315
[5317]316 if ( lhandle->libname != NULL )
317  roar_mm_free(lhandle->libname);
318
[3304]319 roar_mm_free(lhandle);
320
321 return ret;
[3297]322}
323
324void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
325#if defined(ROAR_HAVE_LIBDL)
[3776]326 void * ret = dlsym(_roardl2ldl(lhandle), sym);
327
[5270]328 (void)type;
329
[5317]330 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i): errno=%s, dlerror()='%s'", lhandle, sym, type, ret, strerror(errno), dlerror());
[3776]331 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
332
333 return ret;
[3297]334#else
[5317]335 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = NULL // errno=NOSYS", lhandle, sym, type, ret);
336 roar_err_set(ROAR_ERROR_NOSYS);
[3297]337 return NULL;
338#endif
339}
340
[5275]341int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
342                                         const char * prefix,
343                                         struct roar_dl_librarypara * para) {
[3297]344#define _SUFFIX "_roaraudio_library_init"
345 char name[80] = _SUFFIX;
346 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
347 struct roar_dl_libraryinst * lib;
[5317]348 struct roar_dl_lhandle     * getsymhandle = lhandle;
[5312]349 void * global_data_state = NULL;
[3300]350 int i;
[3297]351
[3305]352 if ( (void*)lhandle < (void*)128 ) {
353  if ( prefix == NULL )
354   return -1;
355 } else {
[5317]356  if ( prefix == NULL )
357   prefix = lhandle->libname;
358
[5275]359  if ( para == NULL )
360   para = lhandle->para;
[5317]361
362  if ( lhandle->flags & ROAR_DL_FLAG_STATIC )
363   getsymhandle = ROAR_DL_HANDLE_DEFAULT;
[3305]364 }
365
[3297]366
367 if ( prefix != NULL ) {
[5008]368  roar_mm_strscpy(name, "_");
369  roar_mm_strscat(name, prefix);
370  roar_mm_strscat(name, _SUFFIX);
[3297]371 }
372
[3307]373 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
374
[5317]375 if ( (func = roar_dl_getsym(getsymhandle, name, -1)) == NULL ) {
376  ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s') = -1", lhandle, prefix);
[3297]377  return -1;
[5317]378 }
[3297]379
[3307]380 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
381
[3300]382 lib = func(para);
[3297]383
384 if ( lib == NULL )
385  return -1;
386
[3300]387 if ( lib->version != ROAR_DL_LIBINST_VERSION )
388  return -1;
389
390 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
391  return -1;
392
[5347]393 if ( (lib->libdep == NULL && lib->libdep_len) || (lib->libdep != NULL && !lib->libdep_len) ) {
394  roar_err_set(ROAR_ERROR_BADLIB);
395  return -1;
396 }
397
398 if ( lib->libdep != NULL && lib->libdep_len ) {
399  // dynamic loader infos are currently not supported.
400  roar_err_set(ROAR_ERROR_NOTSUP);
401  return -1;
402 }
403
[3361]404 if ( !((void*)lhandle < (void*)128) ) {
405  lhandle->lib = lib;
[5312]406
407  if ( lib->global_data_len ) {
408   lhandle->context.global_data = roar_mm_malloc(lib->global_data_len);
409   if ( lhandle->context.global_data == NULL )
410    return -1;
411
412   if ( lib->global_data_init == NULL ) {
413    memset(lhandle->context.global_data, 0, lib->global_data_len);
414   } else {
415    memcpy(lhandle->context.global_data, lib->global_data_init, lib->global_data_len);
416   }
417  }
418 }
419
420 if ( lib->global_data_pointer != NULL ) {
421  global_data_state = *(lib->global_data_pointer);
[5313]422  if ( (void*)lhandle < (void*)128 ) {
[5312]423   *(lib->global_data_pointer) = lib->global_data_init;
424  } else {
425   *(lib->global_data_pointer) = lhandle->context.global_data;
426  }
[3361]427 }
428
[3300]429 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
430  if ( lib->func[i] != NULL )
431   lib->func[i](para, lib);
432 }
433
[5312]434 if ( lib->global_data_pointer != NULL ) {
[5313]435  if ( !((void*)lhandle < (void*)128) ) {
436   *(lib->global_data_pointer) = global_data_state;
437  }
[5312]438 }
439
[3302]440 return 0;
[3297]441}
442
[5275]443const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
[3364]444#if defined(ROAR_HAVE_LIBDL)
[5270]445 (void)lhandle;
[3364]446 return dlerror();
447#else
448 return NULL;
449#endif
450}
451
[5275]452struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
453 if ( (void*)lhandle < (void*)128 ) {
454  roar_err_set(ROAR_ERROR_NOTSUP);
455  return NULL;
456 }
457
458 if ( lhandle->para == NULL ) {
459  roar_err_set(ROAR_ERROR_NOENT);
460  return NULL;
461 }
462
463 if ( roar_dl_para_ref(lhandle->para) == -1 )
464  return NULL;
465
466 return lhandle->para;
467}
468
469const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
470 if ( (void*)lhandle < (void*)128 ) {
471  roar_err_set(ROAR_ERROR_NOTSUP);
472  return NULL;
473 }
474
475 if ( lhandle->lib == NULL ) {
476  roar_err_set(ROAR_ERROR_BADLIB);
477  return NULL;
478 }
479
480 if ( lhandle->lib->libname == NULL ) {
481  roar_err_set(ROAR_ERROR_NOENT);
482  return NULL;
483 }
484
485 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
486  roar_err_set(ROAR_ERROR_BADVERSION);
487  return NULL;
488 }
489
490 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
491  roar_err_set(ROAR_ERROR_HOLE);
492  return NULL;
493 }
494
495 return lhandle->lib->libname;
496}
497
[5312]498int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
499 struct roar_error_state error_state;
500
[5317]501 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
502
[5312]503 if ( (void*)lhandle < (void*)128 ) {
[5317]504  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
[5312]505  roar_err_set(ROAR_ERROR_NOTSUP);
506  return -1;
507 }
508
509 roar_err_store(&error_state);
510 roar_err_restore(&(lhandle->context.error_state));
511 lhandle->context.error_state = error_state;
512
513 if ( lhandle->lib->global_data_pointer != NULL ) {
[5317]514  ROAR_DBG("roar_dl_context_restore(lhandle=%p): gptr(%p): %p -> %p", lhandle,
515           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data);
[5312]516  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
517  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
518 }
519
[5317]520 if ( lhandle->para->notifycore != NULL )
521  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
522
523 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
[5312]524 return 0;
525}
526
527int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
528 struct roar_error_state error_state;
529
[5317]530 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
531
[5312]532 if ( (void*)lhandle < (void*)128 ) {
[5317]533  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
[5312]534  roar_err_set(ROAR_ERROR_NOTSUP);
535  return -1;
536 }
537
[5317]538 if ( lhandle->para->notifycore != NULL ) {
539  roar_notify_core_unref(roar_notify_core_swap_global(lhandle->context.notifycore));
540  roar_notify_core_unref(lhandle->context.notifycore);
541  lhandle->context.notifycore = NULL;
542 }
543
[5312]544 if ( lhandle->lib->global_data_pointer != NULL ) {
[5317]545  ROAR_DBG("roar_dl_context_store(lhandle=%p): gptr(%p): %p -> %p", lhandle,
546           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data_state);
[5312]547  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
548 }
549
550 roar_err_store(&error_state);
551 roar_err_restore(&(lhandle->context.error_state));
552 lhandle->context.error_state = error_state;
553
[5317]554 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
[5312]555 return 0;
556}
557
[5317]558int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
[5335]559 int (*func)  (struct roar_dl_librarypara * para) = NULL;
[5317]560 int ret;
561
562 if ( (void*)lhandle < (void*)128 ) {
563  roar_err_set(ROAR_ERROR_NOTSUP);
564  return -1;
565 }
566
567 if ( lhandle->lib->appsched == NULL ) {
568  roar_err_set(ROAR_ERROR_NOENT);
569  return -1;
570 }
571
572 switch (trigger) {
573#define _trig(lname,uname) \
574  case ROAR_DL_APPSCHED_ ## uname :             \
[5335]575    func = lhandle->lib->appsched->lname;       \
[5317]576   break;
577  _trig(init, INIT);
578  _trig(free, FREE);
579  _trig(update, UPDATE);
[5335]580  _trig(tick, TICK);
581  _trig(wait, WAIT);
582// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
583#ifndef DEBUG
584  default:
585    roar_err_set(ROAR_ERROR_BADRQC);
586    return -1;
587   break;
588#endif
[5317]589 }
590
[5335]591 if ( func == NULL ) {
592  roar_err_set(ROAR_ERROR_NOENT);
593  return -1;
594 }
595
596 roar_dl_context_restore(lhandle);
597 ret = func(lhandle->para);
598 roar_dl_context_store(lhandle);
599 return ret;
[5317]600}
601
[3297]602//ll
Note: See TracBrowser for help on using the repository browser.