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