[PATCH] config-parser: Honor the XDG_CONFIG_DIRS environment variable

Othman, Ossama ossama.othman at intel.com
Sat May 11 23:20:41 PDT 2013


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.othman at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20130511/f9adebd4/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-config-parser-Honor-the-XDG_CONFIG_DIRS-environment-.patch
Type: application/octet-stream
Size: 6304 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20130511/f9adebd4/attachment-0001.obj>


More information about the wayland-devel mailing list