<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>