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
pa_module_exists(const char * name)50 bool 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
pa_module_hook_connect(pa_module * m,pa_hook * hook,pa_hook_priority_t prio,pa_hook_cb_t cb,void * data)108 void 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
pa_module_load(pa_module ** module,pa_core * c,const char * name,const char * argument)115 int 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
242 fail:
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
postponed_dlclose(pa_mainloop_api * api,void * userdata)268 static void postponed_dlclose(pa_mainloop_api *api, void *userdata) {
269 lt_dlhandle dl = userdata;
270
271 lt_dlclose(dl);
272 }
273
pa_module_free(pa_module * m)274 static 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
pa_module_unload(pa_module * m,bool force)313 void 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
pa_module_unload_by_index(pa_core * c,uint32_t idx,bool force)325 void 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
pa_module_unload_all(pa_core * c)339 void 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
defer_cb(pa_mainloop_api * api,pa_defer_event * e,void * userdata)379 static 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
pa_module_unload_request(pa_module * m,bool force)390 void 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
pa_module_unload_request_by_index(pa_core * c,uint32_t idx,bool force)405 void 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
pa_module_get_n_used(pa_module * m)415 int 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
pa_module_update_proplist(pa_module * m,pa_update_mode_t mode,pa_proplist * p)424 void 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