1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 obt/paths.c for the Openbox window manager
4 Copyright (c) 2003-2007 Dana Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
19 #include "obt/bsearch.h"
20 #include "obt/paths.h"
26 #ifdef HAVE_SYS_STAT_H
27 # include <sys/stat.h>
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
53 GSList
*autostart_dirs
;
61 static gint
slist_path_cmp(const gchar
*a
, const gchar
*b
)
66 typedef GSList
* (*GSListFunc
) (gpointer list
, gconstpointer data
);
68 static GSList
* slist_path_add(GSList
*list
, gpointer data
, GSListFunc func
)
75 if (!g_slist_find_custom(list
, data
, (GCompareFunc
) slist_path_cmp
))
76 list
= func(list
, data
);
83 static GSList
* split_paths(const gchar
*paths
)
90 spl
= g_strsplit(paths
, ":", -1);
91 for (it
= spl
; *it
; ++it
)
92 list
= slist_path_add(list
, *it
, (GSListFunc
) g_slist_append
);
97 int gid_cmp(const void *va
, const void *vb
)
99 const gid_t a
= *(const gid_t
*)va
, b
= *(const gid_t
*)vb
;
100 return a
>b
? 1 : (a
== b
? 0 : -1);
103 static void find_uid_gid(uid_t
*u
, gid_t
**g
, guint
*n
)
113 *g
= g_new(gid_t
, *n
=1);
116 while ((gr
= getgrent())) {
117 if (gr
->gr_gid
!= (*g
)[0]) { /* skip the main group */
119 for (c
= gr
->gr_mem
; *c
; ++c
)
120 if (strcmp(*c
, name
) == 0) {
121 *g
= g_renew(gid_t
, *g
, ++(*n
)); /* save the group */
122 (*g
)[*n
-1] = gr
->gr_gid
;
129 qsort(*g
, *n
, sizeof(gid_t
), gid_cmp
);
132 ObtPaths
* obt_paths_new(void)
138 p
= g_slice_new0(ObtPaths
);
141 find_uid_gid(&p
->uid
, &p
->gid
, &p
->n_gid
);
143 path
= g_getenv("XDG_CONFIG_HOME");
144 if (path
&& path
[0] != '\0') /* not unset or empty */
145 p
->config_home
= g_build_filename(path
, NULL
);
147 p
->config_home
= g_build_filename(g_get_home_dir(), ".config", NULL
);
149 path
= g_getenv("XDG_DATA_HOME");
150 if (path
&& path
[0] != '\0') /* not unset or empty */
151 p
->data_home
= g_build_filename(path
, NULL
);
153 p
->data_home
= g_build_filename(g_get_home_dir(), ".local",
156 path
= g_getenv("XDG_CACHE_HOME");
157 if (path
&& path
[0] != '\0') /* not unset or empty */
158 p
->cache_home
= g_build_filename(path
, NULL
);
160 p
->cache_home
= g_build_filename(g_get_home_dir(), ".cache", NULL
);
162 path
= g_getenv("XDG_CONFIG_DIRS");
163 if (path
&& path
[0] != '\0') /* not unset or empty */
164 p
->config_dirs
= split_paths(path
);
166 p
->config_dirs
= slist_path_add(p
->config_dirs
,
168 (GSListFunc
) g_slist_append
);
169 p
->config_dirs
= slist_path_add(p
->config_dirs
,
173 (GSListFunc
) g_slist_append
);
175 p
->config_dirs
= slist_path_add(p
->config_dirs
,
176 g_strdup(p
->config_home
),
177 (GSListFunc
) g_slist_prepend
);
179 for (it
= p
->config_dirs
; it
; it
= g_slist_next(it
)) {
180 gchar
*const s
= g_strdup_printf("%s/autostart", (gchar
*)it
->data
);
181 p
->autostart_dirs
= g_slist_append(p
->autostart_dirs
, s
);
184 path
= g_getenv("XDG_DATA_DIRS");
185 if (path
&& path
[0] != '\0') /* not unset or empty */
186 p
->data_dirs
= split_paths(path
);
188 p
->data_dirs
= slist_path_add(p
->data_dirs
,
190 (GSListFunc
) g_slist_append
);
191 p
->data_dirs
= slist_path_add(p
->data_dirs
,
194 "usr", "local", "share", NULL
),
195 (GSListFunc
) g_slist_append
);
196 p
->data_dirs
= slist_path_add(p
->data_dirs
,
199 "usr", "share", NULL
),
200 (GSListFunc
) g_slist_append
);
202 p
->data_dirs
= slist_path_add(p
->data_dirs
,
203 g_strdup(p
->data_home
),
204 (GSListFunc
) g_slist_prepend
);
206 path
= g_getenv("PATH");
207 if (path
&& path
[0] != '\0') /* not unset or empty */
208 p
->exec_dirs
= split_paths(path
);
215 void obt_paths_ref(ObtPaths
*p
)
220 void obt_paths_unref(ObtPaths
*p
)
222 if (p
&& --p
->ref
== 0) {
225 for (it
= p
->config_dirs
; it
; it
= g_slist_next(it
))
227 g_slist_free(p
->config_dirs
);
228 for (it
= p
->data_dirs
; it
; it
= g_slist_next(it
))
230 g_slist_free(p
->data_dirs
);
231 for (it
= p
->autostart_dirs
; it
; it
= g_slist_next(it
))
233 g_slist_free(p
->autostart_dirs
);
234 for (it
= p
->exec_dirs
; it
; it
= g_slist_next(it
))
236 g_slist_free(p
->exec_dirs
);
237 g_free(p
->config_home
);
238 g_free(p
->data_home
);
239 g_free(p
->cache_home
);
242 g_slice_free(ObtPaths
, p
);
246 gchar
*obt_paths_expand_tilde(const gchar
*f
)
254 regex
= g_regex_new("(?:^|(?<=[ \\t]))~(?=[/ \\t$])", G_REGEX_MULTILINE
| G_REGEX_RAW
, 0, NULL
);
255 ret
= g_regex_replace_literal(regex
, f
, -1, 0, g_get_home_dir(), 0, NULL
);
256 g_regex_unref(regex
);
261 gboolean
obt_paths_mkdir(const gchar
*path
, gint mode
)
265 g_return_val_if_fail(path
!= NULL
, FALSE
);
266 g_return_val_if_fail(path
[0] != '\0', FALSE
);
268 if (!g_file_test(path
, G_FILE_TEST_IS_DIR
))
269 if (mkdir(path
, mode
) == -1)
275 gboolean
obt_paths_mkdir_path(const gchar
*path
, gint mode
)
279 g_return_val_if_fail(path
!= NULL
, FALSE
);
280 g_return_val_if_fail(path
[0] == '/', FALSE
);
282 if (!g_file_test(path
, G_FILE_TEST_IS_DIR
)) {
287 while ((e
= strchr(e
+ 1, '/'))) {
289 if (!(ret
= obt_paths_mkdir(c
, mode
)))
290 goto parse_mkdir_path_end
;
293 ret
= obt_paths_mkdir(c
, mode
);
295 parse_mkdir_path_end
:
302 const gchar
* obt_paths_config_home(ObtPaths
*p
)
304 return p
->config_home
;
307 const gchar
* obt_paths_data_home(ObtPaths
*p
)
312 const gchar
* obt_paths_cache_home(ObtPaths
*p
)
314 return p
->cache_home
;
317 GSList
* obt_paths_config_dirs(ObtPaths
*p
)
319 return p
->config_dirs
;
322 GSList
* obt_paths_data_dirs(ObtPaths
*p
)
327 GSList
* obt_paths_autostart_dirs(ObtPaths
*p
)
329 return p
->autostart_dirs
;
332 static inline gboolean
try_exec(const ObtPaths
*const p
,
333 const gchar
*const path
)
336 BSEARCH_SETUP(guint
);
338 if (stat(path
, &st
) != 0)
341 if (!S_ISREG(st
.st_mode
))
343 if (st
.st_uid
== p
->uid
)
344 return st
.st_mode
& S_IXUSR
;
345 BSEARCH(guint
, p
->gid
, 0, p
->n_gid
, st
.st_gid
);
347 return st
.st_mode
& S_IXGRP
;
348 return st
.st_mode
& S_IXOTH
;
351 gboolean
obt_paths_try_exec(ObtPaths
*p
, const gchar
*path
)
353 if (path
[0] == '/') {
354 return try_exec(p
, path
);
359 for (it
= p
->exec_dirs
; it
; it
= g_slist_next(it
)) {
360 gchar
*f
= g_strdup_printf(it
->data
, G_DIR_SEPARATOR_S
, path
);
361 gboolean e
= try_exec(p
, f
);