26 RCSID(
"$Id: 37717f9f82c82f4dbd6ede12de7e9f66a357e939 $")
28 #include <freeradius-devel/server/dl_module.h>
29 #include <freeradius-devel/server/log.h>
30 #include <freeradius-devel/util/atexit.h>
31 #include <freeradius-devel/util/debug.h>
33 #include <freeradius-devel/util/paths.h>
34 #include <freeradius-devel/util/syserror.h>
37 #ifdef HAVE_VALGRIND_H
38 # include <valgrind.h>
40 # define RUNNING_ON_VALGRIND 0
47 # define RTLD_LOCAL (0)
126 ret = ((
void *)a->
func > (
void *)b->func) - ((
void *)a->
func < (
void *)b->func);
127 if (ret != 0)
return ret;
129 ret = (a->
symbol && !b->symbol) - (!a->
symbol && b->symbol);
130 if (ret != 0)
return ret;
132 if (!a->
symbol && !b->symbol)
return 0;
134 #ifdef STATIC_ANALYZER
138 ret = strcmp(a->
symbol, b->symbol);
149 ret = ((
void *)a->
func > (
void *)b->func) - ((
void *)a->
func < (
void *)b->func);
150 if (ret != 0)
return ret;
152 ret = (a->
symbol && !b->symbol) - (!a->
symbol && b->symbol);
153 if (ret != 0)
return ret;
155 if (!a->
symbol && !b->symbol)
return 0;
157 #ifdef STATIC_ANALYZER
161 ret = strcmp(a->
symbol, b->symbol);
197 sym = dlsym(RTLD_DEFAULT, sym_name);
206 if (dladdr(sym, &info) == 0) {
211 handle = dlopen(info.dli_fname, flags);
250 for (p =
buffer; *p !=
'\0'; p++) {
251 if (*p ==
'-') *p =
'_';
286 char *sym_name = NULL;
289 if (!sym_name)
return -1;
331 .priority = priority,
338 if (p->priority < priority) {
395 .priority = priority,
402 if (p->priority < priority) {
439 dl = talloc_get_type_abort(
dl,
dl_t);
474 char const *search_path;
483 talloc_increase_ref_count(
dl);
498 handle = dlopen(NULL, 0);
503 goto do_symbol_check;
515 #if defined(RTLD_DEEPBIND) && !defined(__SANITIZE_ADDRESS__)
516 flags |= RTLD_DEEPBIND;
532 char *ctx, *paths, *path;
534 char *dlerror_txt = NULL;
539 while ((path =
strsep(&paths,
":")) != NULL) {
543 p = strrchr(path,
'/');
544 if (p && ((p[1] ==
'\0') || (p[1] ==
':'))) *p =
'\0';
547 handle = dlopen(path, flags);
576 dlerror_txt = dlerror();
584 int access_mode = R_OK | X_OK;
587 access_mode |= AT_ACCESS;
589 if (access(path, access_mode) < 0 && errno == ENOENT)
continue;
629 handle = dlopen(
buffer, flags);
631 char *error = dlerror();
652 .uctx_free = uctx_free
691 if (ret != 0)
goto finish;
716 "libraries are still in use:");
751 env = getenv(
"FR_LIBRARY_PATH");
929 #ifdef __EMSCRIPTEN__
969 FR_FAULT_LOG(
"defer_symbol_init : %s",
dl->defer_symbol_init ?
"yes" :
"no");
972 FR_FAULT_LOG(
"symbol_init %s", sym->symbol ? sym->symbol :
"<base>");
979 FR_FAULT_LOG(
"symbol_free %s", sym->symbol ? sym->symbol :
"<base>");
static int const char char buffer[256]
#define fr_atexit_global_once(_init, _free, _uctx)
static dl_loader_t * dl_loader
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
fr_dcursor_eval_t void const * uctx
int fr_get_lsan_state(void)
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define FR_FAULT_LOG(_fmt,...)
struct dl_symbol_free_s dl_symbol_free_t
Symbol dependent free callback.
struct dl_symbol_init_s dl_symbol_init_t
Symbol dependent initialisation callback.
bool do_dlclose
dlclose modules when we're done with them.
dl_loader_t * dl_loader_init(TALLOC_CTX *ctx, void *uctx, bool uctx_free, bool defer_symbol_init)
Initialise structures needed by the dynamic linker.
char const * symbol
to search for. May be NULL in which case func is always called.
void * uctx
dl private extension data.
dl_onload_t func
to call when symbol is found in a dl's symbol table.
bool uctx_free
Free uctx when dl_loader_t is freed.
dl_t * dl_by_name(dl_loader_t *dl_loader, char const *name, void *uctx, bool uctx_free)
Search for a dl's shared object in various locations.
int dl_search_path_append(dl_loader_t *dl_loader, char const *lib_dir)
Append a new search path component to the library search path.
static char * dl_global_libdir
Global search path, prepended all dlopen paths.
int dl_search_global_path_set(char const *lib_dir)
Set the global library path.
int dl_symbol_free_cb_register(dl_loader_t *dl_loader, unsigned int priority, char const *symbol, dl_unload_t func, void *uctx)
Register a callback to execute when a dl with a particular symbol is unloaded.
static int _dl_free(dl_t *dl)
Free a dl.
bool dl_loader_set_static(dl_loader_t *dl_loader, bool do_static)
Runtime override for doing static or dynamic module loading.
static int8_t dl_symbol_init_cmp(void const *one, void const *two)
int dl_search_path_prepend(dl_loader_t *dl_loader, char const *lib_dir)
Append a new search path component to the library search path.
void * dl_open_by_sym(char const *sym_name, int flags)
Utility function to dlopen the library containing a particular symbol.
static int8_t dl_symbol_free_cmp(void const *one, void const *two)
fr_rb_tree_t * tree
Tree of shared objects loaded.
void * uctx
User data to pass to func.
static int _dl_loader_free(dl_loader_t *dl_loader)
char const * dl_search_path(dl_loader_t *dl_loader)
Return current library path.
void * uctx
User data to pass to func.
int dl_symbol_init_cb_register(dl_loader_t *dl_loader, unsigned int priority, char const *symbol, dl_onload_t func, void *uctx)
Register a callback to execute when a dl with a particular symbol is first loaded.
static int8_t dl_handle_cmp(void const *one, void const *two)
Compare the name of two dl_t.
int dl_search_path_set(dl_loader_t *dl_loader, char const *lib_dir)
Set the current library path.
#define RUNNING_ON_VALGRIND
fr_dlist_t entry
Entry into the list of 'free' symbol callbacks.
bool do_static
Do all symbol resolution using the special RTLD_DEFAULT handle, instead of attempting to load modules...
int dl_free(dl_t const *dl)
"free" a dl handle, possibly actually freeing it, and unloading the library
void * dl_loader_uctx(dl_loader_t *dl_loader)
Retrieve the uctx from a dl_loader.
int dl_symbol_init(dl_loader_t *dl_loader, dl_t const *dl)
Walk over the registered init callbacks, searching for the symbols they depend on.
char * lib_dir
Where the libraries live.
bool defer_symbol_init
Do not call dl_symbol_init in dl_loader_init.
unsigned int priority
Call priority.
fr_dlist_t entry
Entry into the list of 'init' symbol callbacks.
void dl_symbol_free_cb_unregister(dl_loader_t *dl_loader, char const *symbol, dl_unload_t func)
Unregister an callback that was to be executed when a dl was unloaded.
void dl_symbol_init_cb_unregister(dl_loader_t *dl_loader, char const *symbol, dl_onload_t func)
Unregister an callback that was to be executed when a dl was first loaded.
void dl_loader_debug(dl_loader_t *dl)
Called from a debugger to print information about a dl_loader.
fr_dlist_head_t sym_init
Linked list of symbol init callbacks.
dl_unload_t func
to call when symbol is found in a dl's symbol table.
fr_dlist_head_t sym_free
Linked list of symbol free callbacks.
char const * symbol
to search for. May be NULL in which case func is always called.
static int dl_symbol_free(dl_loader_t *dl_loader, dl_t const *dl)
Walk over the registered init callbacks, searching for the symbols they depend on.
unsigned int priority
Call priority.
bool in_tree
Whether this dl is registered in the dl_tree.
dl_loader_t * loader
Loader that owns this dl.
struct dl_s dl_t
Module handle.
int(* dl_onload_t)(dl_t const *module, void *symbol, void *user_ctx)
Callback to call when a module is first loaded.
void * handle
Handle returned by dlopen.
void * uctx
API client's opaque data.
char const * name
Name of the module e.g. sql.
void(* dl_unload_t)(dl_t const *module, void *symbol, void *user_ctx)
Callback when a module is destroyed.
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static int fr_dlist_insert_before(fr_dlist_head_t *list_head, void *pos, void *ptr)
Insert an item before an item already in the list.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Head of a doubly linked list.
Entry in a doubly linked list.
char * strsep(char **stringp, char const *delim)
char const * fr_path_default_lib_dir(void)
Return the default lib dir.
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
init
Enter the EAP-IDENTITY state.
size_t strlcat(char *dst, char const *src, size_t siz)
size_t strlcpy(char *dst, char const *src, size_t siz)
char const * fr_syserror_simple(int num)
Guaranteed to be thread-safe version of strerror.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child)
Link two different parent and child contexts, so the child is freed before the parent.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
int talloc_decrease_ref_count(void const *ptr)
Decrease the reference count on a ptr.
#define talloc_get_type_abort_const
static int talloc_const_free(void const *ptr)
Free const'd memory.
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const(_msg)