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