1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  */
8 #include "libi3.h"
9 
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 
14 /*
15  * Get the path of the first configuration file found. If override_configpath is
16  * specified, that path is returned and saved for further calls. Otherwise,
17  * checks the home directory first, then the system directory, always taking
18  * into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
19  * $XDG_CONFIG_DIRS).
20  *
21  */
get_config_path(const char * override_configpath,bool use_system_paths)22 char *get_config_path(const char *override_configpath, bool use_system_paths) {
23     char *xdg_config_home, *xdg_config_dirs, *config_path;
24 
25     static const char *saved_configpath = NULL;
26 
27     if (override_configpath != NULL) {
28         saved_configpath = override_configpath;
29         return sstrdup(saved_configpath);
30     }
31 
32     if (saved_configpath != NULL) {
33         return sstrdup(saved_configpath);
34     }
35 
36     /* 1: check for $XDG_CONFIG_HOME/i3/config */
37     if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) {
38         xdg_config_home = "~/.config";
39     }
40 
41     xdg_config_home = resolve_tilde(xdg_config_home);
42     sasprintf(&config_path, "%s/i3/config", xdg_config_home);
43     free(xdg_config_home);
44 
45     if (path_exists(config_path)) {
46         return config_path;
47     }
48     free(config_path);
49 
50     /* 2: check the traditional path under the home directory */
51     config_path = resolve_tilde("~/.i3/config");
52     if (path_exists(config_path)) {
53         return config_path;
54     }
55     free(config_path);
56 
57     /* The below paths are considered system-level, and can be skipped if the
58      * caller only wants user-level configs. */
59     if (!use_system_paths) {
60         return NULL;
61     }
62 
63     /* 3: check for $XDG_CONFIG_DIRS/i3/config */
64     if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL) {
65         xdg_config_dirs = SYSCONFDIR "/xdg";
66     }
67 
68     char *buf = sstrdup(xdg_config_dirs);
69     char *tok = strtok(buf, ":");
70     while (tok != NULL) {
71         tok = resolve_tilde(tok);
72         sasprintf(&config_path, "%s/i3/config", tok);
73         free(tok);
74         if (path_exists(config_path)) {
75             free(buf);
76             return config_path;
77         }
78         free(config_path);
79         tok = strtok(NULL, ":");
80     }
81     free(buf);
82 
83     /* 4: check the traditional path under /etc */
84     config_path = SYSCONFDIR "/i3/config";
85     if (path_exists(config_path)) {
86         return sstrdup(config_path);
87     }
88 
89     return NULL;
90 }
91