1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
23 #include "specifier.h"
25 #include "unit-name.h"
26 #include "unit-printf.h"
28 #include "cgroup-util.h"
29 #include "formats-util.h"
31 static int specifier_prefix_and_instance(char specifier
, void *data
, void *userdata
, char **ret
) {
37 n
= unit_name_to_prefix_and_instance(u
->id
);
45 static int specifier_prefix(char specifier
, void *data
, void *userdata
, char **ret
) {
51 n
= unit_name_to_prefix(u
->id
);
59 static int specifier_prefix_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
61 _cleanup_free_
char *p
= NULL
;
66 p
= unit_name_to_prefix(u
->id
);
70 n
= unit_name_unescape(p
);
78 static int specifier_instance_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
87 n
= unit_name_unescape(u
->instance
);
95 static int specifier_filename(char specifier
, void *data
, void *userdata
, char **ret
) {
102 n
= unit_name_path_unescape(u
->instance
);
104 n
= unit_name_to_path(u
->id
);
112 static int specifier_cgroup(char specifier
, void *data
, void *userdata
, char **ret
) {
119 n
= strdup(u
->cgroup_path
);
121 n
= unit_default_cgroup_path(u
);
129 static int specifier_cgroup_root(char specifier
, void *data
, void *userdata
, char **ret
) {
137 slice
= unit_slice_name(u
);
138 if (specifier
== 'R' || !slice
)
139 n
= strdup(u
->manager
->cgroup_root
);
141 _cleanup_free_
char *p
= NULL
;
143 r
= cg_slice_to_path(slice
, &p
);
147 n
= strjoin(u
->manager
->cgroup_root
, "/", p
, NULL
);
156 static int specifier_runtime(char specifier
, void *data
, void *userdata
, char **ret
) {
163 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
)
166 e
= getenv("XDG_RUNTIME_DIR");
179 static int specifier_user_name(char specifier
, void *data
, void *userdata
, char **ret
) {
180 char *printed
= NULL
;
187 c
= unit_get_exec_context(u
);
191 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
) {
193 /* We cannot use NSS from PID 1, hence try to make the
194 * best of it in that case, and fail if we can't help
197 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
198 printed
= strdup(specifier
== 'u' ? "root" : "0");
200 if (specifier
== 'u')
201 printed
= strdup(c
->user
);
205 r
= parse_uid(c
->user
, &uid
);
209 r
= asprintf(&printed
, UID_FMT
, uid
);
214 _cleanup_free_
char *tmp
= NULL
;
215 const char *username
= NULL
;
221 /* get USER env from env or our own uid */
222 username
= tmp
= getusername_malloc();
224 /* fish username from passwd */
225 r
= get_user_creds(&username
, &uid
, NULL
, NULL
, NULL
);
229 if (specifier
== 'u')
230 printed
= strdup(username
);
232 r
= asprintf(&printed
, UID_FMT
, uid
);
235 if (r
< 0 || !printed
)
242 static int specifier_user_home(char specifier
, void *data
, void *userdata
, char **ret
) {
250 c
= unit_get_exec_context(u
);
254 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
) {
256 /* We cannot use NSS from PID 1, hence try to make the
257 * best of it if we can, but fail if we can't */
259 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
266 /* return HOME if set, otherwise from passwd */
267 if (!c
|| !c
->user
) {
268 r
= get_home_dir(&n
);
272 const char *username
, *home
;
275 r
= get_user_creds(&username
, NULL
, NULL
, &home
, NULL
);
290 static int specifier_user_shell(char specifier
, void *data
, void *userdata
, char **ret
) {
298 c
= unit_get_exec_context(u
);
302 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
) {
304 /* We cannot use NSS from PID 1, hence try to make the
305 * best of it if we can, but fail if we can't */
307 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
308 n
= strdup("/bin/sh");
314 /* return /bin/sh for root, otherwise the value from passwd */
320 const char *username
, *shell
;
323 r
= get_user_creds(&username
, NULL
, NULL
, NULL
, &shell
);
338 int unit_name_printf(Unit
*u
, const char* format
, char **ret
) {
341 * This will use the passed string as format string and
342 * replace the following specifiers:
344 * %n: the full id of the unit (foo@bar.waldo)
345 * %N: the id of the unit without the suffix (foo@bar)
346 * %p: the prefix (foo)
347 * %i: the instance (bar)
350 const Specifier table
[] = {
351 { 'n', specifier_string
, u
->id
},
352 { 'N', specifier_prefix_and_instance
, NULL
},
353 { 'p', specifier_prefix
, NULL
},
354 { 'i', specifier_string
, u
->instance
},
362 return specifier_printf(format
, table
, u
, ret
);
365 int unit_full_printf(Unit
*u
, const char *format
, char **ret
) {
367 /* This is similar to unit_name_printf() but also supports
368 * unescaping. Also, adds a couple of additional codes:
370 * %f the instance if set, otherwise the id
371 * %c cgroup path of unit
372 * %r where units in this slice are placed in the cgroup tree
373 * %R the root of this systemd's instance tree
374 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
375 * %U the UID of the configured user or running user
376 * %u the username of the configured user or running user
377 * %h the homedir of the configured user or running user
378 * %s the shell of the configured user or running user
379 * %m the machine ID of the running system
380 * %H the host name of the running system
381 * %b the boot ID of the running system
382 * %v `uname -r` of the running system
385 const Specifier table
[] = {
386 { 'n', specifier_string
, u
->id
},
387 { 'N', specifier_prefix_and_instance
, NULL
},
388 { 'p', specifier_prefix
, NULL
},
389 { 'P', specifier_prefix_unescaped
, NULL
},
390 { 'i', specifier_string
, u
->instance
},
391 { 'I', specifier_instance_unescaped
, NULL
},
393 { 'f', specifier_filename
, NULL
},
394 { 'c', specifier_cgroup
, NULL
},
395 { 'r', specifier_cgroup_root
, NULL
},
396 { 'R', specifier_cgroup_root
, NULL
},
397 { 't', specifier_runtime
, NULL
},
398 { 'U', specifier_user_name
, NULL
},
399 { 'u', specifier_user_name
, NULL
},
400 { 'h', specifier_user_home
, NULL
},
401 { 's', specifier_user_shell
, NULL
},
403 { 'm', specifier_machine_id
, NULL
},
404 { 'H', specifier_host_name
, NULL
},
405 { 'b', specifier_boot_id
, NULL
},
406 { 'v', specifier_kernel_release
, NULL
},
414 return specifier_printf(format
, table
, u
, ret
);
417 int unit_full_printf_strv(Unit
*u
, char **l
, char ***ret
) {
422 /* Applies unit_full_printf to every entry in l */
431 for (i
= l
, j
= r
; *i
; i
++, j
++) {
432 q
= unit_full_printf(u
, *i
, j
);
442 for (j
--; j
>= r
; j
--)