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 AUDIO_ERR_LOG("invliad rval");
215 goto fail;
216 }
217 AUDIO_ERR_LOG("Failed to load module \"%{public}s\" (argument: \"%{public}s\"): initialization failed.",
218 name, argument ? argument : "");
219 errcode = -PA_ERR_IO;
220 goto fail;
221 }
222
223 pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : "");
224
225 pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index);
226
227 if ((mi = pa_modinfo_get_by_handle(m->dl, name))) {
228
229 if (mi->author && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_AUTHOR))
230 pa_proplist_sets(m->proplist, PA_PROP_MODULE_AUTHOR, mi->author);
231
232 if (mi->description && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_DESCRIPTION))
233 pa_proplist_sets(m->proplist, PA_PROP_MODULE_DESCRIPTION, mi->description);
234
235 if (mi->version && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_VERSION))
236 pa_proplist_sets(m->proplist, PA_PROP_MODULE_VERSION, mi->version);
237
238 pa_modinfo_free(mi);
239 }
240
241 pa_hook_fire(&m->core->hooks[PA_CORE_HOOK_MODULE_NEW], m);
242
243 *module = m;
244
245 return 0;
246
247 fail:
248
249 if (m) {
250 if (m->index != PA_IDXSET_INVALID)
251 pa_idxset_remove_by_index(c->modules, m->index);
252
253 if (m->hooks)
254 pa_dynarray_free(m->hooks);
255
256 if (m->proplist)
257 pa_proplist_free(m->proplist);
258
259 pa_xfree(m->argument);
260 pa_xfree(m->name);
261
262 if (m->dl)
263 lt_dlclose(m->dl);
264
265 pa_xfree(m);
266 }
267
268 *module = NULL;
269
270 return errcode;
271 }
272
postponed_dlclose(pa_mainloop_api * api,void * userdata)273 static void postponed_dlclose(pa_mainloop_api *api, void *userdata) {
274 lt_dlhandle dl = userdata;
275
276 lt_dlclose(dl);
277 }
278
pa_module_free(pa_module * m)279 static void pa_module_free(pa_module *m) {
280 pa_assert(m);
281 pa_assert(m->core);
282
283 pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index);
284 pa_hook_fire(&m->core->hooks[PA_CORE_HOOK_MODULE_UNLINK], m);
285
286 if (m->hooks) {
287 pa_dynarray_free(m->hooks);
288 m->hooks = NULL;
289 }
290
291 if (m->done)
292 m->done(m);
293
294 if (m->proplist)
295 pa_proplist_free(m->proplist);
296
297 /* If a module unloads itself with pa_module_unload(), we can't call
298 * lt_dlclose() here, because otherwise pa_module_unload() may return to a
299 * code location that has been removed from memory. Therefore, let's
300 * postpone the lt_dlclose() call a bit.
301 *
302 * Apparently lt_dlclose() doesn't always remove the module from memory,
303 * but it can happen, as can be seen here:
304 * https://bugs.freedesktop.org/show_bug.cgi?id=96831 */
305 pa_mainloop_api_once(m->core->mainloop, postponed_dlclose, m->dl);
306
307 pa_hashmap_remove(m->core->modules_pending_unload, m);
308
309 pa_log_info("Unloaded \"%s\" (index: #%u).", m->name, m->index);
310
311 pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index);
312
313 pa_xfree(m->name);
314 pa_xfree(m->argument);
315 pa_xfree(m);
316 }
317
pa_module_unload(pa_module * m,bool force)318 void pa_module_unload(pa_module *m, bool force) {
319 pa_assert(m);
320
321 if (m->core->disallow_module_loading && !force)
322 return;
323
324 if (!(m = pa_idxset_remove_by_data(m->core->modules, m, NULL)))
325 return;
326
327 pa_module_free(m);
328 }
329
pa_module_unload_by_index(pa_core * c,uint32_t idx,bool force)330 void pa_module_unload_by_index(pa_core *c, uint32_t idx, bool force) {
331 pa_module *m;
332 pa_assert(c);
333 pa_assert(idx != PA_IDXSET_INVALID);
334
335 if (c->disallow_module_loading && !force)
336 return;
337
338 if (!(m = pa_idxset_remove_by_index(c->modules, idx)))
339 return;
340
341 pa_module_free(m);
342 }
343
pa_module_unload_all(pa_core * c)344 void pa_module_unload_all(pa_core *c) {
345 pa_module *m;
346 uint32_t *indices;
347 uint32_t state;
348 int i;
349
350 pa_assert(c);
351 pa_assert(c->modules);
352
353 if (pa_idxset_isempty(c->modules))
354 return;
355
356 /* Unload modules in reverse order by default */
357 indices = pa_xnew(uint32_t, pa_idxset_size(c->modules));
358 i = 0;
359 PA_IDXSET_FOREACH(m, c->modules, state)
360 indices[i++] = state;
361 pa_assert(i == (int) pa_idxset_size(c->modules));
362 i--;
363 for (; i >= 0; i--) {
364 m = pa_idxset_remove_by_index(c->modules, indices[i]);
365 if (m)
366 pa_module_free(m);
367 }
368 pa_xfree(indices);
369
370 /* Just in case module unloading caused more modules to load */
371 PA_IDXSET_FOREACH(m, c->modules, state)
372 pa_log_warn("After module unload, module '%s' was still loaded!", m->name);
373 c->disallow_module_loading = 1;
374 pa_idxset_remove_all(c->modules, (pa_free_cb_t) pa_module_free);
375 pa_assert(pa_idxset_isempty(c->modules));
376
377 if (c->module_defer_unload_event) {
378 c->mainloop->defer_free(c->module_defer_unload_event);
379 c->module_defer_unload_event = NULL;
380 }
381 pa_assert(pa_hashmap_isempty(c->modules_pending_unload));
382 }
383
defer_cb(pa_mainloop_api * api,pa_defer_event * e,void * userdata)384 static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) {
385 pa_core *c = PA_CORE(userdata);
386 pa_module *m;
387
388 pa_core_assert_ref(c);
389 api->defer_enable(e, 0);
390
391 while ((m = pa_hashmap_first(c->modules_pending_unload)))
392 pa_module_unload(m, true);
393 }
394
pa_module_unload_request(pa_module * m,bool force)395 void pa_module_unload_request(pa_module *m, bool force) {
396 pa_assert(m);
397
398 if (m->core->disallow_module_loading && !force)
399 return;
400
401 m->unload_requested = true;
402 pa_hashmap_put(m->core->modules_pending_unload, m, m);
403
404 if (!m->core->module_defer_unload_event)
405 m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core);
406
407 m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1);
408 }
409
pa_module_unload_request_by_index(pa_core * c,uint32_t idx,bool force)410 void pa_module_unload_request_by_index(pa_core *c, uint32_t idx, bool force) {
411 pa_module *m;
412 pa_assert(c);
413
414 if (!(m = pa_idxset_get_by_index(c->modules, idx)))
415 return;
416
417 pa_module_unload_request(m, force);
418 }
419
pa_module_get_n_used(pa_module * m)420 int pa_module_get_n_used(pa_module*m) {
421 pa_assert(m);
422
423 if (!m->get_n_used)
424 return -1;
425
426 return m->get_n_used(m);
427 }
428
pa_module_update_proplist(pa_module * m,pa_update_mode_t mode,pa_proplist * p)429 void pa_module_update_proplist(pa_module *m, pa_update_mode_t mode, pa_proplist *p) {
430 pa_assert(m);
431
432 if (p)
433 pa_proplist_update(m->proplist, mode, p);
434
435 pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index);
436 pa_hook_fire(&m->core->hooks[PA_CORE_HOOK_MODULE_PROPLIST_CHANGED], m);
437 }
438