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