]>
Commit | Line | Data |
---|---|---|
41f9172f LP |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
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 Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 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 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
07630cea LP |
22 | #include "cgroup-util.h" |
23 | #include "formats-util.h" | |
24 | #include "macro.h" | |
41f9172f | 25 | #include "specifier.h" |
07630cea | 26 | #include "string-util.h" |
41f9172f LP |
27 | #include "strv.h" |
28 | #include "unit-name.h" | |
07630cea | 29 | #include "unit.h" |
41f9172f LP |
30 | #include "unit-printf.h" |
31 | ||
19f6d710 | 32 | static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 33 | Unit *u = userdata; |
19f6d710 | 34 | |
41f9172f LP |
35 | assert(u); |
36 | ||
7410616c | 37 | return unit_name_to_prefix_and_instance(u->id, ret); |
41f9172f LP |
38 | } |
39 | ||
19f6d710 | 40 | static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 41 | Unit *u = userdata; |
19f6d710 | 42 | |
41f9172f LP |
43 | assert(u); |
44 | ||
7410616c | 45 | return unit_name_to_prefix(u->id, ret); |
41f9172f LP |
46 | } |
47 | ||
19f6d710 | 48 | static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) { |
19f6d710 | 49 | _cleanup_free_ char *p = NULL; |
7410616c LP |
50 | Unit *u = userdata; |
51 | int r; | |
41f9172f LP |
52 | |
53 | assert(u); | |
54 | ||
7410616c LP |
55 | r = unit_name_to_prefix(u->id, &p); |
56 | if (r < 0) | |
57 | return r; | |
41f9172f | 58 | |
7410616c | 59 | return unit_name_unescape(p, ret); |
41f9172f LP |
60 | } |
61 | ||
19f6d710 | 62 | static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 63 | Unit *u = userdata; |
19f6d710 | 64 | |
41f9172f LP |
65 | assert(u); |
66 | ||
2cfbd749 | 67 | if (!u->instance) |
7410616c | 68 | return -EINVAL; |
41f9172f | 69 | |
7410616c | 70 | return unit_name_unescape(u->instance, ret); |
41f9172f LP |
71 | } |
72 | ||
19f6d710 | 73 | static int specifier_filename(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 74 | Unit *u = userdata; |
19f6d710 | 75 | |
41f9172f LP |
76 | assert(u); |
77 | ||
78 | if (u->instance) | |
7410616c | 79 | return unit_name_path_unescape(u->instance, ret); |
19f6d710 | 80 | else |
7410616c | 81 | return unit_name_to_path(u->id, ret); |
41f9172f LP |
82 | } |
83 | ||
19f6d710 | 84 | static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 85 | Unit *u = userdata; |
19f6d710 LP |
86 | char *n; |
87 | ||
41f9172f LP |
88 | assert(u); |
89 | ||
2cfbd749 LP |
90 | if (u->cgroup_path) |
91 | n = strdup(u->cgroup_path); | |
92 | else | |
93 | n = unit_default_cgroup_path(u); | |
19f6d710 LP |
94 | if (!n) |
95 | return -ENOMEM; | |
96 | ||
97 | *ret = n; | |
98 | return 0; | |
41f9172f LP |
99 | } |
100 | ||
19f6d710 | 101 | static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 102 | Unit *u = userdata; |
19f6d710 | 103 | char *n; |
41f9172f | 104 | |
9444b1f2 | 105 | assert(u); |
41f9172f | 106 | |
696fd1ef LP |
107 | n = strdup(u->manager->cgroup_root); |
108 | if (!n) | |
109 | return -ENOMEM; | |
41f9172f | 110 | |
696fd1ef LP |
111 | *ret = n; |
112 | return 0; | |
113 | } | |
19f6d710 | 114 | |
696fd1ef LP |
115 | static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) { |
116 | Unit *u = userdata; | |
117 | char *n; | |
118 | ||
119 | assert(u); | |
120 | ||
121 | if (UNIT_ISSET(u->slice)) { | |
122 | Unit *slice; | |
123 | ||
124 | slice = UNIT_DEREF(u->slice); | |
125 | ||
126 | if (slice->cgroup_path) | |
127 | n = strdup(slice->cgroup_path); | |
128 | else | |
129 | n = unit_default_cgroup_path(slice); | |
130 | } else | |
131 | n = strdup(u->manager->cgroup_root); | |
41f9172f | 132 | |
19f6d710 LP |
133 | *ret = n; |
134 | return 0; | |
41f9172f LP |
135 | } |
136 | ||
19f6d710 | 137 | static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 138 | Unit *u = userdata; |
2cfbd749 | 139 | const char *e; |
19f6d710 LP |
140 | char *n = NULL; |
141 | ||
41f9172f LP |
142 | assert(u); |
143 | ||
b2c23da8 | 144 | if (u->manager->running_as == MANAGER_SYSTEM) |
2cfbd749 LP |
145 | e = "/run"; |
146 | else { | |
41f9172f | 147 | e = getenv("XDG_RUNTIME_DIR"); |
2cfbd749 | 148 | if (!e) |
15411c0c | 149 | return -EOPNOTSUPP; |
41f9172f LP |
150 | } |
151 | ||
2cfbd749 LP |
152 | n = strdup(e); |
153 | if (!n) | |
154 | return -ENOMEM; | |
19f6d710 LP |
155 | |
156 | *ret = n; | |
157 | return 0; | |
41f9172f LP |
158 | } |
159 | ||
19f6d710 | 160 | static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { |
2cfbd749 | 161 | char *printed = NULL; |
3ef63c31 LP |
162 | Unit *u = userdata; |
163 | ExecContext *c; | |
7de80bfe | 164 | int r = 0; |
41f9172f | 165 | |
6569cae1 LP |
166 | assert(u); |
167 | ||
3ef63c31 | 168 | c = unit_get_exec_context(u); |
2cfbd749 | 169 | if (!c) |
7410616c | 170 | return -EINVAL; |
3ef63c31 | 171 | |
b2c23da8 | 172 | if (u->manager->running_as == MANAGER_SYSTEM) { |
2cfbd749 LP |
173 | |
174 | /* We cannot use NSS from PID 1, hence try to make the | |
175 | * best of it in that case, and fail if we can't help | |
176 | * it */ | |
177 | ||
178 | if (!c->user || streq(c->user, "root") || streq(c->user, "0")) | |
179 | printed = strdup(specifier == 'u' ? "root" : "0"); | |
180 | else { | |
181 | if (specifier == 'u') | |
182 | printed = strdup(c->user); | |
183 | else { | |
184 | uid_t uid; | |
185 | ||
186 | r = parse_uid(c->user, &uid); | |
187 | if (r < 0) | |
188 | return -ENODATA; | |
189 | ||
7de80bfe | 190 | r = asprintf(&printed, UID_FMT, uid); |
2cfbd749 LP |
191 | } |
192 | } | |
193 | ||
194 | } else { | |
195 | _cleanup_free_ char *tmp = NULL; | |
196 | const char *username = NULL; | |
197 | uid_t uid; | |
198 | ||
199 | if (c->user) | |
200 | username = c->user; | |
201 | else | |
202 | /* get USER env from env or our own uid */ | |
203 | username = tmp = getusername_malloc(); | |
204 | ||
205 | /* fish username from passwd */ | |
206 | r = get_user_creds(&username, &uid, NULL, NULL, NULL); | |
207 | if (r < 0) | |
208 | return r; | |
209 | ||
210 | if (specifier == 'u') | |
067d851d | 211 | printed = strdup(username); |
2cfbd749 | 212 | else |
7de80bfe | 213 | r = asprintf(&printed, UID_FMT, uid); |
067d851d DW |
214 | } |
215 | ||
7de80bfe | 216 | if (r < 0 || !printed) |
19f6d710 LP |
217 | return -ENOMEM; |
218 | ||
219 | *ret = printed; | |
220 | return 0; | |
41f9172f LP |
221 | } |
222 | ||
19f6d710 | 223 | static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { |
3ef63c31 LP |
224 | Unit *u = userdata; |
225 | ExecContext *c; | |
19f6d710 | 226 | char *n; |
2cfbd749 | 227 | int r; |
41f9172f | 228 | |
6569cae1 LP |
229 | assert(u); |
230 | ||
3ef63c31 | 231 | c = unit_get_exec_context(u); |
2cfbd749 | 232 | if (!c) |
15411c0c | 233 | return -EOPNOTSUPP; |
3ef63c31 | 234 | |
b2c23da8 | 235 | if (u->manager->running_as == MANAGER_SYSTEM) { |
41f9172f | 236 | |
2cfbd749 LP |
237 | /* We cannot use NSS from PID 1, hence try to make the |
238 | * best of it if we can, but fail if we can't */ | |
41f9172f | 239 | |
2cfbd749 LP |
240 | if (!c->user || streq(c->user, "root") || streq(c->user, "0")) |
241 | n = strdup("/root"); | |
242 | else | |
15411c0c | 243 | return -EOPNOTSUPP; |
2cfbd749 LP |
244 | |
245 | } else { | |
41f9172f | 246 | |
2cfbd749 LP |
247 | /* return HOME if set, otherwise from passwd */ |
248 | if (!c || !c->user) { | |
249 | r = get_home_dir(&n); | |
250 | if (r < 0) | |
251 | return r; | |
252 | } else { | |
253 | const char *username, *home; | |
254 | ||
255 | username = c->user; | |
256 | r = get_user_creds(&username, NULL, NULL, &home, NULL); | |
257 | if (r < 0) | |
258 | return r; | |
259 | ||
260 | n = strdup(home); | |
261 | } | |
262 | } | |
41f9172f | 263 | |
19f6d710 LP |
264 | if (!n) |
265 | return -ENOMEM; | |
266 | ||
267 | *ret = n; | |
268 | return 0; | |
41f9172f LP |
269 | } |
270 | ||
19f6d710 | 271 | static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { |
3ef63c31 LP |
272 | Unit *u = userdata; |
273 | ExecContext *c; | |
19f6d710 | 274 | char *n; |
2cfbd749 | 275 | int r; |
41f9172f | 276 | |
6569cae1 LP |
277 | assert(u); |
278 | ||
3ef63c31 | 279 | c = unit_get_exec_context(u); |
2cfbd749 | 280 | if (!c) |
15411c0c | 281 | return -EOPNOTSUPP; |
3ef63c31 | 282 | |
b2c23da8 | 283 | if (u->manager->running_as == MANAGER_SYSTEM) { |
2cfbd749 LP |
284 | |
285 | /* We cannot use NSS from PID 1, hence try to make the | |
286 | * best of it if we can, but fail if we can't */ | |
287 | ||
288 | if (!c->user || streq(c->user, "root") || streq(c->user, "0")) | |
289 | n = strdup("/bin/sh"); | |
290 | else | |
15411c0c | 291 | return -EOPNOTSUPP; |
41f9172f | 292 | |
2cfbd749 LP |
293 | } else { |
294 | ||
295 | /* return /bin/sh for root, otherwise the value from passwd */ | |
296 | if (!c->user) { | |
297 | r = get_shell(&n); | |
298 | if (r < 0) | |
299 | return r; | |
300 | } else { | |
301 | const char *username, *shell; | |
302 | ||
303 | username = c->user; | |
304 | r = get_user_creds(&username, NULL, NULL, NULL, &shell); | |
305 | if (r < 0) | |
306 | return r; | |
307 | ||
308 | n = strdup(shell); | |
309 | } | |
310 | } | |
41f9172f | 311 | |
19f6d710 LP |
312 | if (!n) |
313 | return -ENOMEM; | |
41f9172f | 314 | |
19f6d710 LP |
315 | *ret = n; |
316 | return 0; | |
41f9172f LP |
317 | } |
318 | ||
19f6d710 | 319 | int unit_name_printf(Unit *u, const char* format, char **ret) { |
41f9172f LP |
320 | |
321 | /* | |
322 | * This will use the passed string as format string and | |
323 | * replace the following specifiers: | |
324 | * | |
325 | * %n: the full id of the unit (foo@bar.waldo) | |
326 | * %N: the id of the unit without the suffix (foo@bar) | |
327 | * %p: the prefix (foo) | |
328 | * %i: the instance (bar) | |
329 | */ | |
330 | ||
331 | const Specifier table[] = { | |
332 | { 'n', specifier_string, u->id }, | |
333 | { 'N', specifier_prefix_and_instance, NULL }, | |
334 | { 'p', specifier_prefix, NULL }, | |
335 | { 'i', specifier_string, u->instance }, | |
336 | { 0, NULL, NULL } | |
337 | }; | |
338 | ||
339 | assert(u); | |
340 | assert(format); | |
19f6d710 | 341 | assert(ret); |
41f9172f | 342 | |
19f6d710 | 343 | return specifier_printf(format, table, u, ret); |
41f9172f LP |
344 | } |
345 | ||
19f6d710 | 346 | int unit_full_printf(Unit *u, const char *format, char **ret) { |
41f9172f LP |
347 | |
348 | /* This is similar to unit_name_printf() but also supports | |
349 | * unescaping. Also, adds a couple of additional codes: | |
350 | * | |
dca348bc | 351 | * %f the instance if set, otherwise the id |
41f9172f | 352 | * %c cgroup path of unit |
2cfbd749 | 353 | * %r where units in this slice are placed in the cgroup tree |
9444b1f2 | 354 | * %R the root of this systemd's instance tree |
41f9172f | 355 | * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) |
7584d236 | 356 | * %U the UID of the configured user or running user |
41f9172f LP |
357 | * %u the username of the configured user or running user |
358 | * %h the homedir of the configured user or running user | |
359 | * %s the shell of the configured user or running user | |
6569cae1 | 360 | * %m the machine ID of the running system |
6569cae1 | 361 | * %H the host name of the running system |
7584d236 | 362 | * %b the boot ID of the running system |
6aaa8c2f | 363 | * %v `uname -r` of the running system |
41f9172f LP |
364 | */ |
365 | ||
366 | const Specifier table[] = { | |
367 | { 'n', specifier_string, u->id }, | |
368 | { 'N', specifier_prefix_and_instance, NULL }, | |
369 | { 'p', specifier_prefix, NULL }, | |
370 | { 'P', specifier_prefix_unescaped, NULL }, | |
371 | { 'i', specifier_string, u->instance }, | |
372 | { 'I', specifier_instance_unescaped, NULL }, | |
373 | ||
374 | { 'f', specifier_filename, NULL }, | |
375 | { 'c', specifier_cgroup, NULL }, | |
696fd1ef | 376 | { 'r', specifier_cgroup_slice, NULL }, |
41f9172f LP |
377 | { 'R', specifier_cgroup_root, NULL }, |
378 | { 't', specifier_runtime, NULL }, | |
067d851d | 379 | { 'U', specifier_user_name, NULL }, |
41f9172f LP |
380 | { 'u', specifier_user_name, NULL }, |
381 | { 'h', specifier_user_home, NULL }, | |
382 | { 's', specifier_user_shell, NULL }, | |
6569cae1 LP |
383 | |
384 | { 'm', specifier_machine_id, NULL }, | |
385 | { 'H', specifier_host_name, NULL }, | |
386 | { 'b', specifier_boot_id, NULL }, | |
6aaa8c2f ZJS |
387 | { 'v', specifier_kernel_release, NULL }, |
388 | {} | |
41f9172f LP |
389 | }; |
390 | ||
19f6d710 | 391 | assert(u); |
41f9172f | 392 | assert(format); |
19f6d710 | 393 | assert(ret); |
41f9172f | 394 | |
19f6d710 | 395 | return specifier_printf(format, table, u, ret); |
41f9172f LP |
396 | } |
397 | ||
19f6d710 | 398 | int unit_full_printf_strv(Unit *u, char **l, char ***ret) { |
41f9172f LP |
399 | size_t n; |
400 | char **r, **i, **j; | |
19f6d710 | 401 | int q; |
41f9172f LP |
402 | |
403 | /* Applies unit_full_printf to every entry in l */ | |
404 | ||
405 | assert(u); | |
406 | ||
407 | n = strv_length(l); | |
408 | r = new(char*, n+1); | |
409 | if (!r) | |
19f6d710 | 410 | return -ENOMEM; |
41f9172f LP |
411 | |
412 | for (i = l, j = r; *i; i++, j++) { | |
19f6d710 LP |
413 | q = unit_full_printf(u, *i, j); |
414 | if (q < 0) | |
41f9172f LP |
415 | goto fail; |
416 | } | |
417 | ||
418 | *j = NULL; | |
19f6d710 LP |
419 | *ret = r; |
420 | return 0; | |
41f9172f LP |
421 | |
422 | fail: | |
423 | for (j--; j >= r; j--) | |
424 | free(*j); | |
425 | ||
426 | free(r); | |
19f6d710 | 427 | return q; |
41f9172f | 428 | } |