]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/specifier.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / shared / specifier.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
9e2f7c11 2
a8fbdf54
TA
3#include <errno.h>
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdlib.h>
9e2f7c11 7#include <string.h>
6aaa8c2f 8#include <sys/utsname.h>
9e2f7c11 9
a8fbdf54
TA
10#include "sd-id128.h"
11
b5efdb8a 12#include "alloc-util.h"
b294e594 13#include "fs-util.h"
07630cea 14#include "hostname-util.h"
9e2f7c11 15#include "macro.h"
b5efdb8a 16#include "specifier.h"
07630cea 17#include "string-util.h"
e82f30d1 18#include "strv.h"
36444d22 19#include "user-util.h"
9e2f7c11
LP
20
21/*
22 * Generic infrastructure for replacing %x style specifiers in
23 * strings. Will call a callback for each replacement.
9e2f7c11
LP
24 */
25
751223fe
ZJS
26/* Any ASCII character or digit: our pool of potential specifiers,
27 * and "%" used for escaping. */
28#define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%"
29
303ee601 30int specifier_printf(const char *text, const Specifier table[], const void *userdata, char **_ret) {
e2093454 31 size_t l, allocated = 0;
8208c8f2
ZJS
32 _cleanup_free_ char *ret = NULL;
33 char *t;
9e2f7c11
LP
34 const char *f;
35 bool percent = false;
19f6d710 36 int r;
9e2f7c11
LP
37
38 assert(text);
39 assert(table);
40
41 l = strlen(text);
e2093454 42 if (!GREEDY_REALLOC(ret, allocated, l + 1))
19f6d710 43 return -ENOMEM;
19f6d710 44 t = ret;
9e2f7c11 45
e2093454 46 for (f = text; *f; f++, l--)
9e2f7c11
LP
47 if (percent) {
48 if (*f == '%')
49 *(t++) = '%';
50 else {
51 const Specifier *i;
52
53 for (i = table; i->specifier; i++)
54 if (i->specifier == *f)
55 break;
56
57 if (i->lookup) {
19f6d710 58 _cleanup_free_ char *w = NULL;
9e2f7c11
LP
59 size_t k, j;
60
19f6d710 61 r = i->lookup(i->specifier, i->data, userdata, &w);
8208c8f2 62 if (r < 0)
19f6d710 63 return r;
9e2f7c11 64
19f6d710 65 j = t - ret;
9e2f7c11
LP
66 k = strlen(w);
67
e2093454 68 if (!GREEDY_REALLOC(ret, allocated, j + k + l + 1))
19f6d710 69 return -ENOMEM;
e2093454 70 memcpy(ret + j, w, k);
8208c8f2
ZJS
71 t = ret + j + k;
72 } else if (strchr(POSSIBLE_SPECIFIERS, *f))
751223fe
ZJS
73 /* Oops, an unknown specifier. */
74 return -EBADSLT;
8208c8f2 75 else {
9e2f7c11
LP
76 *(t++) = '%';
77 *(t++) = *f;
78 }
79 }
80
81 percent = false;
82 } else if (*f == '%')
83 percent = true;
84 else
85 *(t++) = *f;
9e2f7c11 86
bec8a68c 87 /* If string ended with a stray %, also end with % */
038492ae
FS
88 if (percent)
89 *(t++) = '%';
bec8a68c
ZJS
90 *(t++) = 0;
91
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);
95 if (t)
96 ret = t;
97 }
038492ae 98
ae2a15bc 99 *_ret = TAKE_PTR(ret);
19f6d710 100 return 0;
9e2f7c11
LP
101}
102
103/* Generic handler for simple string replacements */
104
303ee601 105int specifier_string(char specifier, const void *data, const void *userdata, char **ret) {
19f6d710
LP
106 char *n;
107
108 n = strdup(strempty(data));
109 if (!n)
110 return -ENOMEM;
111
112 *ret = n;
113 return 0;
9e2f7c11 114}
d848b9cb 115
303ee601 116int specifier_machine_id(char specifier, const void *data, const void *userdata, char **ret) {
d848b9cb 117 sd_id128_t id;
19f6d710 118 char *n;
d848b9cb
ZJS
119 int r;
120
121 r = sd_id128_get_machine(&id);
122 if (r < 0)
19f6d710 123 return r;
d848b9cb 124
19f6d710
LP
125 n = new(char, 33);
126 if (!n)
127 return -ENOMEM;
d848b9cb 128
19f6d710
LP
129 *ret = sd_id128_to_string(id, n);
130 return 0;
d848b9cb
ZJS
131}
132
303ee601 133int specifier_boot_id(char specifier, const void *data, const void *userdata, char **ret) {
d848b9cb 134 sd_id128_t id;
19f6d710 135 char *n;
d848b9cb
ZJS
136 int r;
137
138 r = sd_id128_get_boot(&id);
139 if (r < 0)
19f6d710 140 return r;
d848b9cb 141
19f6d710
LP
142 n = new(char, 33);
143 if (!n)
144 return -ENOMEM;
d848b9cb 145
19f6d710
LP
146 *ret = sd_id128_to_string(id, n);
147 return 0;
d848b9cb
ZJS
148}
149
303ee601 150int specifier_host_name(char specifier, const void *data, const void *userdata, char **ret) {
19f6d710
LP
151 char *n;
152
153 n = gethostname_malloc();
154 if (!n)
155 return -ENOMEM;
156
157 *ret = n;
158 return 0;
d848b9cb 159}
6aaa8c2f 160
303ee601 161int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret) {
6aaa8c2f 162 struct utsname uts;
19f6d710 163 char *n;
6aaa8c2f
ZJS
164 int r;
165
166 r = uname(&uts);
167 if (r < 0)
19f6d710
LP
168 return -errno;
169
170 n = strdup(uts.release);
171 if (!n)
172 return -ENOMEM;
6aaa8c2f 173
19f6d710
LP
174 *ret = n;
175 return 0;
6aaa8c2f 176}
e82f30d1 177
303ee601 178int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret) {
b75f0c69
DC
179 char *t;
180
181 t = gid_to_name(getgid());
182 if (!t)
183 return -ENOMEM;
184
185 *ret = t;
186 return 0;
187}
188
303ee601 189int specifier_group_id(char specifier, const void *data, const void *userdata, char **ret) {
b75f0c69
DC
190 if (asprintf(ret, UID_FMT, getgid()) < 0)
191 return -ENOMEM;
192
193 return 0;
194}
195
303ee601 196int specifier_user_name(char specifier, const void *data, const void *userdata, char **ret) {
36444d22
LP
197 char *t;
198
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.
201
c987fefc 202 * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
36444d22
LP
203 * specifer_user_id() below.
204 */
205
206 t = uid_to_name(getuid());
207 if (!t)
208 return -ENOMEM;
209
210 *ret = t;
211 return 0;
212}
213
303ee601 214int specifier_user_id(char specifier, const void *data, const void *userdata, char **ret) {
36444d22
LP
215
216 if (asprintf(ret, UID_FMT, getuid()) < 0)
217 return -ENOMEM;
218
219 return 0;
220}
221
303ee601 222int specifier_user_home(char specifier, const void *data, const void *userdata, char **ret) {
36444d22
LP
223
224 /* On PID 1 (which runs as root) this will not result in NSS,
225 * which is good. See above */
226
227 return get_home_dir(ret);
228}
229
303ee601 230int specifier_user_shell(char specifier, const void *data, const void *userdata, char **ret) {
36444d22
LP
231
232 /* On PID 1 (which runs as root) this will not result in NSS,
233 * which is good. See above */
234
235 return get_shell(ret);
236}
237
303ee601 238int specifier_tmp_dir(char specifier, const void *data, const void *userdata, char **ret) {
b294e594
LP
239 const char *p;
240 char *copy;
241 int r;
242
243 r = tmp_dir(&p);
244 if (r < 0)
245 return r;
246
247 copy = strdup(p);
248 if (!copy)
249 return -ENOMEM;
250
251 *ret = copy;
252 return 0;
253}
254
303ee601 255int specifier_var_tmp_dir(char specifier, const void *data, const void *userdata, char **ret) {
b294e594
LP
256 const char *p;
257 char *copy;
258 int r;
259
260 r = var_tmp_dir(&p);
261 if (r < 0)
262 return r;
263
264 copy = strdup(p);
265 if (!copy)
266 return -ENOMEM;
267
268 *ret = copy;
269 return 0;
270}
271
e82f30d1
LP
272int specifier_escape_strv(char **l, char ***ret) {
273 char **z, **p, **q;
274
275 assert(ret);
276
277 if (strv_isempty(l)) {
278 *ret = NULL;
279 return 0;
280 }
281
282 z = new(char*, strv_length(l)+1);
283 if (!z)
284 return -ENOMEM;
285
286 for (p = l, q = z; *p; p++, q++) {
287
288 *q = specifier_escape(*p);
289 if (!*q) {
290 strv_free(z);
291 return -ENOMEM;
292 }
293 }
294
295 *q = NULL;
296 *ret = z;
297
298 return 0;
299}