]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/path-lookup.c
machine: add reference to machine-dbus.h to Makefile.am
[thirdparty/systemd.git] / src / shared / path-lookup.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
84e3543e
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
84e3543e
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
84e3543e 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
84e3543e
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <assert.h>
23#include <stdlib.h>
24#include <stdio.h>
67445f4e 25#include <string.h>
84e3543e
LP
26#include <unistd.h>
27#include <errno.h>
28
29#include "util.h"
49e942b2 30#include "mkdir.h"
84e3543e 31#include "strv.h"
9eb977db 32#include "path-util.h"
84e3543e
LP
33#include "path-lookup.h"
34
af2d49f7 35int user_config_home(char **config_home) {
10e87ee7 36 const char *e;
26d04f86 37 char *r;
10e87ee7 38
07719a21
LP
39 e = getenv("XDG_CONFIG_HOME");
40 if (e) {
26d04f86
LP
41 r = strappend(e, "/systemd/user");
42 if (!r)
10e87ee7
LP
43 return -ENOMEM;
44
26d04f86 45 *config_home = r;
10e87ee7
LP
46 return 1;
47 } else {
48 const char *home;
49
07719a21
LP
50 home = getenv("HOME");
51 if (home) {
26d04f86
LP
52 r = strappend(home, "/.config/systemd/user");
53 if (!r)
10e87ee7
LP
54 return -ENOMEM;
55
26d04f86 56 *config_home = r;
10e87ee7
LP
57 return 1;
58 }
59 }
60
61 return 0;
62}
63
4d5dec23 64int user_runtime_dir(char **runtime_dir) {
718880ba
SA
65 const char *e;
66 char *r;
67
68 e = getenv("XDG_RUNTIME_DIR");
69 if (e) {
70 r = strappend(e, "/systemd/user");
71 if (!r)
72 return -ENOMEM;
73
4d5dec23 74 *runtime_dir = r;
718880ba
SA
75 return 1;
76 }
77
78 return 0;
79}
80
07719a21
LP
81static char** user_dirs(
82 const char *generator,
83 const char *generator_early,
84 const char *generator_late) {
85
f437d5d2 86 const char * const config_unit_paths[] = {
f437d5d2 87 USER_CONFIG_UNIT_PATH,
4bf2bbb6
LP
88 "/etc/systemd/user",
89 NULL
f437d5d2
LP
90 };
91
718880ba
SA
92 const char * const runtime_unit_path = "/run/systemd/user";
93
f437d5d2
LP
94 const char * const data_unit_paths[] = {
95 "/usr/local/lib/systemd/user",
96 "/usr/local/share/systemd/user",
97 USER_DATA_UNIT_PATH,
98 "/usr/lib/systemd/user",
4bf2bbb6
LP
99 "/usr/share/systemd/user",
100 NULL
f437d5d2
LP
101 };
102
84e3543e 103 const char *home, *e;
4d5dec23 104 _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
e3e45d4f
SP
105 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
106 char **r = NULL;
84e3543e
LP
107
108 /* Implement the mechanisms defined in
109 *
110 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
111 *
112 * We look in both the config and the data dirs because we
113 * want to encourage that distributors ship their unit files
114 * as data, and allow overriding as configuration.
115 */
116
af2d49f7 117 if (user_config_home(&config_home) < 0)
10e87ee7 118 goto fail;
84e3543e 119
4d5dec23 120 if (user_runtime_dir(&runtime_dir) < 0)
718880ba
SA
121 goto fail;
122
10e87ee7 123 home = getenv("HOME");
84e3543e 124
07719a21
LP
125 e = getenv("XDG_CONFIG_DIRS");
126 if (e) {
127 config_dirs = strv_split(e, ":");
128 if (!config_dirs)
84e3543e 129 goto fail;
07719a21 130 }
84e3543e
LP
131
132 /* We don't treat /etc/xdg/systemd here as the spec
133 * suggests because we assume that that is a link to
134 * /etc/systemd/ anyway. */
135
07719a21
LP
136 e = getenv("XDG_DATA_HOME");
137 if (e) {
af2d49f7 138 if (asprintf(&data_home, "%s/systemd/user", e) < 0)
84e3543e
LP
139 goto fail;
140
141 } else if (home) {
af2d49f7 142 if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
84e3543e 143 goto fail;
84e3543e
LP
144 }
145
07719a21
LP
146 e = getenv("XDG_DATA_DIRS");
147 if (e)
84e3543e
LP
148 data_dirs = strv_split(e, ":");
149 else
ef3102bf 150 data_dirs = strv_new("/usr/local/share",
ef3102bf 151 "/usr/share",
ef3102bf 152 NULL);
84e3543e
LP
153 if (!data_dirs)
154 goto fail;
155
156 /* Now merge everything we found. */
e3e45d4f
SP
157 if (generator_early)
158 if (strv_extend(&r, generator_early) < 0)
07719a21 159 goto fail;
07719a21 160
e3e45d4f
SP
161 if (config_home)
162 if (strv_extend(&r, config_home) < 0)
84e3543e 163 goto fail;
84e3543e 164
aa08982d
ZJS
165 if (!strv_isempty(config_dirs))
166 if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0)
718880ba
SA
167 goto fail;
168
aa08982d 169 if (strv_extend_strv(&r, (char**) config_unit_paths) < 0)
718880ba
SA
170 goto fail;
171
aa08982d
ZJS
172 if (runtime_dir)
173 if (strv_extend(&r, runtime_dir) < 0)
e3e45d4f 174 goto fail;
84e3543e 175
aa08982d 176 if (strv_extend(&r, runtime_unit_path) < 0)
84e3543e 177 goto fail;
84e3543e 178
e3e45d4f
SP
179 if (generator)
180 if (strv_extend(&r, generator) < 0)
07719a21 181 goto fail;
07719a21 182
e3e45d4f
SP
183 if (data_home)
184 if (strv_extend(&r, data_home) < 0)
84e3543e 185 goto fail;
84e3543e 186
e3e45d4f
SP
187 if (!strv_isempty(data_dirs))
188 if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0)
f437d5d2 189 goto fail;
84e3543e 190
e3e45d4f 191 if (strv_extend_strv(&r, (char**) data_unit_paths) < 0)
84e3543e 192 goto fail;
84e3543e 193
e3e45d4f
SP
194 if (generator_late)
195 if (strv_extend(&r, generator_late) < 0)
07719a21 196 goto fail;
07719a21 197
9eb977db 198 if (!path_strv_make_absolute_cwd(r))
07719a21 199 goto fail;
84e3543e 200
84e3543e
LP
201 return r;
202
203fail:
204 strv_free(r);
e3e45d4f 205 return NULL;
84e3543e
LP
206}
207
07719a21
LP
208int lookup_paths_init(
209 LookupPaths *p,
67445f4e 210 SystemdRunningAs running_as,
07719a21 211 bool personal,
12ed81d9 212 const char *root_dir,
07719a21
LP
213 const char *generator,
214 const char *generator_early,
215 const char *generator_late) {
216
84e3543e 217 const char *e;
cf7d80a5 218 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
84e3543e
LP
219
220 assert(p);
221
222 /* First priority is whatever has been passed to us via env
223 * vars */
07719a21
LP
224 e = getenv("SYSTEMD_UNIT_PATH");
225 if (e) {
cf7d80a5
ZJS
226 if (endswith(e, ":")) {
227 e = strndupa(e, strlen(e) - 1);
228 append = true;
229 }
230
231 /* FIXME: empty components in other places should be
232 * rejected. */
233
07719a21
LP
234 p->unit_path = path_split_and_make_absolute(e);
235 if (!p->unit_path)
84e3543e 236 return -ENOMEM;
07719a21
LP
237 } else
238 p->unit_path = NULL;
84e3543e 239
cf7d80a5
ZJS
240 if (!p->unit_path || append) {
241 /* Let's figure something out. */
242
1d3bc017 243 _cleanup_strv_free_ char **unit_path;
cf7d80a5 244 int r;
84e3543e 245
07719a21 246 /* For the user units we include share/ in the search
cf7d80a5
ZJS
247 * path in order to comply with the XDG basedir spec.
248 * For the system stuff we avoid such nonsense. OTOH
249 * we include /lib in the search path for the system
250 * stuff but avoid it for user stuff. */
07719a21 251
67445f4e 252 if (running_as == SYSTEMD_USER) {
c800e483 253 if (personal)
cf7d80a5 254 unit_path = user_dirs(generator, generator_early, generator_late);
c800e483 255 else
cf7d80a5 256 unit_path = strv_new(
07719a21 257 /* If you modify this you also want to modify
cf7d80a5
ZJS
258 * systemduserunitpath= in systemd.pc.in, and
259 * the arrays in user_dirs() above! */
07719a21 260 STRV_IFNOTNULL(generator_early),
cf7d80a5
ZJS
261 USER_CONFIG_UNIT_PATH,
262 "/etc/systemd/user",
263 "/run/systemd/user",
07719a21 264 STRV_IFNOTNULL(generator),
cf7d80a5
ZJS
265 "/usr/local/lib/systemd/user",
266 "/usr/local/share/systemd/user",
267 USER_DATA_UNIT_PATH,
268 "/usr/lib/systemd/user",
269 "/usr/share/systemd/user",
07719a21
LP
270 STRV_IFNOTNULL(generator_late),
271 NULL);
cf7d80a5
ZJS
272 } else
273 unit_path = strv_new(
274 /* If you modify this you also want to modify
275 * systemdsystemunitpath= in systemd.pc.in! */
276 STRV_IFNOTNULL(generator_early),
277 SYSTEM_CONFIG_UNIT_PATH,
278 "/etc/systemd/system",
279 "/run/systemd/system",
280 STRV_IFNOTNULL(generator),
281 "/usr/local/lib/systemd/system",
282 SYSTEM_DATA_UNIT_PATH,
283 "/usr/lib/systemd/system",
284#ifdef HAVE_SPLIT_USR
285 "/lib/systemd/system",
286#endif
287 STRV_IFNOTNULL(generator_late),
288 NULL);
07719a21 289
cf7d80a5
ZJS
290 if (!unit_path)
291 return -ENOMEM;
292
293 r = strv_extend_strv(&p->unit_path, unit_path);
294 if (r < 0)
295 return r;
84e3543e
LP
296 }
297
7d8da2c9 298 if (!path_strv_resolve_uniq(p->unit_path, root_dir))
07719a21 299 return -ENOMEM;
07459bb6 300
07459bb6 301 if (!strv_isempty(p->unit_path)) {
7fd1b19b 302 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
07719a21 303 if (!t)
07459bb6 304 return -ENOMEM;
242c4e1c 305 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
07459bb6 306 } else {
242c4e1c 307 log_debug("Ignoring unit files.");
07459bb6
FF
308 strv_free(p->unit_path);
309 p->unit_path = NULL;
310 }
311
67445f4e 312 if (running_as == SYSTEMD_SYSTEM) {
07459bb6 313#ifdef HAVE_SYSV_COMPAT
84e3543e
LP
314 /* /etc/init.d/ compatibility does not matter to users */
315
07719a21
LP
316 e = getenv("SYSTEMD_SYSVINIT_PATH");
317 if (e) {
318 p->sysvinit_path = path_split_and_make_absolute(e);
319 if (!p->sysvinit_path)
84e3543e 320 return -ENOMEM;
07719a21
LP
321 } else
322 p->sysvinit_path = NULL;
84e3543e
LP
323
324 if (strv_isempty(p->sysvinit_path)) {
325 strv_free(p->sysvinit_path);
326
07719a21
LP
327 p->sysvinit_path = strv_new(
328 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
329 NULL);
330 if (!p->sysvinit_path)
84e3543e
LP
331 return -ENOMEM;
332 }
333
07719a21
LP
334 e = getenv("SYSTEMD_SYSVRCND_PATH");
335 if (e) {
336 p->sysvrcnd_path = path_split_and_make_absolute(e);
337 if (!p->sysvrcnd_path)
84e3543e 338 return -ENOMEM;
07719a21
LP
339 } else
340 p->sysvrcnd_path = NULL;
84e3543e
LP
341
342 if (strv_isempty(p->sysvrcnd_path)) {
343 strv_free(p->sysvrcnd_path);
344
07719a21
LP
345 p->sysvrcnd_path = strv_new(
346 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
347 NULL);
348 if (!p->sysvrcnd_path)
84e3543e
LP
349 return -ENOMEM;
350 }
84e3543e 351
7d8da2c9 352 if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
07719a21 353 return -ENOMEM;
84e3543e 354
7d8da2c9 355 if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
07719a21 356 return -ENOMEM;
84e3543e 357
07459bb6 358 if (!strv_isempty(p->sysvinit_path)) {
7fd1b19b 359 _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
07719a21 360 if (!t)
07459bb6 361 return -ENOMEM;
242c4e1c 362 log_debug("Looking for SysV init scripts in:\n\t%s", t);
07459bb6 363 } else {
242c4e1c 364 log_debug("Ignoring SysV init scripts.");
07459bb6
FF
365 strv_free(p->sysvinit_path);
366 p->sysvinit_path = NULL;
367 }
84e3543e 368
07459bb6 369 if (!strv_isempty(p->sysvrcnd_path)) {
7fd1b19b 370 _cleanup_free_ char *t =
7ad94c71 371 strv_join(p->sysvrcnd_path, "\n\t");
07719a21 372 if (!t)
07459bb6 373 return -ENOMEM;
84e3543e 374
07459bb6 375 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
07459bb6
FF
376 } else {
377 log_debug("Ignoring SysV rcN.d links.");
378 strv_free(p->sysvrcnd_path);
379 p->sysvrcnd_path = NULL;
380 }
381#else
242c4e1c 382 log_debug("SysV init scripts and rcN.d links support disabled");
07459bb6 383#endif
84e3543e
LP
384 }
385
386 return 0;
387}
388
389void lookup_paths_free(LookupPaths *p) {
390 assert(p);
391
392 strv_free(p->unit_path);
07459bb6
FF
393 p->unit_path = NULL;
394
395#ifdef HAVE_SYSV_COMPAT
84e3543e
LP
396 strv_free(p->sysvinit_path);
397 strv_free(p->sysvrcnd_path);
07459bb6
FF
398 p->sysvinit_path = p->sysvrcnd_path = NULL;
399#endif
84e3543e 400}