summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMengdong Lin <mengdong.lin@linux.intel.com>2016-10-24 21:22:11 +0800
committerTakashi Iwai <tiwai@suse.de>2016-10-25 09:25:22 +0200
commitc16943868289171deabce8d695990bf75552e178 (patch)
treea9675ec14167528080478a7721fb4d161725fe5d
parentadb9866b70bb8f30b08a0974d72a0256e689143d (diff)
downloadalsa-lib-c16943868289171deabce8d695990bf75552e178.tar.gz
conf: Search included files under user specified configuration directories
Users can include file by giving a relative path or just a file name via alsaconf syntax <xxx>. ALSA conf will search the file in top configuration directory and additional configuration directories defined by users via alsaconf syntax <searchdir:xxx>. ALSA conf will search and open an included file in the following order of priority: 1. directly open the file by its name; 2. search for the file name in top config direcotry "/usr/share/alsa/"; 3. search for the file name in additional configuration directories specified by users, via alsaconf syntax <searchdir:relative-path/to/user/share/alsa>; These directories will be searched in the same order as their definition. The configuration directories defined by a file will only be used to search the files included by this file. Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--src/conf.c159
1 files changed, 158 insertions, 1 deletions
diff --git a/src/conf.c b/src/conf.c
index a5166114..fbd90ac2 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -456,6 +456,18 @@ struct filedesc {
snd_input_t *in;
unsigned int line, column;
struct filedesc *next;
+
+ /* list of the include paths (configuration directories),
+ * defined by <searchdir:relative-path/to/top-alsa-conf-dir>,
+ * for searching its included files.
+ */
+ struct list_head include_paths;
+};
+
+/* path to search included files */
+struct include_path {
+ char *dir;
+ struct list_head list;
};
#define LOCAL_ERROR (-0x68000000)
@@ -501,6 +513,108 @@ static inline void snd_config_unlock(void) { }
#endif
+/*
+ * Add a diretory to the paths to search included files.
+ * param fd - File object that owns these paths to search files included by it.
+ * param dir - Path of the directory to add. Allocated externally and need to
+* be freed manually later.
+ * return - Zero if successful, otherwise a negative error code.
+ *
+ * The direcotry should be a subdiretory of top configuration directory
+ * "/usr/share/alsa/".
+ */
+static int add_include_path(struct filedesc *fd, char *dir)
+{
+ struct include_path *path;
+
+ path = calloc(1, sizeof(*path));
+ if (!path)
+ return -ENOMEM;
+
+ path->dir = dir;
+ list_add_tail(&path->list, &fd->include_paths);
+ return 0;
+}
+
+/*
+ * Free all include paths of a file descriptor.
+ * param fd - File object that owns these paths to search files included by it.
+ */
+static void free_include_paths(struct filedesc *fd)
+{
+ struct list_head *pos, *npos, *base;
+ struct include_path *path;
+
+ base = &fd->include_paths;
+ list_for_each_safe(pos, npos, base) {
+ path = list_entry(pos, struct include_path, list);
+ list_del(&path->list);
+ if (path->dir)
+ free(path->dir);
+ free(path);
+ }
+}
+
+/*
+ * Search and open a file, and creates a new input object reading from the file.
+ * param inputp - The functions puts the pointer to the new input object
+ * at the address specified by \p inputp.
+ * param file - Name of the configuration file.
+ * param include_paths - Optional, addtional directories to search the file.
+ * return - Zero if successful, otherwise a negative error code.
+ *
+ * This function will search and open the file in the following order
+ * of priority:
+ * 1. directly open the file by its name;
+ * 2. search for the file name in top configuration directory
+ * "/usr/share/alsa/";
+ * 3. search for the file name in in additional configuration directories
+ * specified by users, via alsaconf syntax
+ * <searchdir:relative-path/to/user/share/alsa>;
+ * These directories should be subdirectories of /usr/share/alsa.
+ */
+static int input_stdio_open(snd_input_t **inputp, const char *file,
+ struct list_head *include_paths)
+{
+ struct list_head *pos, *base;
+ struct include_path *path;
+ char full_path[PATH_MAX + 1];
+ int err = 0;
+
+ err = snd_input_stdio_open(inputp, file, "r");
+ if (err == 0)
+ goto out;
+
+ if (file[0] == '/') /* not search file with absolute path */
+ return err;
+
+ /* search file in top configuration directory /usr/share/alsa */
+ snprintf(full_path, PATH_MAX, "%s/%s", ALSA_CONFIG_DIR, file);
+ err = snd_input_stdio_open(inputp, full_path, "r");
+ if (err == 0)
+ goto out;
+
+ /* search file in user specified include paths. These directories
+ * are subdirectories of /usr/share/alsa.
+ */
+ if (include_paths) {
+ base = include_paths;
+ list_for_each(pos, base) {
+ path = list_entry(pos, struct include_path, list);
+ if (!path->dir)
+ continue;
+
+ snprintf(full_path, PATH_MAX, "%s/%s", path->dir, file);
+ err = snd_input_stdio_open(inputp, full_path, "r");
+ if (err == 0)
+ goto out;
+ }
+ }
+
+out:
+ return err;
+}
+
static int safe_strtoll(const char *str, long long *val)
{
long long v;
@@ -629,10 +743,44 @@ static int get_char_skip_comments(input_t *input)
char *str;
snd_input_t *in;
struct filedesc *fd;
+ DIR *dirp;
int err = get_delimstring(&str, '>', input);
if (err < 0)
return err;
+
+ if (!strncmp(str, "searchdir:", 10)) {
+ /* directory to search included files */
+ char *tmp;
+
+ tmp = malloc(strlen(ALSA_CONFIG_DIR) + 1
+ + strlen(str + 10) + 1);
+ if (tmp == NULL) {
+ free(str);
+ return -ENOMEM;
+ }
+ sprintf(tmp, ALSA_CONFIG_DIR "/%s", str + 10);
+ free(str);
+ str = tmp;
+
+ dirp = opendir(str);
+ if (!dirp) {
+ SNDERR("Invalid search dir %s", str);
+ free(str);
+ return -EINVAL;
+ }
+ closedir(dirp);
+
+ err = add_include_path(input->current, str);
+ if (err < 0) {
+ SNDERR("Cannot add search dir %s", str);
+ free(str);
+ return err;
+ }
+ continue;
+ }
+
if (!strncmp(str, "confdir:", 8)) {
+ /* file in the specified directory */
char *tmp = malloc(strlen(ALSA_CONFIG_DIR) + 1 + strlen(str + 8) + 1);
if (tmp == NULL) {
free(str);
@@ -641,8 +789,12 @@ static int get_char_skip_comments(input_t *input)
sprintf(tmp, ALSA_CONFIG_DIR "/%s", str + 8);
free(str);
str = tmp;
+ err = snd_input_stdio_open(&in, str, "r");
+ } else { /* absolute or relative file path */
+ err = input_stdio_open(&in, str,
+ &input->current->include_paths);
}
- err = snd_input_stdio_open(&in, str, "r");
+
if (err < 0) {
SNDERR("Cannot access file %s", str);
free(str);
@@ -658,6 +810,7 @@ static int get_char_skip_comments(input_t *input)
fd->next = input->current;
fd->line = 1;
fd->column = 0;
+ INIT_LIST_HEAD(&fd->include_paths);
input->current = fd;
continue;
}
@@ -1668,6 +1821,7 @@ static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override)
fd->line = 1;
fd->column = 0;
fd->next = NULL;
+ INIT_LIST_HEAD(&fd->include_paths);
input.current = fd;
input.unget = 0;
err = parse_defs(config, &input, 0, override);
@@ -1708,9 +1862,12 @@ static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override)
fd_next = fd->next;
snd_input_close(fd->in);
free(fd->name);
+ free_include_paths(fd);
free(fd);
fd = fd_next;
}
+
+ free_include_paths(fd);
free(fd);
return err;
}