]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/specifier.c
tree-wide: drop empty lines in comments
[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
19f6d710 30int specifier_printf(const char *text, const Specifier table[], 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
19f6d710
LP
105int specifier_string(char specifier, void *data, void *userdata, char **ret) {
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
19f6d710 116int specifier_machine_id(char specifier, void *data, 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
19f6d710 133int specifier_boot_id(char specifier, void *data, 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
19f6d710
LP
150int specifier_host_name(char specifier, void *data, void *userdata, char **ret) {
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
19f6d710 161int specifier_kernel_release(char specifier, void *data, 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
36444d22
LP
178int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
179 char *t;
180
181 /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
182 * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
183
c987fefc 184 * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
36444d22
LP
185 * specifer_user_id() below.
186 */
187
188 t = uid_to_name(getuid());
189 if (!t)
190 return -ENOMEM;
191
192 *ret = t;
193 return 0;
194}
195
196int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
197
198 if (asprintf(ret, UID_FMT, getuid()) < 0)
199 return -ENOMEM;
200
201 return 0;
202}
203
204int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
205
206 /* On PID 1 (which runs as root) this will not result in NSS,
207 * which is good. See above */
208
209 return get_home_dir(ret);
210}
211
212int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
213
214 /* On PID 1 (which runs as root) this will not result in NSS,
215 * which is good. See above */
216
217 return get_shell(ret);
218}
219
b294e594
LP
220int specifier_tmp_dir(char specifier, void *data, void *userdata, char **ret) {
221 const char *p;
222 char *copy;
223 int r;
224
225 r = tmp_dir(&p);
226 if (r < 0)
227 return r;
228
229 copy = strdup(p);
230 if (!copy)
231 return -ENOMEM;
232
233 *ret = copy;
234 return 0;
235}
236
237int specifier_var_tmp_dir(char specifier, void *data, void *userdata, char **ret) {
238 const char *p;
239 char *copy;
240 int r;
241
242 r = var_tmp_dir(&p);
243 if (r < 0)
244 return r;
245
246 copy = strdup(p);
247 if (!copy)
248 return -ENOMEM;
249
250 *ret = copy;
251 return 0;
252}
253
e82f30d1
LP
254int specifier_escape_strv(char **l, char ***ret) {
255 char **z, **p, **q;
256
257 assert(ret);
258
259 if (strv_isempty(l)) {
260 *ret = NULL;
261 return 0;
262 }
263
264 z = new(char*, strv_length(l)+1);
265 if (!z)
266 return -ENOMEM;
267
268 for (p = l, q = z; *p; p++, q++) {
269
270 *q = specifier_escape(*p);
271 if (!*q) {
272 strv_free(z);
273 return -ENOMEM;
274 }
275 }
276
277 *q = NULL;
278 *ret = z;
279
280 return 0;
281}