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
) {
162 char *printed
= NULL
;
169 c
= unit_get_exec_context(u
);
173 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
175 /* We cannot use NSS from PID 1, hence try to make the
176 * best of it in that case, and fail if we can't help
179 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
180 printed
= strdup(specifier
== 'u' ? "root" : "0");
182 if (specifier
== 'u')
183 printed
= strdup(c
->user
);
187 r
= parse_uid(c
->user
, &uid
);
191 r
= asprintf(&printed
, UID_FMT
, uid
);
196 _cleanup_free_
char *tmp
= NULL
;
197 const char *username
= NULL
;
203 /* get USER env from env or our own uid */
204 username
= tmp
= getusername_malloc();
206 /* fish username from passwd */
207 r
= get_user_creds(&username
, &uid
, NULL
, NULL
, NULL
);
211 if (specifier
== 'u')
212 printed
= strdup(username
);
214 r
= asprintf(&printed
, UID_FMT
, uid
);
217 if (r
< 0 || !printed
)
224 static int specifier_user_home(char specifier
, void *data
, void *userdata
, char **ret
) {
232 c
= unit_get_exec_context(u
);
236 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
238 /* We cannot use NSS from PID 1, hence try to make the
239 * best of it if we can, but fail if we can't */
241 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
248 /* return HOME if set, otherwise from passwd */
249 if (!c
|| !c
->user
) {
250 r
= get_home_dir(&n
);
254 const char *username
, *home
;
257 r
= get_user_creds(&username
, NULL
, NULL
, &home
, NULL
);
272 static int specifier_user_shell(char specifier
, void *data
, void *userdata
, char **ret
) {
280 c
= unit_get_exec_context(u
);
284 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
286 /* We cannot use NSS from PID 1, hence try to make the
287 * best of it if we can, but fail if we can't */
289 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
290 n
= strdup("/bin/sh");
296 /* return /bin/sh for root, otherwise the value from passwd */
302 const char *username
, *shell
;
305 r
= get_user_creds(&username
, NULL
, NULL
, NULL
, &shell
);
320 int unit_name_printf(Unit
*u
, const char* format
, char **ret
) {
323 * This will use the passed string as format string and
324 * replace the following specifiers:
326 * %n: the full id of the unit (foo@bar.waldo)
327 * %N: the id of the unit without the suffix (foo@bar)
328 * %p: the prefix (foo)
329 * %i: the instance (bar)
332 const Specifier table
[] = {
333 { 'n', specifier_string
, u
->id
},
334 { 'N', specifier_prefix_and_instance
, NULL
},
335 { 'p', specifier_prefix
, NULL
},
336 { 'i', specifier_string
, u
->instance
},
344 return specifier_printf(format
, table
, u
, ret
);
347 int unit_full_printf(Unit
*u
, const char *format
, char **ret
) {
349 /* This is similar to unit_name_printf() but also supports
350 * unescaping. Also, adds a couple of additional codes:
352 * %f the instance if set, otherwise the id
353 * %c cgroup path of unit
354 * %r where units in this slice are placed in the cgroup tree
355 * %R the root of this systemd's instance tree
356 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
357 * %U the UID of the configured user or running user
358 * %u the username of the configured user or running user
359 * %h the homedir of the configured user or running user
360 * %s the shell of the configured user or running user
361 * %m the machine ID of the running system
362 * %H the host name of the running system
363 * %b the boot ID of the running system
364 * %v `uname -r` of the running system
367 const Specifier table
[] = {
368 { 'n', specifier_string
, u
->id
},
369 { 'N', specifier_prefix_and_instance
, NULL
},
370 { 'p', specifier_prefix
, NULL
},
371 { 'P', specifier_prefix_unescaped
, NULL
},
372 { 'i', specifier_string
, u
->instance
},
373 { 'I', specifier_instance_unescaped
, NULL
},
375 { 'f', specifier_filename
, NULL
},
376 { 'c', specifier_cgroup
, NULL
},
377 { 'r', specifier_cgroup_slice
, NULL
},
378 { 'R', specifier_cgroup_root
, NULL
},
379 { 't', specifier_runtime
, NULL
},
380 { 'U', specifier_user_name
, NULL
},
381 { 'u', specifier_user_name
, NULL
},
382 { 'h', specifier_user_home
, NULL
},
383 { 's', specifier_user_shell
, NULL
},
385 { 'm', specifier_machine_id
, NULL
},
386 { 'H', specifier_host_name
, NULL
},
387 { 'b', specifier_boot_id
, NULL
},
388 { 'v', specifier_kernel_release
, NULL
},
396 return specifier_printf(format
, table
, u
, ret
);
399 int unit_full_printf_strv(Unit
*u
, char **l
, char ***ret
) {
404 /* Applies unit_full_printf to every entry in l */
413 for (i
= l
, j
= r
; *i
; i
++, j
++) {
414 q
= unit_full_printf(u
, *i
, j
);
424 for (j
--; j
>= r
; j
--)