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/>.
22 #include "systemd/sd-id128.h"
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 char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
37 return unit_name_to_prefix_and_instance(u->id);
40 static char *specifier_prefix(char specifier, void *data, void *userdata) {
44 return unit_name_to_prefix(u->id);
47 static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) {
53 p = unit_name_to_prefix(u->id);
57 r = unit_name_unescape(p);
63 static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) {
68 return unit_name_unescape(u->instance);
73 static char *specifier_filename(char specifier, void *data, void *userdata) {
78 return unit_name_path_unescape(u->instance);
80 return unit_name_to_path(u->id);
83 static char *specifier_cgroup(char specifier, void *data, void *userdata) {
87 return unit_default_cgroup_path(u);
90 static char *specifier_cgroup_root(char specifier, void *data, void *userdata) {
91 _cleanup_free_ char *p = NULL;
98 slice = unit_slice_name(u);
99 if (specifier == 'R' || !slice)
100 return strdup(u->manager->cgroup_root);
102 r = cg_slice_to_path(slice, &p);
106 return strjoin(u->manager->cgroup_root, "/", p, NULL);
109 static char *specifier_runtime(char specifier, void *data, void *userdata) {
113 if (u->manager->running_as == SYSTEMD_USER) {
116 e = getenv("XDG_RUNTIME_DIR");
121 return strdup("/run");
124 static char *specifier_user_name(char specifier, void *data, void *userdata) {
128 const char *username;
129 _cleanup_free_ char *tmp = NULL;
131 char *printed = NULL;
135 c = unit_get_exec_context(u);
140 /* get USER env from env or our own uid */
141 username = tmp = getusername_malloc();
143 /* fish username from passwd */
144 r = get_user_creds(&username, &uid, NULL, NULL, NULL);
150 if (asprintf(&printed, "%d", uid) < 0)
154 printed = strdup(username);
161 static char *specifier_user_home(char specifier, void *data, void *userdata) {
165 const char *username, *home;
169 c = unit_get_exec_context(u);
171 /* return HOME if set, otherwise from passwd */
172 if (!c || !c->user) {
175 r = get_home_dir(&h);
183 r = get_user_creds(&username, NULL, NULL, &home, NULL);
190 static char *specifier_user_shell(char specifier, void *data, void *userdata) {
194 const char *username, *shell;
199 c = unit_get_exec_context(u);
206 /* return /bin/sh for root, otherwise the value from passwd */
207 r = get_user_creds(&username, NULL, NULL, NULL, &shell);
209 log_warning_unit(u->id,
210 "Failed to determine shell: %s",
215 if (!path_is_absolute(shell)) {
216 log_warning_unit(u->id,
217 "Shell %s is not absolute, ignoring.",
228 char *unit_name_printf(Unit *u, const char* format) {
231 * This will use the passed string as format string and
232 * replace the following specifiers:
234 * %n: the full id of the unit (foo@bar.waldo)
235 * %N: the id of the unit without the suffix (foo@bar)
236 * %p: the prefix (foo)
237 * %i: the instance (bar)
240 const Specifier table[] = {
241 { 'n', specifier_string, u->id },
242 { 'N', specifier_prefix_and_instance, NULL },
243 { 'p', specifier_prefix, NULL },
244 { 'i', specifier_string, u->instance },
251 return specifier_printf(format, table, u);
254 char *unit_full_printf(Unit *u, const char *format) {
256 /* This is similar to unit_name_printf() but also supports
257 * unescaping. Also, adds a couple of additional codes:
259 * %f the the instance if set, otherwise the id
260 * %c cgroup path of unit
261 * %r where units in this slice are place in the cgroup tree
262 * %R the root of this systemd's instance tree
263 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
264 * %U the UID of the configured user or running user
265 * %u the username of the configured user or running user
266 * %h the homedir of the configured user or running user
267 * %s the shell of the configured user or running user
268 * %m the machine ID of the running system
269 * %H the host name of the running system
270 * %b the boot ID of the running system
271 * %v `uname -r` of the running system
274 const Specifier table[] = {
275 { 'n', specifier_string, u->id },
276 { 'N', specifier_prefix_and_instance, NULL },
277 { 'p', specifier_prefix, NULL },
278 { 'P', specifier_prefix_unescaped, NULL },
279 { 'i', specifier_string, u->instance },
280 { 'I', specifier_instance_unescaped, NULL },
282 { 'f', specifier_filename, NULL },
283 { 'c', specifier_cgroup, NULL },
284 { 'r', specifier_cgroup_root, NULL },
285 { 'R', specifier_cgroup_root, NULL },
286 { 't', specifier_runtime, NULL },
287 { 'U', specifier_user_name, NULL },
288 { 'u', specifier_user_name, NULL },
289 { 'h', specifier_user_home, NULL },
290 { 's', specifier_user_shell, NULL },
292 { 'm', specifier_machine_id, NULL },
293 { 'H', specifier_host_name, NULL },
294 { 'b', specifier_boot_id, NULL },
295 { 'v', specifier_kernel_release, NULL },
301 return specifier_printf(format, table, u);
304 char **unit_full_printf_strv(Unit *u, char **l) {
308 /* Applies unit_full_printf to every entry in l */
317 for (i = l, j = r; *i; i++, j++) {
318 *j = unit_full_printf(u, *i);
327 for (j--; j >= r; j--)