]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/path-lookup.c
core: remove ManagerRunningAs enum
[thirdparty/systemd.git] / src / shared / path-lookup.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "alloc-util.h"
26 #include "install.h"
27 #include "log.h"
28 #include "macro.h"
29 #include "path-lookup.h"
30 #include "path-util.h"
31 #include "string-util.h"
32 #include "strv.h"
33 #include "util.h"
34
35 int user_config_home(char **config_home) {
36 const char *e;
37 char *r;
38
39 e = getenv("XDG_CONFIG_HOME");
40 if (e) {
41 r = strappend(e, "/systemd/user");
42 if (!r)
43 return -ENOMEM;
44
45 *config_home = r;
46 return 1;
47 } else {
48 const char *home;
49
50 home = getenv("HOME");
51 if (home) {
52 r = strappend(home, "/.config/systemd/user");
53 if (!r)
54 return -ENOMEM;
55
56 *config_home = r;
57 return 1;
58 }
59 }
60
61 return 0;
62 }
63
64 int user_runtime_dir(char **runtime_dir) {
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
74 *runtime_dir = r;
75 return 1;
76 }
77
78 return 0;
79 }
80
81 static 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 1;
106 }
107
108 static char** user_dirs(
109 const char *persistent_config,
110 const char *runtime_config,
111 const char *generator,
112 const char *generator_early,
113 const char *generator_late) {
114
115 const char * const config_unit_paths[] = {
116 USER_CONFIG_UNIT_PATH,
117 "/etc/systemd/user",
118 NULL
119 };
120
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",
126 "/usr/share/systemd/user",
127 NULL
128 };
129
130 const char *e;
131 _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
132 _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
133 _cleanup_free_ char **res = NULL;
134 char **tmp;
135 int r;
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
146 if (user_config_home(&config_home) < 0)
147 return NULL;
148
149 if (user_runtime_dir(&runtime_dir) < 0)
150 return NULL;
151
152 e = getenv("XDG_CONFIG_DIRS");
153 if (e) {
154 config_dirs = strv_split(e, ":");
155 if (!config_dirs)
156 return NULL;
157 }
158
159 r = user_data_home_dir(&data_home, "/systemd/user");
160 if (r < 0)
161 return NULL;
162
163 e = getenv("XDG_DATA_DIRS");
164 if (e)
165 data_dirs = strv_split(e, ":");
166 else
167 data_dirs = strv_new("/usr/local/share",
168 "/usr/share",
169 NULL);
170 if (!data_dirs)
171 return NULL;
172
173 /* Now merge everything we found. */
174 if (generator_early)
175 if (strv_extend(&res, generator_early) < 0)
176 return NULL;
177
178 if (config_home)
179 if (strv_extend(&res, config_home) < 0)
180 return NULL;
181
182 if (!strv_isempty(config_dirs))
183 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
184 return NULL;
185
186 if (strv_extend(&res, persistent_config) < 0)
187 return NULL;
188
189 if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
190 return NULL;
191
192 if (runtime_dir)
193 if (strv_extend(&res, runtime_dir) < 0)
194 return NULL;
195
196 if (strv_extend(&res, runtime_config) < 0)
197 return NULL;
198
199 if (generator)
200 if (strv_extend(&res, generator) < 0)
201 return NULL;
202
203 if (data_home)
204 if (strv_extend(&res, data_home) < 0)
205 return NULL;
206
207 if (!strv_isempty(data_dirs))
208 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
209 return NULL;
210
211 if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
212 return NULL;
213
214 if (generator_late)
215 if (strv_extend(&res, generator_late) < 0)
216 return NULL;
217
218 if (path_strv_make_absolute_cwd(res) < 0)
219 return NULL;
220
221 tmp = res;
222 res = NULL;
223 return tmp;
224 }
225
226 char **generator_paths(UnitFileScope scope) {
227
228 switch (scope) {
229
230 case UNIT_FILE_SYSTEM:
231 return strv_new("/run/systemd/system-generators",
232 "/etc/systemd/system-generators",
233 "/usr/local/lib/systemd/system-generators",
234 SYSTEM_GENERATOR_PATH,
235 NULL);
236
237 case UNIT_FILE_GLOBAL:
238 case UNIT_FILE_USER:
239 return strv_new("/run/systemd/user-generators",
240 "/etc/systemd/user-generators",
241 "/usr/local/lib/systemd/user-generators",
242 USER_GENERATOR_PATH,
243 NULL);
244
245 default:
246 assert_not_reached("Hmm, unexpected scope.");
247 }
248 }
249
250 static int acquire_generator_dirs(
251 UnitFileScope scope,
252 char **generator,
253 char **generator_early,
254 char **generator_late) {
255
256 _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
257 const char *prefix;
258
259 assert(generator);
260 assert(generator_early);
261 assert(generator_late);
262
263 switch (scope) {
264
265 case UNIT_FILE_SYSTEM:
266 prefix = "/run/systemd/";
267 break;
268
269 case UNIT_FILE_USER: {
270 const char *e;
271
272 e = getenv("XDG_RUNTIME_DIR");
273 if (!e)
274 return -ENXIO;
275
276 prefix = strjoina(e, "/systemd/", NULL);
277 break;
278 }
279
280 case UNIT_FILE_GLOBAL:
281 return -EOPNOTSUPP;
282
283 default:
284 assert_not_reached("Hmm, unexpected scope value.");
285 }
286
287 x = strappend(prefix, "generator");
288 if (!x)
289 return -ENOMEM;
290
291 y = strappend(prefix, "generator.early");
292 if (!y)
293 return -ENOMEM;
294
295 z = strappend(prefix, "generator.late");
296 if (!z)
297 return -ENOMEM;
298
299 *generator = x;
300 *generator_early = y;
301 *generator_late = z;
302
303 x = y = z = NULL;
304 return 0;
305 }
306
307 static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
308 _cleanup_free_ char *a = NULL, *b = NULL;
309 int r;
310
311 assert(persistent);
312 assert(runtime);
313
314 switch (scope) {
315
316 case UNIT_FILE_SYSTEM:
317 a = strdup(SYSTEM_CONFIG_UNIT_PATH);
318 b = strdup("/run/systemd/system");
319 break;
320
321 case UNIT_FILE_GLOBAL:
322 a = strdup(USER_CONFIG_UNIT_PATH);
323 b = strdup("/run/systemd/user");
324 break;
325
326 case UNIT_FILE_USER:
327 r = user_config_home(&a);
328 if (r < 0)
329 return r;
330
331 r = user_runtime_dir(runtime);
332 if (r < 0)
333 return r;
334
335 *persistent = a;
336 a = NULL;
337
338 return 0;
339
340 default:
341 assert_not_reached("Hmm, unexpected scope value.");
342 }
343
344 if (!a || !b)
345 return -ENOMEM;
346
347 *persistent = a;
348 *runtime = b;
349 a = b = NULL;
350
351 return 0;
352 }
353
354 static int patch_root_prefix(char **p, const char *root_dir) {
355 char *c;
356
357 assert(p);
358
359 if (!*p)
360 return 0;
361
362 if (isempty(root_dir) || path_equal(root_dir, "/"))
363 return 0;
364
365 c = prefix_root(root_dir, *p);
366 if (!c)
367 return -ENOMEM;
368
369 free(*p);
370 *p = c;
371
372 return 0;
373 }
374
375 int lookup_paths_init(
376 LookupPaths *p,
377 UnitFileScope scope,
378 const char *root_dir) {
379
380 _cleanup_free_ char *generator = NULL, *generator_early = NULL, *generator_late = NULL,
381 *persistent_config = NULL, *runtime_config = NULL;
382 bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
383 char **l = NULL;
384 const char *e;
385 int r;
386
387 assert(p);
388 assert(scope >= 0);
389 assert(scope < _UNIT_FILE_SCOPE_MAX);
390
391 r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
392 if (r < 0)
393 return r;
394
395 r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late);
396 if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
397 return r;
398
399 /* First priority is whatever has been passed to us via env
400 * vars */
401 e = getenv("SYSTEMD_UNIT_PATH");
402 if (e) {
403 const char *k;
404
405 k = endswith(e, ":");
406 if (k) {
407 e = strndupa(e, k - e);
408 append = true;
409 }
410
411 /* FIXME: empty components in other places should be
412 * rejected. */
413
414 r = path_split_and_make_absolute(e, &l);
415 if (r < 0)
416 return r;
417 } else
418 l = NULL;
419
420 if (!l || append) {
421 /* Let's figure something out. */
422
423 _cleanup_strv_free_ char **add = NULL;
424
425 /* For the user units we include share/ in the search
426 * path in order to comply with the XDG basedir spec.
427 * For the system stuff we avoid such nonsense. OTOH
428 * we include /lib in the search path for the system
429 * stuff but avoid it for user stuff. */
430
431 switch (scope) {
432
433 case UNIT_FILE_SYSTEM:
434 add = strv_new(
435 /* If you modify this you also want to modify
436 * systemdsystemunitpath= in systemd.pc.in! */
437 STRV_IFNOTNULL(generator_early),
438 persistent_config,
439 "/etc/systemd/system",
440 runtime_config,
441 "/run/systemd/system",
442 STRV_IFNOTNULL(generator),
443 "/usr/local/lib/systemd/system",
444 SYSTEM_DATA_UNIT_PATH,
445 "/usr/lib/systemd/system",
446 #ifdef HAVE_SPLIT_USR
447 "/lib/systemd/system",
448 #endif
449 STRV_IFNOTNULL(generator_late),
450 NULL);
451 break;
452
453 case UNIT_FILE_GLOBAL:
454 add = strv_new(
455 /* If you modify this you also want to modify
456 * systemduserunitpath= in systemd.pc.in, and
457 * the arrays in user_dirs() above! */
458 STRV_IFNOTNULL(generator_early),
459 persistent_config,
460 "/etc/systemd/user",
461 runtime_config,
462 "/run/systemd/user",
463 STRV_IFNOTNULL(generator),
464 "/usr/local/lib/systemd/user",
465 "/usr/local/share/systemd/user",
466 USER_DATA_UNIT_PATH,
467 "/usr/lib/systemd/user",
468 "/usr/share/systemd/user",
469 STRV_IFNOTNULL(generator_late),
470 NULL);
471 break;
472
473 case UNIT_FILE_USER:
474 add = user_dirs(persistent_config, runtime_config,
475 generator, generator_early, generator_late);
476 break;
477
478 default:
479 assert_not_reached("Hmm, unexpected scope?");
480 }
481
482 if (!add)
483 return -ENOMEM;
484
485 if (l) {
486 r = strv_extend_strv(&l, add, false);
487 if (r < 0)
488 return r;
489 } else {
490 l = add;
491 add = NULL;
492 }
493 }
494
495 r = patch_root_prefix(&persistent_config, root_dir);
496 if (r < 0)
497 return r;
498 r = patch_root_prefix(&runtime_config, root_dir);
499 if (r < 0)
500 return r;
501
502 r = patch_root_prefix(&generator, root_dir);
503 if (r < 0)
504 return r;
505 r = patch_root_prefix(&generator_early, root_dir);
506 if (r < 0)
507 return r;
508 r = patch_root_prefix(&generator_late, root_dir);
509 if (r < 0)
510 return r;
511
512 if (!path_strv_resolve_uniq(l, root_dir))
513 return -ENOMEM;
514
515 if (strv_isempty(l)) {
516 log_debug("Ignoring unit files.");
517 l = strv_free(l);
518 } else {
519 _cleanup_free_ char *t;
520
521 t = strv_join(l, "\n\t");
522 if (!t)
523 return -ENOMEM;
524
525 log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
526 }
527
528 p->search_path = l;
529 l = NULL;
530
531 p->persistent_config = persistent_config;
532 p->runtime_config = runtime_config;
533 persistent_config = runtime_config = NULL;
534
535 p->generator = generator;
536 p->generator_early = generator_early;
537 p->generator_late = generator_late;
538 generator = generator_early = generator_late = NULL;
539
540 return 0;
541 }
542
543 void lookup_paths_free(LookupPaths *p) {
544 if (!p)
545 return;
546
547 p->search_path = strv_free(p->search_path);
548
549 p->persistent_config = mfree(p->persistent_config);
550 p->runtime_config = mfree(p->runtime_config);
551
552 p->generator = mfree(p->generator);
553 p->generator_early = mfree(p->generator_early);
554 p->generator_late = mfree(p->generator_late);
555 }