]>
Commit | Line | Data |
---|---|---|
84e3543e LP |
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
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 | |
9 | under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2 of the License, or | |
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 | |
16 | General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
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" | |
29 | #include "strv.h" | |
30 | ||
31 | #include "path-lookup.h" | |
32 | ||
33 | static char** session_dirs(void) { | |
34 | const char *home, *e; | |
35 | char *config_home = NULL, *data_home = NULL; | |
36 | char **config_dirs = NULL, **data_dirs = NULL; | |
37 | char **r = NULL, **t; | |
38 | ||
39 | /* Implement the mechanisms defined in | |
40 | * | |
41 | * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html | |
42 | * | |
43 | * We look in both the config and the data dirs because we | |
44 | * want to encourage that distributors ship their unit files | |
45 | * as data, and allow overriding as configuration. | |
46 | */ | |
47 | ||
48 | home = getenv("HOME"); | |
49 | ||
50 | if ((e = getenv("XDG_CONFIG_HOME"))) { | |
51 | if (asprintf(&config_home, "%s/systemd/session", e) < 0) | |
52 | goto fail; | |
53 | ||
54 | } else if (home) { | |
55 | if (asprintf(&config_home, "%s/.config/systemd/session", home) < 0) | |
56 | goto fail; | |
57 | } | |
58 | ||
59 | if ((e = getenv("XDG_CONFIG_DIRS"))) | |
60 | if (!(config_dirs = strv_split(e, ":"))) | |
61 | goto fail; | |
62 | ||
63 | /* We don't treat /etc/xdg/systemd here as the spec | |
64 | * suggests because we assume that that is a link to | |
65 | * /etc/systemd/ anyway. */ | |
66 | ||
67 | if ((e = getenv("XDG_DATA_HOME"))) { | |
68 | if (asprintf(&data_home, "%s/systemd/session", e) < 0) | |
69 | goto fail; | |
70 | ||
71 | } else if (home) { | |
72 | if (asprintf(&data_home, "%s/.local/share/systemd/session", home) < 0) | |
73 | goto fail; | |
74 | ||
75 | /* There is really no need for two unit dirs in $HOME, | |
76 | * except to be fully compliant with the XDG spec. We | |
77 | * now try to link the two dirs, so that we can | |
78 | * minimize disk seeks a little. Further down we'll | |
79 | * then filter out this link, if it is actually is | |
80 | * one. */ | |
81 | ||
82 | mkdir_parents(data_home, 0777); | |
83 | symlink("../../../.config/systemd/session", data_home); | |
84 | } | |
85 | ||
86 | if ((e = getenv("XDG_DATA_DIRS"))) | |
87 | data_dirs = strv_split(e, ":"); | |
88 | else | |
89 | data_dirs = strv_new("/usr/local/share", "/usr/share", NULL); | |
90 | ||
91 | if (!data_dirs) | |
92 | goto fail; | |
93 | ||
94 | /* Now merge everything we found. */ | |
95 | if (config_home) { | |
96 | if (!(t = strv_append(r, config_home))) | |
97 | goto fail; | |
98 | strv_free(r); | |
99 | r = t; | |
100 | } | |
101 | ||
102 | if (!(t = strv_merge_concat(r, config_dirs, "/systemd/session"))) | |
103 | goto finish; | |
104 | strv_free(r); | |
105 | r = t; | |
106 | ||
107 | if (!(t = strv_append(r, SESSION_CONFIG_UNIT_PATH))) | |
108 | goto fail; | |
109 | strv_free(r); | |
110 | r = t; | |
111 | ||
112 | if (data_home) { | |
113 | if (!(t = strv_append(r, data_home))) | |
114 | goto fail; | |
115 | strv_free(r); | |
116 | r = t; | |
117 | } | |
118 | ||
119 | if (!(t = strv_merge_concat(r, data_dirs, "/systemd/session"))) | |
120 | goto fail; | |
121 | strv_free(r); | |
122 | r = t; | |
123 | ||
124 | if (!(t = strv_append(r, SESSION_DATA_UNIT_PATH))) | |
125 | goto fail; | |
126 | strv_free(r); | |
127 | r = t; | |
128 | ||
129 | if (!strv_path_make_absolute_cwd(r)) | |
130 | goto fail; | |
131 | ||
132 | finish: | |
133 | free(config_home); | |
134 | strv_free(config_dirs); | |
135 | free(data_home); | |
136 | strv_free(data_dirs); | |
137 | ||
138 | return r; | |
139 | ||
140 | fail: | |
141 | strv_free(r); | |
142 | r = NULL; | |
143 | goto finish; | |
144 | } | |
145 | ||
146 | int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as) { | |
147 | const char *e; | |
148 | char *t; | |
149 | ||
150 | assert(p); | |
151 | ||
152 | /* First priority is whatever has been passed to us via env | |
153 | * vars */ | |
154 | if ((e = getenv("SYSTEMD_UNIT_PATH"))) | |
155 | if (!(p->unit_path = split_path_and_make_absolute(e))) | |
156 | return -ENOMEM; | |
157 | ||
158 | if (strv_isempty(p->unit_path)) { | |
159 | ||
160 | /* Nothing is set, so let's figure something out. */ | |
161 | strv_free(p->unit_path); | |
162 | ||
163 | if (running_as == MANAGER_SESSION) { | |
164 | if (!(p->unit_path = session_dirs())) | |
165 | return -ENOMEM; | |
166 | } else | |
167 | if (!(p->unit_path = strv_new( | |
168 | SYSTEM_CONFIG_UNIT_PATH, /* /etc/systemd/system/ */ | |
169 | SYSTEM_DATA_UNIT_PATH, /* /lib/systemd/system/ */ | |
170 | NULL))) | |
171 | return -ENOMEM; | |
172 | } | |
173 | ||
174 | if (running_as == MANAGER_INIT) { | |
175 | /* /etc/init.d/ compatibility does not matter to users */ | |
176 | ||
177 | if ((e = getenv("SYSTEMD_SYSVINIT_PATH"))) | |
178 | if (!(p->sysvinit_path = split_path_and_make_absolute(e))) | |
179 | return -ENOMEM; | |
180 | ||
181 | if (strv_isempty(p->sysvinit_path)) { | |
182 | strv_free(p->sysvinit_path); | |
183 | ||
184 | if (!(p->sysvinit_path = strv_new( | |
185 | SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ | |
186 | NULL))) | |
187 | return -ENOMEM; | |
188 | } | |
189 | ||
190 | if ((e = getenv("SYSTEMD_SYSVRCND_PATH"))) | |
191 | if (!(p->sysvrcnd_path = split_path_and_make_absolute(e))) | |
192 | return -ENOMEM; | |
193 | ||
194 | if (strv_isempty(p->sysvrcnd_path)) { | |
195 | strv_free(p->sysvrcnd_path); | |
196 | ||
197 | if (!(p->sysvrcnd_path = strv_new( | |
198 | SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ | |
199 | NULL))) | |
200 | return -ENOMEM; | |
201 | } | |
202 | } | |
203 | ||
204 | if (p->unit_path) | |
205 | if (!strv_path_canonicalize(p->unit_path)) | |
206 | return -ENOMEM; | |
207 | ||
208 | if (p->sysvinit_path) | |
209 | if (!strv_path_canonicalize(p->sysvinit_path)) | |
210 | return -ENOMEM; | |
211 | ||
212 | if (p->sysvrcnd_path) | |
213 | if (!strv_path_canonicalize(p->sysvrcnd_path)) | |
214 | return -ENOMEM; | |
215 | ||
216 | strv_uniq(p->unit_path); | |
217 | strv_uniq(p->sysvinit_path); | |
218 | strv_uniq(p->sysvrcnd_path); | |
219 | ||
220 | if (!strv_isempty(p->unit_path)) { | |
221 | ||
222 | if (!(t = strv_join(p->unit_path, "\n\t"))) | |
223 | return -ENOMEM; | |
224 | log_debug("Looking for unit files in:\n\t%s", t); | |
225 | free(t); | |
226 | } else { | |
227 | log_debug("Ignoring unit files."); | |
228 | strv_free(p->unit_path); | |
229 | p->unit_path = NULL; | |
230 | } | |
231 | ||
232 | if (!strv_isempty(p->sysvinit_path)) { | |
233 | ||
234 | if (!(t = strv_join(p->sysvinit_path, "\n\t"))) | |
235 | return -ENOMEM; | |
236 | ||
237 | log_debug("Looking for SysV init scripts in:\n\t%s", t); | |
238 | free(t); | |
239 | } else { | |
240 | log_debug("Ignoring SysV init scripts."); | |
241 | strv_free(p->sysvinit_path); | |
242 | p->sysvinit_path = NULL; | |
243 | } | |
244 | ||
245 | if (!strv_isempty(p->sysvrcnd_path)) { | |
246 | ||
247 | if (!(t = strv_join(p->sysvrcnd_path, "\n\t"))) | |
248 | return -ENOMEM; | |
249 | ||
250 | log_debug("Looking for SysV rcN.d links in:\n\t%s", t); | |
251 | free(t); | |
252 | } else { | |
253 | log_debug("Ignoring SysV rcN.d links."); | |
254 | strv_free(p->sysvrcnd_path); | |
255 | p->sysvrcnd_path = NULL; | |
256 | } | |
257 | ||
258 | return 0; | |
259 | } | |
260 | ||
261 | void lookup_paths_free(LookupPaths *p) { | |
262 | assert(p); | |
263 | ||
264 | strv_free(p->unit_path); | |
265 | strv_free(p->sysvinit_path); | |
266 | strv_free(p->sysvrcnd_path); | |
267 | ||
268 | p->unit_path = p->sysvinit_path = p->sysvrcnd_path = NULL; | |
269 | } |