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 "cgroup-util.h"
23 #include "formats-util.h"
25 #include "specifier.h"
26 #include "string-util.h"
28 #include "unit-name.h"
29 #include "unit-printf.h"
31 #include "user-util.h"
33 static int specifier_prefix_and_instance(char specifier
, void *data
, void *userdata
, char **ret
) {
38 return unit_name_to_prefix_and_instance(u
->id
, ret
);
41 static int specifier_prefix(char specifier
, void *data
, void *userdata
, char **ret
) {
46 return unit_name_to_prefix(u
->id
, ret
);
49 static int specifier_prefix_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
50 _cleanup_free_
char *p
= NULL
;
56 r
= unit_name_to_prefix(u
->id
, &p
);
60 return unit_name_unescape(p
, ret
);
63 static int specifier_instance_unescaped(char specifier
, void *data
, void *userdata
, char **ret
) {
68 return unit_name_unescape(strempty(u
->instance
), ret
);
71 static int specifier_filename(char specifier
, void *data
, void *userdata
, char **ret
) {
77 return unit_name_path_unescape(u
->instance
, ret
);
79 return unit_name_to_path(u
->id
, ret
);
82 static int specifier_cgroup(char specifier
, void *data
, void *userdata
, char **ret
) {
89 n
= strdup(u
->cgroup_path
);
91 n
= unit_default_cgroup_path(u
);
99 static int specifier_cgroup_root(char specifier
, void *data
, void *userdata
, char **ret
) {
105 n
= strdup(u
->manager
->cgroup_root
);
113 static int specifier_cgroup_slice(char specifier
, void *data
, void *userdata
, char **ret
) {
119 if (UNIT_ISSET(u
->slice
)) {
122 slice
= UNIT_DEREF(u
->slice
);
124 if (slice
->cgroup_path
)
125 n
= strdup(slice
->cgroup_path
);
127 n
= unit_default_cgroup_path(slice
);
129 n
= strdup(u
->manager
->cgroup_root
);
137 static int specifier_runtime(char specifier
, void *data
, void *userdata
, char **ret
) {
144 if (u
->manager
->running_as
== MANAGER_SYSTEM
)
147 e
= getenv("XDG_RUNTIME_DIR");
160 static int specifier_user_name(char specifier
, void *data
, void *userdata
, char **ret
) {
161 char *printed
= NULL
;
168 c
= unit_get_exec_context(u
);
172 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
174 /* We cannot use NSS from PID 1, hence try to make the
175 * best of it in that case, and fail if we can't help
178 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
179 printed
= strdup(specifier
== 'u' ? "root" : "0");
181 if (specifier
== 'u')
182 printed
= strdup(c
->user
);
186 r
= parse_uid(c
->user
, &uid
);
190 r
= asprintf(&printed
, UID_FMT
, uid
);
195 _cleanup_free_
char *tmp
= NULL
;
196 const char *username
= NULL
;
202 /* get USER env from env or our own uid */
203 username
= tmp
= getusername_malloc();
205 /* fish username from passwd */
206 r
= get_user_creds(&username
, &uid
, NULL
, NULL
, NULL
);
210 if (specifier
== 'u')
211 printed
= strdup(username
);
213 r
= asprintf(&printed
, UID_FMT
, uid
);
216 if (r
< 0 || !printed
)
223 static int specifier_user_home(char specifier
, void *data
, void *userdata
, char **ret
) {
231 c
= unit_get_exec_context(u
);
235 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
237 /* We cannot use NSS from PID 1, hence try to make the
238 * best of it if we can, but fail if we can't */
240 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
247 /* return HOME if set, otherwise from passwd */
248 if (!c
|| !c
->user
) {
249 r
= get_home_dir(&n
);
253 const char *username
, *home
;
256 r
= get_user_creds(&username
, NULL
, NULL
, &home
, NULL
);
271 static int specifier_user_shell(char specifier
, void *data
, void *userdata
, char **ret
) {
279 c
= unit_get_exec_context(u
);
283 if (u
->manager
->running_as
== MANAGER_SYSTEM
) {
285 /* We cannot use NSS from PID 1, hence try to make the
286 * best of it if we can, but fail if we can't */
288 if (!c
->user
|| streq(c
->user
, "root") || streq(c
->user
, "0"))
289 n
= strdup("/bin/sh");
295 /* return /bin/sh for root, otherwise the value from passwd */
301 const char *username
, *shell
;
304 r
= get_user_creds(&username
, NULL
, NULL
, NULL
, &shell
);
319 int unit_name_printf(Unit
*u
, const char* format
, char **ret
) {
322 * This will use the passed string as format string and
323 * replace the following specifiers:
325 * %n: the full id of the unit (foo@bar.waldo)
326 * %N: the id of the unit without the suffix (foo@bar)
327 * %p: the prefix (foo)
328 * %i: the instance (bar)
331 const Specifier table
[] = {
332 { 'n', specifier_string
, u
->id
},
333 { 'N', specifier_prefix_and_instance
, NULL
},
334 { 'p', specifier_prefix
, NULL
},
335 { 'i', specifier_string
, u
->instance
},
343 return specifier_printf(format
, table
, u
, ret
);
346 int unit_full_printf(Unit
*u
, const char *format
, char **ret
) {
348 /* This is similar to unit_name_printf() but also supports
349 * unescaping. Also, adds a couple of additional codes:
351 * %f the instance if set, otherwise the id
352 * %c cgroup path of unit
353 * %r where units in this slice are placed in the cgroup tree
354 * %R the root of this systemd's instance tree
355 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
356 * %U the UID of the configured user or running user
357 * %u the username of the configured user or running user
358 * %h the homedir of the configured user or running user
359 * %s the shell of the configured user or running user
360 * %m the machine ID of the running system
361 * %H the host name of the running system
362 * %b the boot ID of the running system
363 * %v `uname -r` of the running system
366 const Specifier table
[] = {
367 { 'n', specifier_string
, u
->id
},
368 { 'N', specifier_prefix_and_instance
, NULL
},
369 { 'p', specifier_prefix
, NULL
},
370 { 'P', specifier_prefix_unescaped
, NULL
},
371 { 'i', specifier_string
, u
->instance
},
372 { 'I', specifier_instance_unescaped
, NULL
},
374 { 'f', specifier_filename
, NULL
},
375 { 'c', specifier_cgroup
, NULL
},
376 { 'r', specifier_cgroup_slice
, NULL
},
377 { 'R', specifier_cgroup_root
, NULL
},
378 { 't', specifier_runtime
, NULL
},
379 { 'U', specifier_user_name
, NULL
},
380 { 'u', specifier_user_name
, NULL
},
381 { 'h', specifier_user_home
, NULL
},
382 { 's', specifier_user_shell
, NULL
},
384 { 'm', specifier_machine_id
, NULL
},
385 { 'H', specifier_host_name
, NULL
},
386 { 'b', specifier_boot_id
, NULL
},
387 { 'v', specifier_kernel_release
, NULL
},
395 return specifier_printf(format
, table
, u
, ret
);
398 int unit_full_printf_strv(Unit
*u
, char **l
, char ***ret
) {
403 /* Applies unit_full_printf to every entry in l */
412 for (i
= l
, j
= r
; *i
; i
++, j
++) {
413 q
= unit_full_printf(u
, *i
, j
);
423 for (j
--; j
>= r
; j
--)