2 * Copyright (c) 2012, 2013, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/types.h>
40 #include <murphy/common/macros.h>
41 #include <murphy/common/debug.h>
42 #include <murphy/common/mainloop.h>
44 #include "srs/daemon/plugin.h"
45 #include "srs/daemon/voice.h"
47 #define PLUGIN_NAME "festival-loader"
48 #define PLUGIN_AUTHORS "Krisztian Litkey <kli@iki.fi>"
49 #define PLUGIN_VERSION "0.0.1"
50 #define PLUGIN_DESCR \
51 "A plugin to load libFestival.so. This loader works around a bug in " \
52 "festival caused by a symbol conflict with glibc that causes a SIGSEGV " \
53 "and a crash during library initialization."
56 # define PATH_MAX 1024
59 #define MAX_LIBS 8 /* max libs to preload */
60 #define MAX_DIRS 8 /* max dirs to search */
62 #define CONFIG_DIRS "SRS_FESTIVAL_DIRS" /* env. var. for dirs to search */
63 #define CONFIG_LIBS "SRS_FESTIVAL_LIBS" /* env. var. for libs to preload */
65 #define DEFAULT_DIRS "/usr/lib64, /usr/lib, /lib64, /lib"
66 #define DEFAULT_LIBS "libeststring.so*, libestbase.so*, libestools.so*, " \
71 const char *dirs[MAX_DIRS]; /* directories to search */
72 int ndir; /* number of directories */
73 const char *libs[MAX_LIBS]; /* libraries to preload */
74 int nlib; /* number of libraries */
75 void *handles[MAX_LIBS]; /* library DSO handles */
78 static loader_t loader;
81 static int check_config(loader_t *l)
83 static char buf[PATH_MAX * 16];
84 const char *evdir, *evlib, *s;
87 if ((evdir = getenv(CONFIG_DIRS)) == NULL)
90 if ((evlib = getenv(CONFIG_LIBS)) == NULL)
93 mrp_log_info("Directories to search: %s.", evdir);
94 mrp_log_info("Libraries to preaload: %s.", evlib);
100 while (*s == ' ' || *s == '\t' || *s == ',' || *s == ':')
103 l->dirs[l->ndir++] = b;
105 while (*s && *s != ' ' && *s != '\t' && *s != ',' && *s != ':') {
108 if (b - buf >= sizeof(buf) - 1) {
114 if (b - buf >= sizeof(buf) - 1) {
120 mrp_debug("added preload search dir '%s'...", l->dirs[l->ndir - 1]);
126 while (*s == ' ' || *s == '\t' || *s == ',' || *s == ':')
129 l->libs[l->nlib++] = b;
131 while (*s && *s != ' ' && *s != '\t' && *s != ',' && *s != ':') {
134 if (b - buf >= sizeof(buf) - 1) {
140 if (b - buf >= sizeof(buf) - 1) {
147 mrp_debug("added preload lib '%s'...", l->libs[l->nlib - 1]);
154 static char *find_matching(char *buf, size_t size, const char *dir,
157 char pattern[PATH_MAX], path[PATH_MAX], *p;
159 int len, prfx, match, ok;
165 if (strchr(lib, '*') == NULL && strchr(lib, '?') == NULL) {
166 if (snprintf(buf, size, "%s/%s", dir, lib) >= size)
168 if (access(buf, R_OK) == 0)
174 if ((dp = opendir(dir)) == NULL)
181 while (len > 1 && *l) {
189 prfx = (p - pattern);
201 prfx = (p - pattern);
216 mrp_debug("regex pattern to match: '%s'", pattern);
218 if (regcomp(&re, pattern, REG_NOSUB) != 0)
221 while ((de = readdir(dp)) != NULL) {
222 if (de->d_type == DT_REG) {
224 if (prfx > 0 && strncmp(de->d_name, pattern, prfx) != 0)
227 if (regexec(&re, de->d_name, 1, &rm, 0) == 0) {
228 ok = snprintf(buf, size, "%s/%s", dir, de->d_name) < size;
233 return ok ? buf : NULL;
236 else if (de->d_type == DT_LNK) {
239 snprintf(path, sizeof(path), "%s/%s", dir, de->d_name);
241 if (stat(path, &st) == 0 && S_ISREG(st.st_mode))
258 static const char *load_libs(loader_t *l)
260 char path[PATH_MAX], *err;
264 for (i = 0; i < l->nlib; i++) {
265 for (j = 0; j < l->ndir; j++) {
266 mrp_log_info("Looking for %s in %s...", l->libs[i], l->dirs[j]);
268 if (find_matching(path, sizeof(path), l->dirs[j], l->libs[i])) {
269 h = dlopen(path, RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND);
272 mrp_log_info("Preloaded %s.", path);
278 mrp_log_warning("Failed to load %s (error: %s).",
279 l->libs[i], err ? err : "unknown");
284 if (l->handles[i] == NULL) {
285 mrp_log_error("Failed to preload %s.", l->libs[i]);
294 static void unload_libs(loader_t *l)
298 for (i = 0; i < l->nlib; i++)
299 if (l->handles[i] != NULL) {
300 dlclose(l->handles[i]);
301 l->handles[i] = NULL;
306 static int create_loader(srs_plugin_t *plugin)
314 if (check_config(&loader) != 0) {
315 mrp_log_error("Failed to get configuration (%d: %s).", errno,
320 if ((failed = load_libs(&loader)) != NULL) {
321 mrp_log_error("Failed to preload library '%s'.", failed);
329 static int config_loader(srs_plugin_t *plugin, srs_cfg_t *settings)
332 MRP_UNUSED(settings);
338 static int start_loader(srs_plugin_t *plugin)
344 static void stop_loader(srs_plugin_t *plugin)
350 static void destroy_loader(srs_plugin_t *plugin)
354 unload_libs(&loader);
358 SRS_DECLARE_PLUGIN(PLUGIN_NAME, PLUGIN_DESCR, PLUGIN_AUTHORS, PLUGIN_VERSION,
359 create_loader, config_loader, start_loader, stop_loader,