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