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
) {
36 return unit_name_to_prefix_and_instance(u
->id
, ret
);
39 static int specifier_prefix(char specifier
, void *data
, void *userdata
, char **ret
) {
44 return unit_name_to_prefix(u
->id
, ret
);
47 static int specifier_prefix_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
48 _cleanup_free_
char *p
= NULL
;
54 r
= unit_name_to_prefix(u
->id
, &p
);
58 return unit_name_unescape(p
, ret
);
61 static int specifier_instance_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
69 return unit_name_unescape(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
);
136 static int specifier_runtime(char specifier
, void *data
, void *userdata
, char **ret
) {
143 if (u
->manager
->running_as
== MANAGER_SYSTEM
)
146 e
= getenv("XDG_RUNTIME_DIR");
159 static int specifier_user_name(char specifier
, void *data
, void *userdata
, char **ret
) {
160 char *printed
= NULL
;
167 c
= unit_get_exec_context(u
);
171 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
173 /* We cannot use NSS from PID 1, hence try to make the
174 * best of it in that case, and fail if we can't help
177 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
178 printed
= strdup(specifier
== 'u' ? "root" : "0");
180 if (specifier
== 'u')
181 printed
= strdup(c
->user
);
185 r
= parse_uid(c
->user
, &uid
);
189 r
= asprintf(&printed
, UID_FMT
, uid
);
194 _cleanup_free_
char *tmp
= NULL
;
195 const char *username
= NULL
;
201 /* get USER env from env or our own uid */
202 username
= tmp
= getusername_malloc();
204 /* fish username from passwd */
205 r
= get_user_creds(&username
, &uid
, NULL
, NULL
, NULL
);
209 if (specifier
== 'u')
210 printed
= strdup(username
);
212 r
= asprintf(&printed
, UID_FMT
, uid
);
215 if (r
< 0 || !printed
)
222 static int specifier_user_home(char specifier
, void *data
, void *userdata
, char **ret
) {
230 c
= unit_get_exec_context(u
);
234 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
236 /* We cannot use NSS from PID 1, hence try to make the
237 * best of it if we can, but fail if we can't */
239 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
246 /* return HOME if set, otherwise from passwd */
247 if (!c
|| !c
->user
) {
248 r
= get_home_dir(&n
);
252 const char *username
, *home
;
255 r
= get_user_creds(&username
, NULL
, NULL
, &home
, NULL
);
270 static int specifier_user_shell(char specifier
, void *data
, void *userdata
, char **ret
) {
278 c
= unit_get_exec_context(u
);
282 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
284 /* We cannot use NSS from PID 1, hence try to make the
285 * best of it if we can, but fail if we can't */
287 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
288 n
= strdup("/bin/sh");
294 /* return /bin/sh for root, otherwise the value from passwd */
300 const char *username
, *shell
;
303 r
= get_user_creds(&username
, NULL
, NULL
, NULL
, &shell
);
318 int unit_name_printf(Unit
*u
, const char* format
, char **ret
) {
321 * This will use the passed string as format string and
322 * replace the following specifiers:
324 * %n: the full id of the unit (foo@bar.waldo)
325 * %N: the id of the unit without the suffix (foo@bar)
326 * %p: the prefix (foo)
327 * %i: the instance (bar)
330 const Specifier table
[] = {
331 { 'n', specifier_string
, u
->id
},
332 { 'N', specifier_prefix_and_instance
, NULL
},
333 { 'p', specifier_prefix
, NULL
},
334 { 'i', specifier_string
, u
->instance
},
342 return specifier_printf(format
, table
, u
, ret
);
345 int unit_full_printf(Unit
*u
, const char *format
, char **ret
) {
347 /* This is similar to unit_name_printf() but also supports
348 * unescaping. Also, adds a couple of additional codes:
350 * %f the instance if set, otherwise the id
351 * %c cgroup path of unit
352 * %r where units in this slice are placed in the cgroup tree
353 * %R the root of this systemd's instance tree
354 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
355 * %U the UID of the configured user or running user
356 * %u the username of the configured user or running user
357 * %h the homedir of the configured user or running user
358 * %s the shell of the configured user or running user
359 * %m the machine ID of the running system
360 * %H the host name of the running system
361 * %b the boot ID of the running system
362 * %v `uname -r` of the running system
365 const Specifier table
[] = {
366 { 'n', specifier_string
, u
->id
},
367 { 'N', specifier_prefix_and_instance
, NULL
},
368 { 'p', specifier_prefix
, NULL
},
369 { 'P', specifier_prefix_unescaped
, NULL
},
370 { 'i', specifier_string
, u
->instance
},
371 { 'I', specifier_instance_unescaped
, NULL
},
373 { 'f', specifier_filename
, NULL
},
374 { 'c', specifier_cgroup
, NULL
},
375 { 'r', specifier_cgroup_slice
, NULL
},
376 { 'R', specifier_cgroup_root
, NULL
},
377 { 't', specifier_runtime
, NULL
},
378 { 'U', specifier_user_name
, NULL
},
379 { 'u', specifier_user_name
, NULL
},
380 { 'h', specifier_user_home
, NULL
},
381 { 's', specifier_user_shell
, NULL
},
383 { 'm', specifier_machine_id
, NULL
},
384 { 'H', specifier_host_name
, NULL
},
385 { 'b', specifier_boot_id
, NULL
},
386 { 'v', specifier_kernel_release
, NULL
},
394 return specifier_printf(format
, table
, u
, ret
);
397 int unit_full_printf_strv(Unit
*u
, char **l
, char ***ret
) {
402 /* Applies unit_full_printf to every entry in l */
411 for (i
= l
, j
= r
; *i
; i
++, j
++) {
412 q
= unit_full_printf(u
, *i
, j
);
422 for (j
--; j
>= r
; j
--)