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