]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/path-lookup.c
Merge pull request #2092 from poettering/dnssec2
[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
cf0fbc49 22#include <errno.h>
84e3543e 23#include <stdio.h>
cf0fbc49 24#include <stdlib.h>
67445f4e 25#include <string.h>
84e3543e 26
b5efdb8a 27#include "alloc-util.h"
a8ffe6fb 28#include "install.h"
07630cea 29#include "path-lookup.h"
cf0fbc49
TA
30#include "path-util.h"
31#include "string-util.h"
32#include "strv.h"
33#include "util.h"
84e3543e 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
e801700e
ZJS
81static int user_data_home_dir(char **dir, const char *suffix) {
82 const char *e;
83 char *res;
84
85 /* We don't treat /etc/xdg/systemd here as the spec
86 * suggests because we assume that that is a link to
87 * /etc/systemd/ anyway. */
88
89 e = getenv("XDG_DATA_HOME");
90 if (e)
91 res = strappend(e, suffix);
92 else {
93 const char *home;
94
95 home = getenv("HOME");
96 if (home)
97 res = strjoin(home, "/.local/share", suffix, NULL);
98 else
99 return 0;
100 }
101 if (!res)
102 return -ENOMEM;
103
104 *dir = res;
105 return 0;
106}
107
07719a21
LP
108static char** user_dirs(
109 const char *generator,
110 const char *generator_early,
111 const char *generator_late) {
112
f437d5d2 113 const char * const config_unit_paths[] = {
f437d5d2 114 USER_CONFIG_UNIT_PATH,
4bf2bbb6
LP
115 "/etc/systemd/user",
116 NULL
f437d5d2
LP
117 };
118
718880ba
SA
119 const char * const runtime_unit_path = "/run/systemd/user";
120
f437d5d2
LP
121 const char * const data_unit_paths[] = {
122 "/usr/local/lib/systemd/user",
123 "/usr/local/share/systemd/user",
124 USER_DATA_UNIT_PATH,
125 "/usr/lib/systemd/user",
4bf2bbb6
LP
126 "/usr/share/systemd/user",
127 NULL
f437d5d2
LP
128 };
129
e801700e 130 const char *e;
4d5dec23 131 _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
e3e45d4f 132 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
e801700e
ZJS
133 _cleanup_free_ char **res = NULL;
134 char **tmp;
135 int r;
84e3543e
LP
136
137 /* Implement the mechanisms defined in
138 *
139 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
140 *
141 * We look in both the config and the data dirs because we
142 * want to encourage that distributors ship their unit files
143 * as data, and allow overriding as configuration.
144 */
145
af2d49f7 146 if (user_config_home(&config_home) < 0)
e801700e 147 return NULL;
84e3543e 148
4d5dec23 149 if (user_runtime_dir(&runtime_dir) < 0)
e801700e 150 return NULL;
84e3543e 151
07719a21
LP
152 e = getenv("XDG_CONFIG_DIRS");
153 if (e) {
154 config_dirs = strv_split(e, ":");
155 if (!config_dirs)
e801700e 156 return NULL;
07719a21 157 }
84e3543e 158
e801700e
ZJS
159 r = user_data_home_dir(&data_home, "/systemd/user");
160 if (r < 0)
161 return NULL;
84e3543e 162
07719a21
LP
163 e = getenv("XDG_DATA_DIRS");
164 if (e)
84e3543e
LP
165 data_dirs = strv_split(e, ":");
166 else
ef3102bf 167 data_dirs = strv_new("/usr/local/share",
ef3102bf 168 "/usr/share",
ef3102bf 169 NULL);
84e3543e 170 if (!data_dirs)
e801700e 171 return NULL;
84e3543e
LP
172
173 /* Now merge everything we found. */
e3e45d4f 174 if (generator_early)
e801700e
ZJS
175 if (strv_extend(&res, generator_early) < 0)
176 return NULL;
07719a21 177
e3e45d4f 178 if (config_home)
e801700e
ZJS
179 if (strv_extend(&res, config_home) < 0)
180 return NULL;
84e3543e 181
aa08982d 182 if (!strv_isempty(config_dirs))
e801700e
ZJS
183 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
184 return NULL;
718880ba 185
e287086b 186 if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
e801700e 187 return NULL;
718880ba 188
aa08982d 189 if (runtime_dir)
e801700e
ZJS
190 if (strv_extend(&res, runtime_dir) < 0)
191 return NULL;
84e3543e 192
e801700e
ZJS
193 if (strv_extend(&res, runtime_unit_path) < 0)
194 return NULL;
84e3543e 195
e3e45d4f 196 if (generator)
e801700e
ZJS
197 if (strv_extend(&res, generator) < 0)
198 return NULL;
07719a21 199
e3e45d4f 200 if (data_home)
e801700e
ZJS
201 if (strv_extend(&res, data_home) < 0)
202 return NULL;
84e3543e 203
e3e45d4f 204 if (!strv_isempty(data_dirs))
e801700e
ZJS
205 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
206 return NULL;
84e3543e 207
e287086b 208 if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
e801700e 209 return NULL;
84e3543e 210
e3e45d4f 211 if (generator_late)
e801700e
ZJS
212 if (strv_extend(&res, generator_late) < 0)
213 return NULL;
07719a21 214
0f474365 215 if (path_strv_make_absolute_cwd(res) < 0)
e801700e 216 return NULL;
84e3543e 217
e801700e
ZJS
218 tmp = res;
219 res = NULL;
220 return tmp;
221}
84e3543e 222
b2c23da8
LP
223char **generator_paths(ManagerRunningAs running_as) {
224 if (running_as == MANAGER_USER)
33e1e5a7
ZJS
225 return strv_new("/run/systemd/user-generators",
226 "/etc/systemd/user-generators",
e801700e
ZJS
227 "/usr/local/lib/systemd/user-generators",
228 USER_GENERATOR_PATH,
229 NULL);
230 else
33e1e5a7
ZJS
231 return strv_new("/run/systemd/system-generators",
232 "/etc/systemd/system-generators",
e801700e
ZJS
233 "/usr/local/lib/systemd/system-generators",
234 SYSTEM_GENERATOR_PATH,
235 NULL);
84e3543e
LP
236}
237
07719a21
LP
238int lookup_paths_init(
239 LookupPaths *p,
b2c23da8 240 ManagerRunningAs running_as,
07719a21 241 bool personal,
12ed81d9 242 const char *root_dir,
07719a21
LP
243 const char *generator,
244 const char *generator_early,
245 const char *generator_late) {
246
84e3543e 247 const char *e;
cf7d80a5 248 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
0f474365 249 int r;
84e3543e
LP
250
251 assert(p);
252
253 /* First priority is whatever has been passed to us via env
254 * vars */
07719a21
LP
255 e = getenv("SYSTEMD_UNIT_PATH");
256 if (e) {
cf7d80a5
ZJS
257 if (endswith(e, ":")) {
258 e = strndupa(e, strlen(e) - 1);
259 append = true;
260 }
261
262 /* FIXME: empty components in other places should be
263 * rejected. */
264
0f474365
LP
265 r = path_split_and_make_absolute(e, &p->unit_path);
266 if (r < 0)
267 return r;
07719a21
LP
268 } else
269 p->unit_path = NULL;
84e3543e 270
cf7d80a5
ZJS
271 if (!p->unit_path || append) {
272 /* Let's figure something out. */
273
1d3bc017 274 _cleanup_strv_free_ char **unit_path;
84e3543e 275
07719a21 276 /* For the user units we include share/ in the search
cf7d80a5
ZJS
277 * path in order to comply with the XDG basedir spec.
278 * For the system stuff we avoid such nonsense. OTOH
279 * we include /lib in the search path for the system
280 * stuff but avoid it for user stuff. */
07719a21 281
b2c23da8 282 if (running_as == MANAGER_USER) {
c800e483 283 if (personal)
cf7d80a5 284 unit_path = user_dirs(generator, generator_early, generator_late);
c800e483 285 else
cf7d80a5 286 unit_path = strv_new(
07719a21 287 /* If you modify this you also want to modify
cf7d80a5
ZJS
288 * systemduserunitpath= in systemd.pc.in, and
289 * the arrays in user_dirs() above! */
07719a21 290 STRV_IFNOTNULL(generator_early),
cf7d80a5
ZJS
291 USER_CONFIG_UNIT_PATH,
292 "/etc/systemd/user",
293 "/run/systemd/user",
07719a21 294 STRV_IFNOTNULL(generator),
cf7d80a5
ZJS
295 "/usr/local/lib/systemd/user",
296 "/usr/local/share/systemd/user",
297 USER_DATA_UNIT_PATH,
298 "/usr/lib/systemd/user",
299 "/usr/share/systemd/user",
07719a21
LP
300 STRV_IFNOTNULL(generator_late),
301 NULL);
cf7d80a5
ZJS
302 } else
303 unit_path = strv_new(
304 /* If you modify this you also want to modify
305 * systemdsystemunitpath= in systemd.pc.in! */
306 STRV_IFNOTNULL(generator_early),
307 SYSTEM_CONFIG_UNIT_PATH,
308 "/etc/systemd/system",
309 "/run/systemd/system",
310 STRV_IFNOTNULL(generator),
311 "/usr/local/lib/systemd/system",
312 SYSTEM_DATA_UNIT_PATH,
313 "/usr/lib/systemd/system",
314#ifdef HAVE_SPLIT_USR
315 "/lib/systemd/system",
316#endif
317 STRV_IFNOTNULL(generator_late),
318 NULL);
07719a21 319
cf7d80a5
ZJS
320 if (!unit_path)
321 return -ENOMEM;
322
e287086b 323 r = strv_extend_strv(&p->unit_path, unit_path, false);
cf7d80a5
ZJS
324 if (r < 0)
325 return r;
84e3543e
LP
326 }
327
7d8da2c9 328 if (!path_strv_resolve_uniq(p->unit_path, root_dir))
07719a21 329 return -ENOMEM;
07459bb6 330
07459bb6 331 if (!strv_isempty(p->unit_path)) {
7fd1b19b 332 _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
07719a21 333 if (!t)
07459bb6 334 return -ENOMEM;
242c4e1c 335 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
07459bb6 336 } else {
242c4e1c 337 log_debug("Ignoring unit files.");
6796073e 338 p->unit_path = strv_free(p->unit_path);
07459bb6
FF
339 }
340
b2c23da8 341 if (running_as == MANAGER_SYSTEM) {
07459bb6 342#ifdef HAVE_SYSV_COMPAT
84e3543e
LP
343 /* /etc/init.d/ compatibility does not matter to users */
344
07719a21
LP
345 e = getenv("SYSTEMD_SYSVINIT_PATH");
346 if (e) {
0f474365
LP
347 r = path_split_and_make_absolute(e, &p->sysvinit_path);
348 if (r < 0)
349 return r;
07719a21
LP
350 } else
351 p->sysvinit_path = NULL;
84e3543e
LP
352
353 if (strv_isempty(p->sysvinit_path)) {
354 strv_free(p->sysvinit_path);
355
07719a21
LP
356 p->sysvinit_path = strv_new(
357 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
358 NULL);
359 if (!p->sysvinit_path)
84e3543e
LP
360 return -ENOMEM;
361 }
362
07719a21
LP
363 e = getenv("SYSTEMD_SYSVRCND_PATH");
364 if (e) {
0f474365
LP
365 r = path_split_and_make_absolute(e, &p->sysvrcnd_path);
366 if (r < 0)
367 return r;
07719a21
LP
368 } else
369 p->sysvrcnd_path = NULL;
84e3543e
LP
370
371 if (strv_isempty(p->sysvrcnd_path)) {
372 strv_free(p->sysvrcnd_path);
373
07719a21
LP
374 p->sysvrcnd_path = strv_new(
375 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
376 NULL);
377 if (!p->sysvrcnd_path)
84e3543e
LP
378 return -ENOMEM;
379 }
84e3543e 380
7d8da2c9 381 if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
07719a21 382 return -ENOMEM;
84e3543e 383
7d8da2c9 384 if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
07719a21 385 return -ENOMEM;
84e3543e 386
07459bb6 387 if (!strv_isempty(p->sysvinit_path)) {
7fd1b19b 388 _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
07719a21 389 if (!t)
07459bb6 390 return -ENOMEM;
242c4e1c 391 log_debug("Looking for SysV init scripts in:\n\t%s", t);
07459bb6 392 } else {
242c4e1c 393 log_debug("Ignoring SysV init scripts.");
6796073e 394 p->sysvinit_path = strv_free(p->sysvinit_path);
07459bb6 395 }
84e3543e 396
07459bb6 397 if (!strv_isempty(p->sysvrcnd_path)) {
7fd1b19b 398 _cleanup_free_ char *t =
7ad94c71 399 strv_join(p->sysvrcnd_path, "\n\t");
07719a21 400 if (!t)
07459bb6 401 return -ENOMEM;
84e3543e 402
07459bb6 403 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
07459bb6
FF
404 } else {
405 log_debug("Ignoring SysV rcN.d links.");
6796073e 406 p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
07459bb6
FF
407 }
408#else
242c4e1c 409 log_debug("SysV init scripts and rcN.d links support disabled");
07459bb6 410#endif
84e3543e
LP
411 }
412
413 return 0;
414}
415
416void lookup_paths_free(LookupPaths *p) {
417 assert(p);
418
6796073e 419 p->unit_path = strv_free(p->unit_path);
07459bb6
FF
420
421#ifdef HAVE_SYSV_COMPAT
0f474365
LP
422 p->sysvinit_path = strv_free(p->sysvinit_path);
423 p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
07459bb6 424#endif
84e3543e 425}
60d27f19
IS
426
427int lookup_paths_init_from_scope(LookupPaths *paths,
428 UnitFileScope scope,
429 const char *root_dir) {
430 assert(paths);
431 assert(scope >= 0);
432 assert(scope < _UNIT_FILE_SCOPE_MAX);
433
434 zero(*paths);
435
436 return lookup_paths_init(paths,
b2c23da8 437 scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
60d27f19
IS
438 scope == UNIT_FILE_USER,
439 root_dir,
440 NULL, NULL, NULL);
441}