]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-printf.c
Always check asprintf return code
[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
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 33static 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 47static 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 61static 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 80static 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 97static 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 114static 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 131static 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 158static 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 181static 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 244static 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 292static 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 340int 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 367int 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 419int 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
443fail:
444 for (j--; j >= r; j--)
445 free(*j);
446
447 free(r);
19f6d710 448 return q;
41f9172f 449}