I've revised the patch to build a list of possible filenames as Bill suggested. This time around I've included a patch for the man page, as well.
Thanks! -Ossama --- Search for a given config file in the directories listed in $XDG_CONFIG_DIRS if it wasn't found in $XDG_CONFIG_HOME or ~/.config. This allows packages to install custom config files in /etc/xdg/weston, for example, thus allowing them to avoid dealing with home directories. Signed-off-by: Ossama Othman <ossama.oth...@intel.com> --- man/weston.ini.man | 12 +++- shared/config-parser.c | 155 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 142 insertions(+), 25 deletions(-) diff --git a/man/weston.ini.man b/man/weston.ini.man index 2287730..d37654a 100644 --- a/man/weston.ini.man +++ b/man/weston.ini.man @@ -24,7 +24,10 @@ server is started: .nf .BR "$XDG_CONFIG_HOME/weston.ini " "(if $XDG_CONFIG_HOME is set)" .BR "$HOME/.config/weston.ini " "(if $HOME is set)" -.BR "<current dir>/weston.ini " "(if both variables were not set)" +.B "weston/weston.ini in each" +.BR "\ \ \ \ $XDG_CONFIG_DIR " "(if $XDG_CONFIG_DIRS is set)" +.BR "/etc/xdg/weston/weston.ini " "(if $XDG_CONFIG_DIRS is not set)" +.BR "<current dir>/weston.ini " "(if no variables were set)" .fi .RE .PP @@ -32,7 +35,12 @@ where environment variable .B $HOME is the user's home directory, and .B $XDG_CONFIG_HOME -is the user specific configuration directory. +is the user specific configuration directory, and +.B $XDG_CONFIG_DIRS +is a colon +.B ':' +delimited listed of configuration base directories, such as +.BR /etc/xdg-foo:/etc/xdg . .PP The .I weston.ini diff --git a/shared/config-parser.c b/shared/config-parser.c index 10ff86a..4ebd453 100644 --- a/shared/config-parser.c +++ b/shared/config-parser.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include <assert.h> #include <ctype.h> +#include <unistd.h> #include "config-parser.h" @@ -95,6 +96,9 @@ parse_config_file(const char *path, const struct config_section *current = NULL; int i; + if (path == NULL) + return -1; + fp = fopen(path, "r"); if (fp == NULL) { fprintf(stderr, "couldn't open %s\n", path); @@ -151,37 +155,142 @@ parse_config_file(const char *path, return 0; } -char * -config_file_path(const char *name) +struct config_info { - const char dotconf[] = "/.config/"; - const char *config_dir; - const char *home_dir; + /* Array of config file paths. */ + char **paths; + + /* Number of elements in the "paths" array. */ + size_t count; +}; + +static char * +allocate_config_file_path(struct config_info *info, size_t path_size) +{ + char **paths; char *path; - size_t size; - - config_dir = getenv("XDG_CONFIG_HOME"); - if (!config_dir) { - home_dir = getenv("HOME"); - if (!home_dir) { - fprintf(stderr, "HOME is not set, using cwd.\n"); - return strdup(name); + + if (!info) + return 0; + + path = malloc(path_size); + if (path) { + paths = realloc(info->paths, + (info->count + 1) * sizeof(*(info->paths))); + if (paths) { + paths[info->count] = path; + info->paths = paths; + ++info->count; + } else { + free(path); + path = NULL; } + } + + return path; +} + +char * +config_file_path(const char *name) +{ + const char *config_dir = getenv("XDG_CONFIG_HOME"); + const char *home_dir = getenv("HOME"); + const char *config_dirs = getenv("XDG_CONFIG_DIRS"); + static const char weston_dir[] = "/weston/"; + static const char cwd[] = "./"; + static const int DEFAULT_DIR_COUNT = 5; + struct config_info info; + size_t name_len, size; + char *path, *dir, *saveptr, *tmp_dirs; + char **p; + + info.count = 0; + info.paths = malloc(DEFAULT_DIR_COUNT * sizeof(char *)); + if (info.paths == NULL) + return NULL; + + name_len = strlen(name); - size = strlen(home_dir) + sizeof dotconf + strlen(name); - path = malloc(size); - if (!path) - return NULL; + /* Precedence is given to config files in the home directory, + * and then to directories listed in XDG_CONFIG_DIRS and + * finally to the current working directory. */ - snprintf(path, size, "%s%s%s", home_dir, dotconf, name); - return path; + /* $XDG_CONFIG_HOME */ + if (config_dir) { + size = strlen(config_dir) + 1 + name_len + 1; + path = allocate_config_file_path(&info, size); + + if (path) + snprintf(path, size, "%s/%s", config_dir, name); } - size = strlen(config_dir) + 1 + strlen(name) + 1; - path = malloc(size); - if (!path) + /* $HOME/.config */ + if (home_dir) { + static const char dotconf[] = "/.config/"; + + size = strlen(home_dir) + sizeof dotconf + name_len; + path = allocate_config_file_path(&info, size); + + if (path) + snprintf(path, size, "%s%s%s", + home_dir, dotconf, name); + } + + /* For each $XDG_CONFIG_DIRS: weston/<config_file> */ + if (!config_dirs) + config_dirs = "/etc/xdg"; /* See XDG base dir spec. */ + + size = strlen(config_dirs) + 1; + tmp_dirs = malloc(size); + if (!tmp_dirs) return NULL; - snprintf(path, size, "%s/%s", config_dir, name); + /* strtok_r() modifies the first argument. Avoid + * clobbering the process environment. */ + strncpy(tmp_dirs, config_dirs, size); + + for (dir = strtok_r(tmp_dirs, ":", &saveptr); + dir != NULL; + dir = strtok_r(NULL, ":", &saveptr)) { + size = strlen(dir) + sizeof weston_dir + name_len; + path = allocate_config_file_path(&info, size); + + if (path) + snprintf(path, size, "%s%s%s", dir, weston_dir, name); + } + + free(tmp_dirs); + + /* Current working directory. */ + size = sizeof cwd + name_len; + path = allocate_config_file_path(&info, size); + + if (path) + snprintf(path, size, "%s%s", cwd, name); + + path = NULL; + + /* Search for usable configuration file. */ + for (p = info.paths; p != info.paths + info.count; ++p) { + /* Use the first found config file. + * + * FIXME: TOCTOU race here. Ideally we should open the + * file and return a handle to it. */ + if (!path && access(*p, R_OK) == 0) + path = *p; + else + free(*p); + } + + if (path == info.paths[info.count - 1]) + fprintf(stderr, "HOME is not set, using cwd.\n"); + + free(info.paths); + + if (!path) + fprintf(stderr, + "config file \"%s\" not found.\n", + name); + return path; } -- 1.7.10.4
0001-config-parser-Honor-the-XDG_CONFIG_DIRS-environment-.patch
Description: Binary data
_______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel