]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/specifier.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include <sys/utsname.h>
11 #include "alloc-util.h"
12 #include "architecture.h"
13 #include "format-util.h"
15 #include "hostname-util.h"
18 #include "specifier.h"
19 #include "string-util.h"
21 #include "user-util.h"
24 * Generic infrastructure for replacing %x style specifiers in
25 * strings. Will call a callback for each replacement.
28 /* Any ASCII character or digit: our pool of potential specifiers,
29 * and "%" used for escaping. */
30 #define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%"
32 int specifier_printf(const char *text
, size_t max_length
, const Specifier table
[], const void *userdata
, char **ret
) {
33 _cleanup_free_
char *result
= NULL
;
44 if (!GREEDY_REALLOC(result
, l
+ 1))
48 for (f
= text
; *f
!= '\0'; f
++, l
--) {
55 for (i
= table
; i
->specifier
; i
++)
56 if (i
->specifier
== *f
)
60 _cleanup_free_
char *w
= NULL
;
63 r
= i
->lookup(i
->specifier
, i
->data
, userdata
, &w
);
70 if (!GREEDY_REALLOC(result
, j
+ k
+ l
+ 1))
72 memcpy(result
+ j
, w
, k
);
74 } else if (strchr(POSSIBLE_SPECIFIERS
, *f
))
75 /* Oops, an unknown specifier. */
89 if ((size_t) (t
- result
) > max_length
)
93 /* If string ended with a stray %, also end with % */
96 if ((size_t) (t
- result
) > max_length
)
101 *ret
= TAKE_PTR(result
);
105 /* Generic handler for simple string replacements */
107 int specifier_string(char specifier
, const void *data
, const void *userdata
, char **ret
) {
110 n
= strdup(strempty(data
));
118 int specifier_machine_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
123 r
= sd_id128_get_machine(&id
);
127 n
= new(char, SD_ID128_STRING_MAX
);
131 *ret
= sd_id128_to_string(id
, n
);
135 int specifier_boot_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
140 r
= sd_id128_get_boot(&id
);
144 n
= new(char, SD_ID128_STRING_MAX
);
148 *ret
= sd_id128_to_string(id
, n
);
152 int specifier_host_name(char specifier
, const void *data
, const void *userdata
, char **ret
) {
155 n
= gethostname_malloc();
163 int specifier_short_host_name(char specifier
, const void *data
, const void *userdata
, char **ret
) {
166 n
= gethostname_short_malloc();
174 int specifier_kernel_release(char specifier
, const void *data
, const void *userdata
, char **ret
) {
183 n
= strdup(uts
.release
);
191 int specifier_architecture(char specifier
, const void *data
, const void *userdata
, char **ret
) {
194 t
= strdup(architecture_to_string(uname_architecture()));
202 static int specifier_os_release_common(const char *field
, char **ret
) {
206 r
= parse_os_release(NULL
, field
, &t
);
210 /* fields in /etc/os-release might quite possibly be missing, even if everything is entirely
211 * valid otherwise. Let's hence return "" in that case. */
221 int specifier_os_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
222 return specifier_os_release_common("ID", ret
);
225 int specifier_os_version_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
226 return specifier_os_release_common("VERSION_ID", ret
);
229 int specifier_os_build_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
230 return specifier_os_release_common("BUILD_ID", ret
);
233 int specifier_os_variant_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
234 return specifier_os_release_common("VARIANT_ID", ret
);
237 int specifier_os_image_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
238 return specifier_os_release_common("IMAGE_ID", ret
);
241 int specifier_os_image_version(char specifier
, const void *data
, const void *userdata
, char **ret
) {
242 return specifier_os_release_common("IMAGE_VERSION", ret
);
245 int specifier_group_name(char specifier
, const void *data
, const void *userdata
, char **ret
) {
248 t
= gid_to_name(getgid());
256 int specifier_group_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
257 if (asprintf(ret
, UID_FMT
, getgid()) < 0)
263 int specifier_user_name(char specifier
, const void *data
, const void *userdata
, char **ret
) {
266 /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
267 * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
269 * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
270 * specifer_user_id() below.
273 t
= uid_to_name(getuid());
281 int specifier_user_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
283 if (asprintf(ret
, UID_FMT
, getuid()) < 0)
289 int specifier_user_home(char specifier
, const void *data
, const void *userdata
, char **ret
) {
291 /* On PID 1 (which runs as root) this will not result in NSS,
292 * which is good. See above */
294 return get_home_dir(ret
);
297 int specifier_user_shell(char specifier
, const void *data
, const void *userdata
, char **ret
) {
299 /* On PID 1 (which runs as root) this will not result in NSS,
300 * which is good. See above */
302 return get_shell(ret
);
305 int specifier_tmp_dir(char specifier
, const void *data
, const void *userdata
, char **ret
) {
322 int specifier_var_tmp_dir(char specifier
, const void *data
, const void *userdata
, char **ret
) {
339 int specifier_escape_strv(char **l
, char ***ret
) {
344 if (strv_isempty(l
)) {
349 z
= new(char*, strv_length(l
)+1);
353 for (p
= l
, q
= z
; *p
; p
++, q
++) {
355 *q
= specifier_escape(*p
);