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 "alloc-util.h"
23 #include "cgroup-util.h"
24 #include "formats-util.h"
26 #include "specifier.h"
27 #include "string-util.h"
29 #include "unit-name.h"
30 #include "unit-printf.h"
32 #include "user-util.h"
34 static int specifier_prefix_and_instance(char specifier
, void *data
, void *userdata
, char **ret
) {
39 return unit_name_to_prefix_and_instance(u
->id
, ret
);
42 static int specifier_prefix(char specifier
, void *data
, void *userdata
, char **ret
) {
47 return unit_name_to_prefix(u
->id
, ret
);
50 static int specifier_prefix_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
51 _cleanup_free_
char *p
= NULL
;
57 r
= unit_name_to_prefix(u
->id
, &p
);
61 return unit_name_unescape(p
, ret
);
64 static int specifier_instance_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
69 return unit_name_unescape(strempty(u
->instance
), ret
);
72 static int specifier_filename(char specifier
, void *data
, void *userdata
, char **ret
) {
78 return unit_name_path_unescape(u
->instance
, ret
);
80 return unit_name_to_path(u
->id
, ret
);
83 static int specifier_cgroup(char specifier
, void *data
, void *userdata
, char **ret
) {
90 n
= strdup(u
->cgroup_path
);
92 n
= unit_default_cgroup_path(u
);
100 static int specifier_cgroup_root(char specifier
, void *data
, void *userdata
, char **ret
) {
106 n
= strdup(u
->manager
->cgroup_root
);
114 static int specifier_cgroup_slice(char specifier
, void *data
, void *userdata
, char **ret
) {
120 if (UNIT_ISSET(u
->slice
)) {
123 slice
= UNIT_DEREF(u
->slice
);
125 if (slice
->cgroup_path
)
126 n
= strdup(slice
->cgroup_path
);
128 n
= unit_default_cgroup_path(slice
);
130 n
= strdup(u
->manager
->cgroup_root
);
138 static int specifier_runtime(char specifier
, void *data
, void *userdata
, char **ret
) {
145 if (u
->manager
->running_as
== MANAGER_SYSTEM
)
148 e
= getenv("XDG_RUNTIME_DIR");
161 static int specifier_user_name(char specifier
, void *data
, void *userdata
, char **ret
) {
164 /* If we are UID 0 (root), this will not result in NSS,
165 * otherwise it might. This is good, as we want to be able to
166 * run this in PID 1, where our user ID is 0, but where NSS
167 * lookups are not allowed. */
169 t
= getusername_malloc();
177 static int specifier_user_id(char specifier
, void *data
, void *userdata
, char **ret
) {
179 if (asprintf(ret
, UID_FMT
, getuid()) < 0)
185 static int specifier_user_home(char specifier
, void *data
, void *userdata
, char **ret
) {
187 /* On PID 1 (which runs as root) this will not result in NSS,
188 * which is good. See above */
190 return get_home_dir(ret
);
193 static int specifier_user_shell(char specifier
, void *data
, void *userdata
, char **ret
) {
195 /* On PID 1 (which runs as root) this will not result in NSS,
196 * which is good. See above */
198 return get_shell(ret
);
201 int unit_name_printf(Unit
*u
, const char* format
, char **ret
) {
204 * This will use the passed string as format string and
205 * replace the following specifiers:
207 * %n: the full id of the unit (foo@bar.waldo)
208 * %N: the id of the unit without the suffix (foo@bar)
209 * %p: the prefix (foo)
210 * %i: the instance (bar)
213 const Specifier table
[] = {
214 { 'n', specifier_string
, u
->id
},
215 { 'N', specifier_prefix_and_instance
, NULL
},
216 { 'p', specifier_prefix
, NULL
},
217 { 'i', specifier_string
, u
->instance
},
225 return specifier_printf(format
, table
, u
, ret
);
228 int unit_full_printf(Unit
*u
, const char *format
, char **ret
) {
230 /* This is similar to unit_name_printf() but also supports
231 * unescaping. Also, adds a couple of additional codes:
233 * %f the instance if set, otherwise the id
234 * %c cgroup path of unit
235 * %r where units in this slice are placed in the cgroup tree
236 * %R the root of this systemd's instance tree
237 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
238 * %U the UID of the running user
239 * %u the username of the running user
240 * %h the homedir of the running user
241 * %s the shell of the running user
242 * %m the machine ID of the running system
243 * %H the host name of the running system
244 * %b the boot ID of the running system
245 * %v `uname -r` of the running system
248 const Specifier table
[] = {
249 { 'n', specifier_string
, u
->id
},
250 { 'N', specifier_prefix_and_instance
, NULL
},
251 { 'p', specifier_prefix
, NULL
},
252 { 'P', specifier_prefix_unescaped
, NULL
},
253 { 'i', specifier_string
, u
->instance
},
254 { 'I', specifier_instance_unescaped
, NULL
},
256 { 'f', specifier_filename
, NULL
},
257 { 'c', specifier_cgroup
, NULL
},
258 { 'r', specifier_cgroup_slice
, NULL
},
259 { 'R', specifier_cgroup_root
, NULL
},
260 { 't', specifier_runtime
, NULL
},
262 { 'U', specifier_user_id
, NULL
},
263 { 'u', specifier_user_name
, NULL
},
264 { 'h', specifier_user_home
, NULL
},
265 { 's', specifier_user_shell
, NULL
},
267 { 'm', specifier_machine_id
, NULL
},
268 { 'H', specifier_host_name
, NULL
},
269 { 'b', specifier_boot_id
, NULL
},
270 { 'v', specifier_kernel_release
, NULL
},
278 return specifier_printf(format
, table
, u
, ret
);
281 int unit_full_printf_strv(Unit
*u
, char **l
, char ***ret
) {
286 /* Applies unit_full_printf to every entry in l */
295 for (i
= l
, j
= r
; *i
; i
++, j
++) {
296 q
= unit_full_printf(u
, *i
, j
);
306 for (j
--; j
>= r
; j
--)