]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-printf.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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
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 32static 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 40static 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 48static 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 62static 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 73static 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 84static 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 101static 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
115static 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 137static 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 160static 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 223static 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 271static 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 319int 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 346int 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 398int 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
422fail:
423 for (j--; j >= r; j--)
424 free(*j);
425
426 free(r);
19f6d710 427 return q;
41f9172f 428}