]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/path-lookup.c
automount: also whine if an automount directory is not empty
[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>
25#include <unistd.h>
26#include <errno.h>
27
28#include "util.h"
49e942b2 29#include "mkdir.h"
84e3543e 30#include "strv.h"
9eb977db 31#include "path-util.h"
84e3543e
LP
32#include "path-lookup.h"
33
af2d49f7 34int user_config_home(char **config_home) {
10e87ee7
LP
35 const char *e;
36
07719a21
LP
37 e = getenv("XDG_CONFIG_HOME");
38 if (e) {
af2d49f7 39 if (asprintf(config_home, "%s/systemd/user", e) < 0)
10e87ee7
LP
40 return -ENOMEM;
41
42 return 1;
43 } else {
44 const char *home;
45
07719a21
LP
46 home = getenv("HOME");
47 if (home) {
af2d49f7 48 if (asprintf(config_home, "%s/.config/systemd/user", home) < 0)
10e87ee7
LP
49 return -ENOMEM;
50
51 return 1;
52 }
53 }
54
55 return 0;
56}
57
07719a21
LP
58static char** user_dirs(
59 const char *generator,
60 const char *generator_early,
61 const char *generator_late) {
62
f437d5d2 63 const char * const config_unit_paths[] = {
f437d5d2 64 USER_CONFIG_UNIT_PATH,
4bf2bbb6 65 "/etc/systemd/user",
fc1a2e06 66 "/run/systemd/user",
4bf2bbb6 67 NULL
f437d5d2
LP
68 };
69
70 const char * const data_unit_paths[] = {
71 "/usr/local/lib/systemd/user",
72 "/usr/local/share/systemd/user",
73 USER_DATA_UNIT_PATH,
74 "/usr/lib/systemd/user",
4bf2bbb6
LP
75 "/usr/share/systemd/user",
76 NULL
f437d5d2
LP
77 };
78
84e3543e
LP
79 const char *home, *e;
80 char *config_home = NULL, *data_home = NULL;
81 char **config_dirs = NULL, **data_dirs = NULL;
82 char **r = NULL, **t;
83
84 /* Implement the mechanisms defined in
85 *
86 * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
87 *
88 * We look in both the config and the data dirs because we
89 * want to encourage that distributors ship their unit files
90 * as data, and allow overriding as configuration.
91 */
92
af2d49f7 93 if (user_config_home(&config_home) < 0)
10e87ee7 94 goto fail;
84e3543e 95
10e87ee7 96 home = getenv("HOME");
84e3543e 97
07719a21
LP
98 e = getenv("XDG_CONFIG_DIRS");
99 if (e) {
100 config_dirs = strv_split(e, ":");
101 if (!config_dirs)
84e3543e 102 goto fail;
07719a21 103 }
84e3543e
LP
104
105 /* We don't treat /etc/xdg/systemd here as the spec
106 * suggests because we assume that that is a link to
107 * /etc/systemd/ anyway. */
108
07719a21
LP
109 e = getenv("XDG_DATA_HOME");
110 if (e) {
af2d49f7 111 if (asprintf(&data_home, "%s/systemd/user", e) < 0)
84e3543e
LP
112 goto fail;
113
114 } else if (home) {
af2d49f7 115 if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
84e3543e
LP
116 goto fail;
117
118 /* There is really no need for two unit dirs in $HOME,
119 * except to be fully compliant with the XDG spec. We
120 * now try to link the two dirs, so that we can
121 * minimize disk seeks a little. Further down we'll
122 * then filter out this link, if it is actually is
123 * one. */
124
d2e54fae 125 mkdir_parents_label(data_home, 0777);
af2d49f7 126 (void) symlink("../../../.config/systemd/user", data_home);
84e3543e
LP
127 }
128
07719a21
LP
129 e = getenv("XDG_DATA_DIRS");
130 if (e)
84e3543e
LP
131 data_dirs = strv_split(e, ":");
132 else
ef3102bf 133 data_dirs = strv_new("/usr/local/share",
ef3102bf 134 "/usr/share",
ef3102bf 135 NULL);
84e3543e
LP
136 if (!data_dirs)
137 goto fail;
138
139 /* Now merge everything we found. */
07719a21
LP
140 if (generator_early) {
141 t = strv_append(r, generator_early);
142 if (!t)
143 goto fail;
144 strv_free(r);
145 r = t;
146 }
147
84e3543e 148 if (config_home) {
07719a21
LP
149 t = strv_append(r, config_home);
150 if (!t)
84e3543e
LP
151 goto fail;
152 strv_free(r);
153 r = t;
154 }
155
f437d5d2 156 if (!strv_isempty(config_dirs)) {
07719a21
LP
157 t = strv_merge_concat(r, config_dirs, "/systemd/user");
158 if (!t)
f437d5d2
LP
159 goto finish;
160 strv_free(r);
161 r = t;
162 }
84e3543e 163
07719a21
LP
164 t = strv_merge(r, (char**) config_unit_paths);
165 if (!t)
84e3543e
LP
166 goto fail;
167 strv_free(r);
168 r = t;
169
07719a21
LP
170 if (generator) {
171 t = strv_append(r, generator);
172 if (!t)
173 goto fail;
174 strv_free(r);
175 r = t;
176 }
177
84e3543e 178 if (data_home) {
07719a21
LP
179 t = strv_append(r, data_home);
180 if (!t)
84e3543e
LP
181 goto fail;
182 strv_free(r);
183 r = t;
184 }
185
f437d5d2 186 if (!strv_isempty(data_dirs)) {
07719a21
LP
187 t = strv_merge_concat(r, data_dirs, "/systemd/user");
188 if (!t)
f437d5d2
LP
189 goto fail;
190 strv_free(r);
191 r = t;
192 }
84e3543e 193
07719a21
LP
194 t = strv_merge(r, (char**) data_unit_paths);
195 if (!t)
84e3543e
LP
196 goto fail;
197 strv_free(r);
198 r = t;
199
07719a21
LP
200 if (generator_late) {
201 t = strv_append(r, generator_late);
202 if (!t)
203 goto fail;
204 strv_free(r);
205 r = t;
206 }
207
9eb977db 208 if (!path_strv_make_absolute_cwd(r))
07719a21 209 goto fail;
84e3543e
LP
210
211finish:
212 free(config_home);
213 strv_free(config_dirs);
214 free(data_home);
215 strv_free(data_dirs);
216
217 return r;
218
219fail:
220 strv_free(r);
221 r = NULL;
222 goto finish;
223}
224
07719a21
LP
225int lookup_paths_init(
226 LookupPaths *p,
227 ManagerRunningAs running_as,
228 bool personal,
229 const char *generator,
230 const char *generator_early,
231 const char *generator_late) {
232
84e3543e
LP
233 const char *e;
234 char *t;
235
236 assert(p);
237
238 /* First priority is whatever has been passed to us via env
239 * vars */
07719a21
LP
240 e = getenv("SYSTEMD_UNIT_PATH");
241 if (e) {
242 p->unit_path = path_split_and_make_absolute(e);
243 if (!p->unit_path)
84e3543e 244 return -ENOMEM;
07719a21
LP
245 } else
246 p->unit_path = NULL;
84e3543e
LP
247
248 if (strv_isempty(p->unit_path)) {
84e3543e
LP
249 /* Nothing is set, so let's figure something out. */
250 strv_free(p->unit_path);
251
07719a21
LP
252 /* For the user units we include share/ in the search
253 * path in order to comply with the XDG basedir
254 * spec. For the system stuff we avoid such
255 * nonsense. OTOH we include /lib in the search path
256 * for the system stuff but avoid it for user
257 * stuff. */
258
af2d49f7 259 if (running_as == MANAGER_USER) {
c800e483
LP
260
261 if (personal)
07719a21 262 p->unit_path = user_dirs(generator, generator_early, generator_late);
c800e483
LP
263 else
264 p->unit_path = strv_new(
265 /* If you modify this you also want to modify
266 * systemduserunitpath= in systemd.pc.in, and
267 * the arrays in user_dirs() above! */
07719a21 268 STRV_IFNOTNULL(generator_early),
c800e483 269 USER_CONFIG_UNIT_PATH,
a5afffa1 270 "/etc/systemd/user",
fc1a2e06 271 "/run/systemd/user",
07719a21 272 STRV_IFNOTNULL(generator),
c800e483
LP
273 "/usr/local/lib/systemd/user",
274 "/usr/local/share/systemd/user",
275 USER_DATA_UNIT_PATH,
276 "/usr/lib/systemd/user",
277 "/usr/share/systemd/user",
07719a21 278 STRV_IFNOTNULL(generator_late),
c800e483
LP
279 NULL);
280
281 if (!p->unit_path)
84e3543e 282 return -ENOMEM;
c800e483 283
07719a21
LP
284 } else {
285 p->unit_path = strv_new(
286 /* If you modify this you also want to modify
287 * systemdsystemunitpath= in systemd.pc.in! */
288 STRV_IFNOTNULL(generator_early),
289 SYSTEM_CONFIG_UNIT_PATH,
290 "/etc/systemd/system",
291 "/run/systemd/system",
292 STRV_IFNOTNULL(generator),
293 "/usr/local/lib/systemd/system",
294 SYSTEM_DATA_UNIT_PATH,
295 "/usr/lib/systemd/system",
283b73b3 296#ifdef HAVE_SPLIT_USR
07719a21 297 "/lib/systemd/system",
283b73b3 298#endif
07719a21
LP
299 STRV_IFNOTNULL(generator_late),
300 NULL);
301
302 if (!p->unit_path)
84e3543e 303 return -ENOMEM;
07719a21 304 }
84e3543e
LP
305 }
306
07719a21
LP
307 if (!path_strv_canonicalize(p->unit_path))
308 return -ENOMEM;
07459bb6
FF
309
310 strv_uniq(p->unit_path);
9eb977db 311 path_strv_remove_empty(p->unit_path);
07459bb6
FF
312
313 if (!strv_isempty(p->unit_path)) {
314
07719a21
LP
315 t = strv_join(p->unit_path, "\n\t");
316 if (!t)
07459bb6
FF
317 return -ENOMEM;
318 log_debug("Looking for unit files in:\n\t%s", t);
319 free(t);
320 } else {
321 log_debug("Ignoring unit files.");
322 strv_free(p->unit_path);
323 p->unit_path = NULL;
324 }
325
a3d4e06d 326 if (running_as == MANAGER_SYSTEM) {
07459bb6 327#ifdef HAVE_SYSV_COMPAT
84e3543e
LP
328 /* /etc/init.d/ compatibility does not matter to users */
329
07719a21
LP
330 e = getenv("SYSTEMD_SYSVINIT_PATH");
331 if (e) {
332 p->sysvinit_path = path_split_and_make_absolute(e);
333 if (!p->sysvinit_path)
84e3543e 334 return -ENOMEM;
07719a21
LP
335 } else
336 p->sysvinit_path = NULL;
84e3543e
LP
337
338 if (strv_isempty(p->sysvinit_path)) {
339 strv_free(p->sysvinit_path);
340
07719a21
LP
341 p->sysvinit_path = strv_new(
342 SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
343 NULL);
344 if (!p->sysvinit_path)
84e3543e
LP
345 return -ENOMEM;
346 }
347
07719a21
LP
348 e = getenv("SYSTEMD_SYSVRCND_PATH");
349 if (e) {
350 p->sysvrcnd_path = path_split_and_make_absolute(e);
351 if (!p->sysvrcnd_path)
84e3543e 352 return -ENOMEM;
07719a21
LP
353 } else
354 p->sysvrcnd_path = NULL;
84e3543e
LP
355
356 if (strv_isempty(p->sysvrcnd_path)) {
357 strv_free(p->sysvrcnd_path);
358
07719a21
LP
359 p->sysvrcnd_path = strv_new(
360 SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
361 NULL);
362 if (!p->sysvrcnd_path)
84e3543e
LP
363 return -ENOMEM;
364 }
84e3543e 365
07719a21
LP
366 if (!path_strv_canonicalize(p->sysvinit_path))
367 return -ENOMEM;
84e3543e 368
07719a21
LP
369 if (!path_strv_canonicalize(p->sysvrcnd_path))
370 return -ENOMEM;
84e3543e 371
07459bb6
FF
372 strv_uniq(p->sysvinit_path);
373 strv_uniq(p->sysvrcnd_path);
9eb977db
KS
374 path_strv_remove_empty(p->sysvinit_path);
375 path_strv_remove_empty(p->sysvrcnd_path);
a9dd2082 376
07459bb6 377 if (!strv_isempty(p->sysvinit_path)) {
84e3543e 378
07719a21
LP
379 t = strv_join(p->sysvinit_path, "\n\t");
380 if (!t)
07459bb6 381 return -ENOMEM;
07459bb6
FF
382 log_debug("Looking for SysV init scripts in:\n\t%s", t);
383 free(t);
384 } else {
385 log_debug("Ignoring SysV init scripts.");
386 strv_free(p->sysvinit_path);
387 p->sysvinit_path = NULL;
388 }
84e3543e 389
07459bb6 390 if (!strv_isempty(p->sysvrcnd_path)) {
84e3543e 391
07719a21
LP
392 t = strv_join(p->sysvrcnd_path, "\n\t");
393 if (!t)
07459bb6 394 return -ENOMEM;
84e3543e 395
07459bb6
FF
396 log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
397 free(t);
398 } else {
399 log_debug("Ignoring SysV rcN.d links.");
400 strv_free(p->sysvrcnd_path);
401 p->sysvrcnd_path = NULL;
402 }
403#else
404 log_debug("Disabled SysV init scripts and rcN.d links support");
405#endif
84e3543e
LP
406 }
407
408 return 0;
409}
410
411void lookup_paths_free(LookupPaths *p) {
412 assert(p);
413
414 strv_free(p->unit_path);
07459bb6
FF
415 p->unit_path = NULL;
416
417#ifdef HAVE_SYSV_COMPAT
84e3543e
LP
418 strv_free(p->sysvinit_path);
419 strv_free(p->sysvrcnd_path);
07459bb6
FF
420 p->sysvinit_path = p->sysvrcnd_path = NULL;
421#endif
84e3543e 422}