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> --- shared/config-parser.c | 125 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 23 deletions(-) diff --git a/shared/config-parser.c b/shared/config-parser.c index 10ff86a..34c16a6 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,112 @@ parse_config_file(const char *path, return 0; } +static char * +config_file_path_xdg_config_home(const char *name) +{ + const char *config_dir = getenv("XDG_CONFIG_HOME"); + + if (config_dir) { + size_t size = strlen(config_dir) + 1 + strlen(name) + 1; + char *path = malloc(size); + + /* TOCTOU race here. Ideally we should open the file + * and return a handle to it. */ + if (path && + snprintf(path, size, "%s/%s", config_dir, name) > 0 && + access(path, R_OK) == 0) + return path; + + free(path); + } + + return NULL; +} + +static char * +config_file_path_home(const char *name) +{ + const char *home_dir = getenv("HOME"); + + if (home_dir) { + const char dotconf[] = "/.config/"; + + size_t size = strlen(home_dir) + sizeof dotconf + strlen(name); + char *path = malloc(size); + + if (path && + snprintf(path, size, "%s%s%s", + home_dir, dotconf, name) > 0 && + access(path, R_OK) == 0) + return path; + + free(path); + } + + return NULL; +} + +static char * +config_file_path_xdg_config_dirs(const char *name) +{ + const char *config_dirs = getenv("XDG_CONFIG_DIRS"); + + if (config_dirs) { + const char weston_dir[] = "/weston/"; + char *config_dir, *saveptr, *dirs; + char *path = NULL; + size_t size; + + size = strlen(config_dirs) + 1; + dirs = malloc(size); + if (!dirs) + return NULL; + + /* strtok_r() modifies the first argument. Avoid + * clobbering the process environment. */ + strncpy(dirs, config_dirs, size); + + for (config_dir = strtok_r(dirs, ":", &saveptr); + config_dir != NULL; + config_dir = strtok_r(NULL, ":", &saveptr)) { + size = strlen(config_dir) + + sizeof weston_dir + strlen(name); + path = realloc(path, size); + + if (path && + snprintf(path, size, "%s%s%s", + config_dir, weston_dir, name) > 0 && + access(path, R_OK) == 0) + return path; + } + + free(path); + } + + return NULL; +} + char * config_file_path(const char *name) { - const char dotconf[] = "/.config/"; - const char *config_dir; - const char *home_dir; 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); - } - 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. */ - snprintf(path, size, "%s%s%s", home_dir, dotconf, name); - return path; - } + path = config_file_path_xdg_config_home(name); + + if (!path) + path = config_file_path_home(name); + + if (!path) + path = config_file_path_xdg_config_dirs(name); - size = strlen(config_dir) + 1 + strlen(name) + 1; - path = malloc(size); if (!path) - return NULL; + fprintf(stderr, + "config file \"%s\" not found in " + "$XDG_CONFIG_{HOME,DIRS} or ~/.config\n", + name); - snprintf(path, size, "%s/%s", config_dir, 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