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/>.
24 #include "specifier.h"
25 #include "path-util.h"
27 #include "unit-name.h"
28 #include "unit-printf.h"
30 #include "cgroup-util.h"
33 static int specifier_prefix_and_instance(char specifier
, void *data
, void *userdata
, char **ret
) {
39 n
= unit_name_to_prefix_and_instance(u
->id
);
47 static int specifier_prefix(char specifier
, void *data
, void *userdata
, char **ret
) {
53 n
= unit_name_to_prefix(u
->id
);
61 static int specifier_prefix_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
63 _cleanup_free_
char *p
= NULL
;
68 p
= unit_name_to_prefix(u
->id
);
72 n
= unit_name_unescape(p
);
80 static int specifier_instance_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
89 n
= unit_name_unescape(u
->instance
);
97 static int specifier_filename(char specifier
, void *data
, void *userdata
, char **ret
) {
104 n
= unit_name_path_unescape(u
->instance
);
106 n
= unit_name_to_path(u
->id
);
114 static int specifier_cgroup(char specifier
, void *data
, void *userdata
, char **ret
) {
121 n
= strdup(u
->cgroup_path
);
123 n
= unit_default_cgroup_path(u
);
131 static int specifier_cgroup_root(char specifier
, void *data
, void *userdata
, char **ret
) {
139 slice
= unit_slice_name(u
);
140 if (specifier
== 'R' || !slice
)
141 n
= strdup(u
->manager
->cgroup_root
);
143 _cleanup_free_
char *p
= NULL
;
145 r
= cg_slice_to_path(slice
, &p
);
149 n
= strjoin(u
->manager
->cgroup_root
, "/", p
, NULL
);
158 static int specifier_runtime(char specifier
, void *data
, void *userdata
, char **ret
) {
165 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
)
168 e
= getenv("XDG_RUNTIME_DIR");
181 static int specifier_user_name(char specifier
, void *data
, void *userdata
, char **ret
) {
182 char *printed
= NULL
;
189 c
= unit_get_exec_context(u
);
193 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
) {
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
199 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
200 printed
= strdup(specifier
== 'u' ? "root" : "0");
202 if (specifier
== 'u')
203 printed
= strdup(c
->user
);
207 r
= parse_uid(c
->user
, &uid
);
211 r
= asprintf(&printed
, UID_FMT
, uid
);
216 _cleanup_free_
char *tmp
= NULL
;
217 const char *username
= NULL
;
223 /* get USER env from env or our own uid */
224 username
= tmp
= getusername_malloc();
226 /* fish username from passwd */
227 r
= get_user_creds(&username
, &uid
, NULL
, NULL
, NULL
);
231 if (specifier
== 'u')
232 printed
= strdup(username
);
234 r
= asprintf(&printed
, UID_FMT
, uid
);
237 if (r
< 0 || !printed
)
244 static int specifier_user_home(char specifier
, void *data
, void *userdata
, char **ret
) {
252 c
= unit_get_exec_context(u
);
256 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
) {
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 */
261 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
268 /* return HOME if set, otherwise from passwd */
269 if (!c
|| !c
->user
) {
270 r
= get_home_dir(&n
);
274 const char *username
, *home
;
277 r
= get_user_creds(&username
, NULL
, NULL
, &home
, NULL
);
292 static int specifier_user_shell(char specifier
, void *data
, void *userdata
, char **ret
) {
300 c
= unit_get_exec_context(u
);
304 if (u
->manager
->running_as
== SYSTEMD_SYSTEM
) {
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 */
309 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
310 n
= strdup("/bin/sh");
316 /* return /bin/sh for root, otherwise the value from passwd */
322 const char *username
, *shell
;
325 r
= get_user_creds(&username
, NULL
, NULL
, NULL
, &shell
);
340 int unit_name_printf(Unit
*u
, const char* format
, char **ret
) {
343 * This will use the passed string as format string and
344 * replace the following specifiers:
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)
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
},
364 return specifier_printf(format
, table
, u
, ret
);
367 int unit_full_printf(Unit
*u
, const char *format
, char **ret
) {
369 /* This is similar to unit_name_printf() but also supports
370 * unescaping. Also, adds a couple of additional codes:
372 * %f the instance if set, otherwise the id
373 * %c cgroup path of unit
374 * %r where units in this slice are placed in the cgroup tree
375 * %R the root of this systemd's instance tree
376 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
377 * %U the UID of the configured user or running user
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
381 * %m the machine ID of the running system
382 * %H the host name of the running system
383 * %b the boot ID of the running system
384 * %v `uname -r` of the running system
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
},
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
},
400 { 'U', specifier_user_name
, NULL
},
401 { 'u', specifier_user_name
, NULL
},
402 { 'h', specifier_user_home
, NULL
},
403 { 's', specifier_user_shell
, NULL
},
405 { 'm', specifier_machine_id
, NULL
},
406 { 'H', specifier_host_name
, NULL
},
407 { 'b', specifier_boot_id
, NULL
},
408 { 'v', specifier_kernel_release
, NULL
},
416 return specifier_printf(format
, table
, u
, ret
);
419 int unit_full_printf_strv(Unit
*u
, char **l
, char ***ret
) {
424 /* Applies unit_full_printf to every entry in l */
433 for (i
= l
, j
= r
; *i
; i
++, j
++) {
434 q
= unit_full_printf(u
, *i
, j
);
444 for (j
--; j
>= r
; j
--)