1/***
2  This file is part of PulseAudio.
3
4  Copyright 2004-2006 Lennart Poettering
5  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7  PulseAudio is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 2.1 of the License,
10  or (at your option) any later version.
11
12  PulseAudio is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General Public License
18  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <errno.h>
29#include <ltdl.h>
30
31#include <pulse/xmalloc.h>
32#include <pulse/proplist.h>
33
34#include <pulsecore/core-subscribe.h>
35#include <pulsecore/log.h>
36#include <pulsecore/core-util.h>
37#include <pulsecore/macro.h>
38#include <pulsecore/ltdl-helper.h>
39#include <pulsecore/modinfo.h>
40
41#include "module.h"
42
43#define PA_SYMBOL_INIT "pa__init"
44#define PA_SYMBOL_DONE "pa__done"
45#define PA_SYMBOL_LOAD_ONCE "pa__load_once"
46#define PA_SYMBOL_GET_N_USED "pa__get_n_used"
47#define PA_SYMBOL_GET_DEPRECATE "pa__get_deprecated"
48#define PA_SYMBOL_GET_VERSION "pa__get_version"
49
50bool pa_module_exists(const char *name) {
51    const char *paths, *state = NULL;
52    char *n, *p, *pathname;
53    bool result;
54
55    pa_assert(name);
56
57    if (name[0] == PA_PATH_SEP_CHAR) {
58        result = access(name, F_OK) == 0 ? true : false;
59        pa_log_debug("Checking for existence of '%s': %s", name, result ? "success" : "failure");
60        if (result)
61            return true;
62    }
63
64    if (!(paths = lt_dlgetsearchpath()))
65        return false;
66
67    /* strip .so from the end of name, if present */
68    n = pa_xstrdup(name);
69    p = strrchr(n, '.');
70    if (p && pa_streq(p, PA_SOEXT))
71        p[0] = 0;
72
73    while ((p = pa_split(paths, ":", &state))) {
74        pathname = pa_sprintf_malloc("%s" PA_PATH_SEP "%s" PA_SOEXT, p, n);
75        result = access(pathname, F_OK) == 0 ? true : false;
76        pa_log_debug("Checking for existence of '%s': %s", pathname, result ? "success" : "failure");
77        pa_xfree(pathname);
78        pa_xfree(p);
79        if (result) {
80            pa_xfree(n);
81            return true;
82        }
83    }
84
85    state = NULL;
86    if (PA_UNLIKELY(pa_run_from_build_tree())) {
87        while ((p = pa_split(paths, ":", &state))) {
88#ifdef MESON_BUILD
89            pathname = pa_sprintf_malloc("%s" PA_PATH_SEP "src" PA_PATH_SEP "modules" PA_PATH_SEP "%s" PA_SOEXT, p, n);
90#else
91            pathname = pa_sprintf_malloc("%s" PA_PATH_SEP ".libs" PA_PATH_SEP "%s" PA_SOEXT, p, n);
92#endif
93            result = access(pathname, F_OK) == 0 ? true : false;
94            pa_log_debug("Checking for existence of '%s': %s", pathname, result ? "success" : "failure");
95            pa_xfree(pathname);
96            pa_xfree(p);
97            if (result) {
98                pa_xfree(n);
99                return true;
100            }
101        }
102    }
103
104    pa_xfree(n);
105    return false;
106}
107
108void pa_module_hook_connect(pa_module *m, pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data) {
109    pa_assert(m);
110    pa_assert(hook);
111    pa_assert(m->hooks);
112    pa_dynarray_append(m->hooks, pa_hook_connect(hook, prio, cb, data));
113}
114
115int pa_module_load(pa_module** module, pa_core *c, const char *name, const char *argument) {
116    pa_module *m = NULL;
117    const char *(*get_version)(void);
118    bool (*load_once)(void);
119    const char* (*get_deprecated)(void);
120    pa_modinfo *mi;
121    int errcode, rval;
122
123    pa_assert(module);
124    pa_assert(c);
125    pa_assert(name);
126
127    if (c->disallow_module_loading) {
128        errcode = -PA_ERR_ACCESS;
129        goto fail;
130    }
131
132    m = pa_xnew(pa_module, 1);
133    m->name = pa_xstrdup(name);
134    m->argument = pa_xstrdup(argument);
135    m->load_once = false;
136    m->proplist = pa_proplist_new();
137    m->hooks = pa_dynarray_new((pa_free_cb_t) pa_hook_slot_free);
138    m->index = PA_IDXSET_INVALID;
139
140    if (!(m->dl = lt_dlopenext(name))) {
141        /* We used to print the error that is returned by lt_dlerror(), but
142         * lt_dlerror() is useless. It returns pretty much always "file not
143         * found". That's because if there are any problems with loading the
144         * module with normal loaders, libltdl falls back to the "preload"
145         * loader, which never finds anything, and therefore says "file not
146         * found". */
147        pa_log("Failed to open module \"%s\".", name);
148        errcode = -PA_ERR_IO;
149        goto fail;
150    }
151
152    if ((get_version = (const char *(*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_VERSION))) {
153        const char *version = get_version();
154
155        if (!pa_safe_streq(version, PACKAGE_VERSION)) {
156            pa_log("Module \"%s\" version (%s) doesn't match the expected version (%s).",
157                   name, pa_strnull(version), PACKAGE_VERSION);
158            errcode = -PA_ERR_IO;
159            goto fail;
160        }
161    } else {
162        pa_log("Symbol \"%s\" not found in module \"%s\".", PA_SYMBOL_GET_VERSION, name);
163        errcode = -PA_ERR_IO;
164        goto fail;
165    }
166
167    if ((load_once = (bool (*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_LOAD_ONCE))) {
168
169        m->load_once = load_once();
170
171        if (m->load_once) {
172            pa_module *i;
173            uint32_t idx;
174            /* OK, the module only wants to be loaded once, let's make sure it is */
175
176            PA_IDXSET_FOREACH(i, c->modules, idx) {
177                if (pa_streq(name, i->name)) {
178                    pa_log("Module \"%s\" should be loaded once at most. Refusing to load.", name);
179                    errcode = -PA_ERR_EXIST;
180                    goto fail;
181                }
182            }
183        }
184    }
185
186    if ((get_deprecated = (const char* (*) (void)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_DEPRECATE))) {
187        const char *t;
188
189        if ((t = get_deprecated()))
190            pa_log_warn("%s is deprecated: %s", name, t);
191    }
192
193    if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) {
194        pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name);
195        errcode = -PA_ERR_IO;
196        goto fail;
197    }
198
199    m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE);
200    m->get_n_used = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_N_USED);
201    m->userdata = NULL;
202    m->core = c;
203    m->unload_requested = false;
204
205    pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0);
206    pa_assert(m->index != PA_IDXSET_INVALID);
207
208    if ((rval = m->init(m)) < 0) {
209        if (rval == -PA_MODULE_ERR_SKIP) {
210            errcode = -PA_ERR_NOENTITY;
211            goto fail;
212        }
213        pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
214        errcode = -PA_ERR_IO;
215        goto fail;
216    }
217
218    pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : "");
219
220    pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index);
221
222    if ((mi = pa_modinfo_get_by_handle(m->dl, name))) {
223
224        if (mi->author && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_AUTHOR))
225            pa_proplist_sets(m->proplist, PA_PROP_MODULE_AUTHOR, mi->author);
226
227        if (mi->description && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_DESCRIPTION))
228            pa_proplist_sets(m->proplist, PA_PROP_MODULE_DESCRIPTION, mi->description);
229
230        if (mi->version && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_VERSION))
231            pa_proplist_sets(m->proplist, PA_PROP_MODULE_VERSION, mi->version);
232
233        pa_modinfo_free(mi);
234    }
235
236    pa_hook_fire(&m->core->hooks[PA_CORE_HOOK_MODULE_NEW], m);
237
238    *module = m;
239
240    return 0;
241
242fail:
243
244    if (m) {
245        if (m->index != PA_IDXSET_INVALID)
246            pa_idxset_remove_by_index(c->modules, m->index);
247
248        if (m->hooks)
249            pa_dynarray_free(m->hooks);
250
251        if (m->proplist)
252            pa_proplist_free(m->proplist);
253
254        pa_xfree(m->argument);
255        pa_xfree(m->name);
256
257        if (m->dl)
258            lt_dlclose(m->dl);
259
260        pa_xfree(m);
261    }
262
263    *module = NULL;
264
265    return errcode;
266}
267
268static void postponed_dlclose(pa_mainloop_api *api, void *userdata) {
269    lt_dlhandle dl = userdata;
270
271    lt_dlclose(dl);
272}
273
274static void pa_module_free(pa_module *m) {
275    pa_assert(m);
276    pa_assert(m->core);
277
278    pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index);
279    pa_hook_fire(&m->core->hooks[PA_CORE_HOOK_MODULE_UNLINK], m);
280
281    if (m->hooks) {
282       pa_dynarray_free(m->hooks);
283       m->hooks = NULL;
284    }
285
286    if (m->done)
287        m->done(m);
288
289    if (m->proplist)
290        pa_proplist_free(m->proplist);
291
292    /* If a module unloads itself with pa_module_unload(), we can't call
293     * lt_dlclose() here, because otherwise pa_module_unload() may return to a
294     * code location that has been removed from memory. Therefore, let's
295     * postpone the lt_dlclose() call a bit.
296     *
297     * Apparently lt_dlclose() doesn't always remove the module from memory,
298     * but it can happen, as can be seen here:
299     * https://bugs.freedesktop.org/show_bug.cgi?id=96831 */
300    pa_mainloop_api_once(m->core->mainloop, postponed_dlclose, m->dl);
301
302    pa_hashmap_remove(m->core->modules_pending_unload, m);
303
304    pa_log_info("Unloaded \"%s\" (index: #%u).", m->name, m->index);
305
306    pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index);
307
308    pa_xfree(m->name);
309    pa_xfree(m->argument);
310    pa_xfree(m);
311}
312
313void pa_module_unload(pa_module *m, bool force) {
314    pa_assert(m);
315
316    if (m->core->disallow_module_loading && !force)
317        return;
318
319    if (!(m = pa_idxset_remove_by_data(m->core->modules, m, NULL)))
320        return;
321
322    pa_module_free(m);
323}
324
325void pa_module_unload_by_index(pa_core *c, uint32_t idx, bool force) {
326    pa_module *m;
327    pa_assert(c);
328    pa_assert(idx != PA_IDXSET_INVALID);
329
330    if (c->disallow_module_loading && !force)
331        return;
332
333    if (!(m = pa_idxset_remove_by_index(c->modules, idx)))
334        return;
335
336    pa_module_free(m);
337}
338
339void pa_module_unload_all(pa_core *c) {
340    pa_module *m;
341    uint32_t *indices;
342    uint32_t state;
343    int i;
344
345    pa_assert(c);
346    pa_assert(c->modules);
347
348    if (pa_idxset_isempty(c->modules))
349        return;
350
351    /* Unload modules in reverse order by default */
352    indices = pa_xnew(uint32_t, pa_idxset_size(c->modules));
353    i = 0;
354    PA_IDXSET_FOREACH(m, c->modules, state)
355        indices[i++] = state;
356    pa_assert(i == (int) pa_idxset_size(c->modules));
357    i--;
358    for (; i >= 0; i--) {
359        m = pa_idxset_remove_by_index(c->modules, indices[i]);
360        if (m)
361            pa_module_free(m);
362    }
363    pa_xfree(indices);
364
365    /* Just in case module unloading caused more modules to load */
366    PA_IDXSET_FOREACH(m, c->modules, state)
367        pa_log_warn("After module unload, module '%s' was still loaded!", m->name);
368    c->disallow_module_loading = 1;
369    pa_idxset_remove_all(c->modules, (pa_free_cb_t) pa_module_free);
370    pa_assert(pa_idxset_isempty(c->modules));
371
372    if (c->module_defer_unload_event) {
373        c->mainloop->defer_free(c->module_defer_unload_event);
374        c->module_defer_unload_event = NULL;
375    }
376    pa_assert(pa_hashmap_isempty(c->modules_pending_unload));
377}
378
379static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) {
380    pa_core *c = PA_CORE(userdata);
381    pa_module *m;
382
383    pa_core_assert_ref(c);
384    api->defer_enable(e, 0);
385
386    while ((m = pa_hashmap_first(c->modules_pending_unload)))
387        pa_module_unload(m, true);
388}
389
390void pa_module_unload_request(pa_module *m, bool force) {
391    pa_assert(m);
392
393    if (m->core->disallow_module_loading && !force)
394        return;
395
396    m->unload_requested = true;
397    pa_hashmap_put(m->core->modules_pending_unload, m, m);
398
399    if (!m->core->module_defer_unload_event)
400        m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core);
401
402    m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1);
403}
404
405void pa_module_unload_request_by_index(pa_core *c, uint32_t idx, bool force) {
406    pa_module *m;
407    pa_assert(c);
408
409    if (!(m = pa_idxset_get_by_index(c->modules, idx)))
410        return;
411
412    pa_module_unload_request(m, force);
413}
414
415int pa_module_get_n_used(pa_module*m) {
416    pa_assert(m);
417
418    if (!m->get_n_used)
419        return -1;
420
421    return m->get_n_used(m);
422}
423
424void pa_module_update_proplist(pa_module *m, pa_update_mode_t mode, pa_proplist *p) {
425    pa_assert(m);
426
427    if (p)
428        pa_proplist_update(m->proplist, mode, p);
429
430    pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index);
431    pa_hook_fire(&m->core->hooks[PA_CORE_HOOK_MODULE_PROPLIST_CHANGED], m);
432}
433