]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/specifier.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include <sys/utsname.h>
12 #include "alloc-util.h"
14 #include "hostname-util.h"
16 #include "specifier.h"
17 #include "string-util.h"
19 #include "user-util.h"
22 * Generic infrastructure for replacing %x style specifiers in
23 * strings. Will call a callback for each replacement.
26 /* Any ASCII character or digit: our pool of potential specifiers,
27 * and "%" used for escaping. */
28 #define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%"
30 int specifier_printf(const char *text
, const Specifier table
[], const void *userdata
, char **_ret
) {
31 size_t l
, allocated
= 0;
32 _cleanup_free_
char *ret
= NULL
;
42 if (!GREEDY_REALLOC(ret
, allocated
, l
+ 1))
46 for (f
= text
; *f
; f
++, l
--)
53 for (i
= table
; i
->specifier
; i
++)
54 if (i
->specifier
== *f
)
58 _cleanup_free_
char *w
= NULL
;
61 r
= i
->lookup(i
->specifier
, i
->data
, userdata
, &w
);
68 if (!GREEDY_REALLOC(ret
, allocated
, j
+ k
+ l
+ 1))
70 memcpy(ret
+ j
, w
, k
);
72 } else if (strchr(POSSIBLE_SPECIFIERS
, *f
))
73 /* Oops, an unknown specifier. */
87 /* If string ended with a stray %, also end with % */
92 /* Try to deallocate unused bytes, but don't sweat it too much */
93 if ((size_t)(t
- ret
) < allocated
) {
94 t
= realloc(ret
, t
- ret
);
99 *_ret
= TAKE_PTR(ret
);
103 /* Generic handler for simple string replacements */
105 int specifier_string(char specifier
, const void *data
, const void *userdata
, char **ret
) {
108 n
= strdup(strempty(data
));
116 int specifier_machine_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
121 r
= sd_id128_get_machine(&id
);
129 *ret
= sd_id128_to_string(id
, n
);
133 int specifier_boot_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
138 r
= sd_id128_get_boot(&id
);
146 *ret
= sd_id128_to_string(id
, n
);
150 int specifier_host_name(char specifier
, const void *data
, const void *userdata
, char **ret
) {
153 n
= gethostname_malloc();
161 int specifier_kernel_release(char specifier
, const void *data
, const void *userdata
, char **ret
) {
170 n
= strdup(uts
.release
);
178 int specifier_group_name(char specifier
, const void *data
, const void *userdata
, char **ret
) {
181 t
= gid_to_name(getgid());
189 int specifier_group_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
190 if (asprintf(ret
, UID_FMT
, getgid()) < 0)
196 int specifier_user_name(char specifier
, const void *data
, const void *userdata
, char **ret
) {
199 /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
200 * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
202 * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
203 * specifer_user_id() below.
206 t
= uid_to_name(getuid());
214 int specifier_user_id(char specifier
, const void *data
, const void *userdata
, char **ret
) {
216 if (asprintf(ret
, UID_FMT
, getuid()) < 0)
222 int specifier_user_home(char specifier
, const void *data
, const void *userdata
, char **ret
) {
224 /* On PID 1 (which runs as root) this will not result in NSS,
225 * which is good. See above */
227 return get_home_dir(ret
);
230 int specifier_user_shell(char specifier
, const void *data
, const void *userdata
, char **ret
) {
232 /* On PID 1 (which runs as root) this will not result in NSS,
233 * which is good. See above */
235 return get_shell(ret
);
238 int specifier_tmp_dir(char specifier
, const void *data
, const void *userdata
, char **ret
) {
255 int specifier_var_tmp_dir(char specifier
, const void *data
, const void *userdata
, char **ret
) {
272 int specifier_escape_strv(char **l
, char ***ret
) {
277 if (strv_isempty(l
)) {
282 z
= new(char*, strv_length(l
)+1);
286 for (p
= l
, q
= z
; *p
; p
++, q
++) {
288 *q
= specifier_escape(*p
);