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