<div dir="ltr"><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> shared/config-parser.c |  125 +++++++++++++++++++++++++++++++++++++++---------</div><div> 1 file changed, 102 insertions(+), 23 deletions(-)</div><div><br></div><div>diff --git a/shared/config-parser.c b/shared/config-parser.c</div>
<div>index 10ff86a..34c16a6 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,112 @@ parse_config_file(const char *path,</div><div> <span class="" style="white-space:pre">  </span>return 0;</div><div> }</div><div> </div><div>+static char *</div><div>+config_file_path_xdg_config_home(const char *name)</div>
<div>+{</div><div>+<span class="" style="white-space:pre">  </span>const char *config_dir = getenv("XDG_CONFIG_HOME");</div><div>+</div><div>+<span class="" style="white-space:pre">     </span>if (config_dir) {</div>
<div>+<span class="" style="white-space:pre">           </span>size_t size = strlen(config_dir) + 1 + strlen(name) + 1;</div><div>+<span class="" style="white-space:pre">          </span>char *path = malloc(size);</div><div>+</div><div>+<span class="" style="white-space:pre">                </span>/* TOCTOU race here.  Ideally we should open the file</div>
<div>+<span class="" style="white-space:pre">           </span> * and return a handle to it. */</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) > 0 &&</div>
<div>+<span class="" style="white-space:pre">           </span>    access(path, R_OK) == 0)</div><div>+<span class="" style="white-space:pre">                      </span>return path;</div><div>+</div><div>+<span class="" style="white-space:pre">              </span>free(path);</div>
<div>+<span class="" style="white-space:pre">   </span>}</div><div>+</div><div>+<span class="" style="white-space:pre"> </span>return NULL;</div><div>+}</div><div>+</div><div>+static char *</div><div>+config_file_path_home(const char *name)</div>
<div>+{</div><div>+<span class="" style="white-space:pre">  </span>const char *home_dir = getenv("HOME");</div><div>+</div><div>+<span class="" style="white-space:pre">  </span>if (home_dir) {</div><div>+<span class="" style="white-space:pre">           </span>const char dotconf[] = "/.config/";</div>
<div>+</div><div>+<span class="" style="white-space:pre">           </span>size_t size = strlen(home_dir) + sizeof dotconf + strlen(name);</div><div>+<span class="" style="white-space:pre">           </span>char *path = malloc(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) > 0 &&</div>
<div>+<span class="" style="white-space:pre">           </span>    access(path, R_OK) == 0)</div><div>+<span class="" style="white-space:pre">                      </span>return path;</div><div>+</div><div>+<span class="" style="white-space:pre">              </span>free(path);</div>
<div>+<span class="" style="white-space:pre">   </span>}</div><div>+</div><div>+<span class="" style="white-space:pre"> </span>return NULL;</div><div>+}</div><div>+</div><div>+static char *</div><div>+config_file_path_xdg_config_dirs(const char *name)</div>
<div>+{</div><div>+<span class="" style="white-space:pre">  </span>const char *config_dirs = getenv("XDG_CONFIG_DIRS");</div><div>+</div><div>+<span class="" style="white-space:pre">    </span>if (config_dirs) {</div>
<div>+<span class="" style="white-space:pre">           </span>const char weston_dir[] = "/weston/";</div><div>+<span class="" style="white-space:pre">           </span>char *config_dir, *saveptr, *dirs;</div><div>+<span class="" style="white-space:pre">                </span>char *path = NULL;</div>
<div>+<span class="" style="white-space:pre">           </span>size_t size;</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>dirs = malloc(size);</div>
<div>+<span class="" style="white-space:pre">           </span>if (!dirs)</div><div>+<span class="" style="white-space:pre">                        </span>return NULL;</div><div>+</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(dirs, config_dirs, size);</div><div>+</div><div>+<span class="" style="white-space:pre">         </span>for (config_dir = strtok_r(dirs, ":", &saveptr);</div>
<div>+<span class="" style="white-space:pre">           </span>     config_dir != NULL;</div><div>+<span class="" style="white-space:pre">          </span>     config_dir = strtok_r(NULL, ":", &saveptr)) {</div><div>+<span class="" style="white-space:pre">                  </span>size = strlen(config_dir) +</div>
<div>+<span class="" style="white-space:pre">                                   </span>sizeof weston_dir + strlen(name);</div><div>+<span class="" style="white-space:pre">                 </span>path = realloc(path, 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>     config_dir, weston_dir, name) > 0 &&</div><div>
+<span class="" style="white-space:pre">                      </span>    access(path, R_OK) == 0)</div><div>+<span class="" style="white-space:pre">                              </span>return path;</div><div>+<span class="" style="white-space:pre">              </span>}</div><div>
+</div><div>+<span class="" style="white-space:pre">              </span>free(path);</div><div>+<span class="" style="white-space:pre">       </span>}</div><div>+</div><div>+<span class="" style="white-space:pre"> </span>return NULL;</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 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>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>-<span class="" style="white-space:pre">           </span>}</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. */</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>}</div><div>+<span class="" style="white-space:pre"> </span>path = config_file_path_xdg_config_home(name);</div>
<div>+</div><div>+<span class="" style="white-space:pre">   </span>if (!path)</div><div>+<span class="" style="white-space:pre">                </span>path = config_file_path_home(name);</div><div>+</div><div>+<span class="" style="white-space:pre">       </span>if (!path)</div>
<div>+<span class="" style="white-space:pre">           </span>path = config_file_path_xdg_config_dirs(name);</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>return NULL;</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 in "</div><div>+<span class="" style="white-space:pre">                    </span>"$XDG_CONFIG_{HOME,DIRS} or ~/.config\n",</div>
<div>+<span class="" style="white-space:pre">                   </span>name);</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>return path;</div>
<div> }</div><div>-- </div><div>1.7.10.4</div><div><br></div></div></div>