3
* xdg.c - XDG compliant path constructor
5
* Copyright © 2012 Canonical Ltd.
6
* Author: Dmitrijs Ledkovs <dmitrijs.ledkovs@canonical.com>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2, as
10
* published by the Free Software Foundation.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License along
18
* with this program; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
#endif /* HAVE_CONFIG_H */
28
#include <sys/types.h>
30
#include <nih/alloc.h>
31
#include <nih/logging.h>
32
#include <nih/string.h>
42
* If TRUE, upstart runs in user session mode.
44
int user_mode = FALSE;
49
* Full path to file containing UPSTART_SESSION details (only set when
50
* user_mode in operation).
52
* File is created on startup and removed on clean shutdown.
54
const char *session_file = NULL;
56
#endif /* INITCTL_BUILD */
60
* @dir: initial directory,
61
* @suffix: sub-directory of @dir,
62
* @create: flag to create sub-directory.
64
* Construct path by appending @suffix to @dir. If @create
65
* flag is TRUE, also attempt to create that directory.
67
* Errors upon directory creation are ignored.
69
* Returns: Newly-allocated path, or NULL on error.
72
get_subdir (const char *dir, const char *suffix, int create)
76
nih_assert (dir != NULL);
77
nih_assert (suffix != NULL);
78
nih_assert (suffix[0]);
81
newdir = nih_sprintf (NULL, "%s/%s", dir, suffix);
85
mkdir (newdir, INIT_XDG_PATH_MODE);
95
* @suffix: sub-directory name,
96
* @create: flag to create sub-directory.
98
* Construct path to @suffix directory in user's HOME directory.
99
* If @create is TRUE, also attempt to create that directory.
101
* Errors upon directory creation are ignored.
103
* Returns: Newly-allocated path, or NULL on error.
106
get_home_subdir (const char *suffix, int create)
110
env = getenv ("HOME");
114
return get_subdir (env, suffix, create);
118
* xdg_get_cache_home:
120
* Determine an XDG compliant XDG_CACHE_HOME
122
* Returns: newly-allocated path, or NULL on error.
125
xdg_get_cache_home (void)
129
dir = getenv ("XDG_CACHE_HOME");
131
if (dir && dir[0] == '/') {
132
mkdir (dir, INIT_XDG_PATH_MODE);
133
dir = nih_strdup (NULL, dir);
137
/* Per XDG spec, we should only create dirs, if we are
138
* attempting to write and the dir is not there. Here we
139
* anticipate logging to happen really soon now, hence we
140
* pre-create the cache dir. That does not protect us from
141
* this directory disappering while upstart is running. =/
142
* hence this dir should be created each time we try to write
144
dir = get_home_subdir (".cache", TRUE);
150
* xdg_get_config_home:
152
* Determine an XDG compliant XDG_CONFIG_HOME
154
* Returns: newly-allocated path, or NULL on error.
157
xdg_get_config_home (void)
161
dir = getenv ("XDG_CONFIG_HOME");
163
if (dir && dir[0] == '/') {
164
mkdir (dir, INIT_XDG_PATH_MODE);
165
dir = nih_strdup (NULL, dir);
169
/* Per XDG spec, we should only create dirs, if we are
170
* attempting to write to the dir. But we only read config
171
* dir. But we rather create it, to place inotify watch on
173
dir = get_home_subdir (".config", TRUE);
179
* xdg_get_runtime_dir:
181
* Determine an XDG compliant XDG_RUNTIME_DIR.
183
* Note: No attempt is made to create this directory since if it does
184
* not exist, a non-priv user is unlikely be able to create it anyway.
186
* Returns: newly-allocated path, or NULL on error.
189
xdg_get_runtime_dir (void)
193
dir = getenv ("XDG_RUNTIME_DIR");
195
if (dir && dir[0] == '/')
196
dir = nih_strdup (NULL, dir);
204
* Determine full path to XDG-compliant session directory used to store
207
* Returns: Newly-allocated path, or NULL on error.
210
get_session_dir (void)
212
nih_local char *runtime_dir = NULL;
213
nih_local char *dir = NULL;
216
runtime_dir = xdg_get_runtime_dir ();
218
if (runtime_dir && runtime_dir[0] == '/') {
219
dir = get_subdir (runtime_dir, INIT_XDG_SUBDIR, TRUE);
223
session_dir = get_subdir (dir, INIT_XDG_SESSION_SUBDIR,
233
* xdg_get_config_dirs:
235
* Determine a list of XDG compliant XDG_CONFIG_DIRS
237
* Returns: newly-allocated array of paths, or NULL on error.
240
xdg_get_config_dirs (void)
245
env_path = getenv ("XDG_CONFIG_DIRS");
246
if (! env_path || ! env_path[0])
247
env_path = "/etc/xdg";
249
dirs = nih_str_split (NULL, env_path, ":", TRUE);
255
* get_user_upstart_dirs:
257
* Construct an array of user session config source paths to config
258
* dirs for a particular user. This array is sorted in highest
259
* priority order and therefore can be iterated to add each of these
260
* directories as config source dirs, when e.g. upstart is running as
263
* Returns: newly-allocated array of paths, or NULL or error.
266
get_user_upstart_dirs (void)
270
char **all_dirs = NULL;
272
all_dirs = nih_str_array_new (NULL);
276
/* The current order is inline with Enhanced User Sessions Spec */
278
/* User's: ~/.config/upstart or XDG_CONFIG_HOME/upstart */
279
path = xdg_get_config_home ();
283
if (path && path[0]) {
284
if (! nih_strcat_sprintf (&path, NULL, "/%s", INIT_XDG_SUBDIR))
286
mkdir (path, INIT_XDG_PATH_MODE);
287
if (! nih_str_array_add (&all_dirs, NULL, NULL, path))
293
/* Legacy User's: ~/.init */
294
path = get_home_subdir (USERCONFDIR, FALSE);
298
if (path && path[0]) {
299
if (! nih_str_array_add (&all_dirs, NULL, NULL, path))
305
/* Systems': XDG_CONFIG_DIRS/upstart */
306
dirs = xdg_get_config_dirs ();
310
for (char **p = dirs; p && *p; p++) {
313
if (! nih_strcat_sprintf (p, NULL, "/%s", INIT_XDG_SUBDIR))
315
if (! nih_str_array_add (&all_dirs, NULL, NULL, *p))
321
/* System's read-only location */
322
if (! nih_str_array_add (&all_dirs, NULL, NULL, SYSTEM_USERCONFDIR))
343
* Constructs an XDG compliant path to a cache directory in the user's
344
* home directory. It can be used to store logs.
346
* Returns: newly-allocated array of paths, or NULL or error.
349
get_user_log_dir (void)
351
nih_local char *path = NULL;
353
path = xdg_get_cache_home ();
354
if (path && path[0] == '/') {
355
dir = nih_sprintf (NULL, "%s/%s", path, INIT_XDG_SUBDIR);
358
mkdir (dir, INIT_XDG_PATH_MODE);