]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-printf.c
core: s/reexection/reexecution/ typo fix
[thirdparty/systemd.git] / src / core / unit-printf.c
CommitLineData
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 31static 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 39static 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 47static 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 61static 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 72static 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 83static 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 100static 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
114static 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 136static 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 159static 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 222static 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 270static 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 318int 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 345int 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 397int 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
421fail:
422 for (j--; j >= r; j--)
423 free(*j);
424
425 free(r);
19f6d710 426 return q;
41f9172f 427}