1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "dlfcn-util.h"
4
dlsym_many_or_warnv(void * dl,int log_level,va_list ap)5 static int dlsym_many_or_warnv(void *dl, int log_level, va_list ap) {
6 void (**fn)(void);
7
8 /* Tries to resolve a bunch of function symbols, and logs an error about if it cannot resolve one of
9 * them. Note that this function possibly modifies the supplied function pointers if the whole
10 * operation fails. */
11
12 while ((fn = va_arg(ap, typeof(fn)))) {
13 void (*tfn)(void);
14 const char *symbol;
15
16 symbol = va_arg(ap, typeof(symbol));
17
18 tfn = (typeof(tfn)) dlsym(dl, symbol);
19 if (!tfn)
20 return log_full_errno(log_level,
21 SYNTHETIC_ERRNO(ELIBBAD),
22 "Can't find symbol %s: %s", symbol, dlerror());
23 *fn = tfn;
24 }
25
26 return 0;
27 }
28
dlsym_many_or_warn_sentinel(void * dl,int log_level,...)29 int dlsym_many_or_warn_sentinel(void *dl, int log_level, ...) {
30 va_list ap;
31 int r;
32
33 va_start(ap, log_level);
34 r = dlsym_many_or_warnv(dl, log_level, ap);
35 va_end(ap);
36
37 return r;
38 }
39
dlopen_many_sym_or_warn_sentinel(void ** dlp,const char * filename,int log_level,...)40 int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_level, ...) {
41 _cleanup_(dlclosep) void *dl = NULL;
42 int r;
43
44 if (*dlp)
45 return 0; /* Already loaded */
46
47 dl = dlopen(filename, RTLD_LAZY);
48 if (!dl)
49 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
50 "%s is not installed: %s", filename, dlerror());
51
52 va_list ap;
53 va_start(ap, log_level);
54 r = dlsym_many_or_warnv(dl, log_level, ap);
55 va_end(ap);
56
57 if (r < 0)
58 return r;
59
60 /* Note that we never release the reference here, because there's no real reason to. After all this
61 * was traditionally a regular shared library dependency which lives forever too. */
62 *dlp = TAKE_PTR(dl);
63 return 1;
64 }
65