]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
9e2f7c11 LP |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2010 Lennart Poettering | |
6 | ||
7 | systemd is free software; you can redistribute it and/or modify it | |
5430f7f2 LP |
8 | under the terms of the GNU Lesser General Public License as published by |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
9e2f7c11 LP |
10 | (at your option) any later version. |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
5430f7f2 | 15 | Lesser General Public License for more details. |
9e2f7c11 | 16 | |
5430f7f2 | 17 | You should have received a copy of the GNU Lesser General Public License |
9e2f7c11 LP |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
19 | ***/ | |
20 | ||
a8fbdf54 TA |
21 | #include <errno.h> |
22 | #include <stdbool.h> | |
23 | #include <stddef.h> | |
24 | #include <stdlib.h> | |
9e2f7c11 | 25 | #include <string.h> |
6aaa8c2f | 26 | #include <sys/utsname.h> |
9e2f7c11 | 27 | |
a8fbdf54 TA |
28 | #include "sd-id128.h" |
29 | ||
b5efdb8a | 30 | #include "alloc-util.h" |
07630cea | 31 | #include "hostname-util.h" |
9e2f7c11 | 32 | #include "macro.h" |
b5efdb8a | 33 | #include "specifier.h" |
07630cea | 34 | #include "string-util.h" |
e82f30d1 | 35 | #include "strv.h" |
36444d22 | 36 | #include "user-util.h" |
9e2f7c11 LP |
37 | |
38 | /* | |
39 | * Generic infrastructure for replacing %x style specifiers in | |
40 | * strings. Will call a callback for each replacement. | |
41 | * | |
42 | */ | |
43 | ||
751223fe ZJS |
44 | /* Any ASCII character or digit: our pool of potential specifiers, |
45 | * and "%" used for escaping. */ | |
46 | #define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%" | |
47 | ||
19f6d710 | 48 | int specifier_printf(const char *text, const Specifier table[], void *userdata, char **_ret) { |
8208c8f2 ZJS |
49 | size_t l; |
50 | _cleanup_free_ char *ret = NULL; | |
51 | char *t; | |
9e2f7c11 LP |
52 | const char *f; |
53 | bool percent = false; | |
19f6d710 | 54 | int r; |
9e2f7c11 LP |
55 | |
56 | assert(text); | |
57 | assert(table); | |
58 | ||
59 | l = strlen(text); | |
19f6d710 LP |
60 | ret = new(char, l+1); |
61 | if (!ret) | |
62 | return -ENOMEM; | |
9e2f7c11 | 63 | |
19f6d710 | 64 | t = ret; |
9e2f7c11 LP |
65 | |
66 | for (f = text; *f; f++, l--) { | |
67 | ||
68 | if (percent) { | |
69 | if (*f == '%') | |
70 | *(t++) = '%'; | |
71 | else { | |
72 | const Specifier *i; | |
73 | ||
74 | for (i = table; i->specifier; i++) | |
75 | if (i->specifier == *f) | |
76 | break; | |
77 | ||
78 | if (i->lookup) { | |
19f6d710 LP |
79 | _cleanup_free_ char *w = NULL; |
80 | char *n; | |
9e2f7c11 LP |
81 | size_t k, j; |
82 | ||
19f6d710 | 83 | r = i->lookup(i->specifier, i->data, userdata, &w); |
8208c8f2 | 84 | if (r < 0) |
19f6d710 | 85 | return r; |
9e2f7c11 | 86 | |
19f6d710 | 87 | j = t - ret; |
9e2f7c11 LP |
88 | k = strlen(w); |
89 | ||
7ae03f36 | 90 | n = new(char, j + k + l + 1); |
8208c8f2 | 91 | if (!n) |
19f6d710 | 92 | return -ENOMEM; |
9e2f7c11 | 93 | |
19f6d710 | 94 | memcpy(n, ret, j); |
9e2f7c11 LP |
95 | memcpy(n + j, w, k); |
96 | ||
8208c8f2 ZJS |
97 | free_and_replace(ret, n); |
98 | t = ret + j + k; | |
99 | } else if (strchr(POSSIBLE_SPECIFIERS, *f)) | |
751223fe ZJS |
100 | /* Oops, an unknown specifier. */ |
101 | return -EBADSLT; | |
8208c8f2 | 102 | else { |
9e2f7c11 LP |
103 | *(t++) = '%'; |
104 | *(t++) = *f; | |
105 | } | |
106 | } | |
107 | ||
108 | percent = false; | |
109 | } else if (*f == '%') | |
110 | percent = true; | |
111 | else | |
112 | *(t++) = *f; | |
113 | } | |
114 | ||
038492ae FS |
115 | /* if string ended with a stray %, also end with % */ |
116 | if (percent) | |
117 | *(t++) = '%'; | |
118 | ||
9e2f7c11 | 119 | *t = 0; |
ae2a15bc | 120 | *_ret = TAKE_PTR(ret); |
19f6d710 | 121 | return 0; |
9e2f7c11 LP |
122 | } |
123 | ||
124 | /* Generic handler for simple string replacements */ | |
125 | ||
19f6d710 LP |
126 | int specifier_string(char specifier, void *data, void *userdata, char **ret) { |
127 | char *n; | |
128 | ||
129 | n = strdup(strempty(data)); | |
130 | if (!n) | |
131 | return -ENOMEM; | |
132 | ||
133 | *ret = n; | |
134 | return 0; | |
9e2f7c11 | 135 | } |
d848b9cb | 136 | |
19f6d710 | 137 | int specifier_machine_id(char specifier, void *data, void *userdata, char **ret) { |
d848b9cb | 138 | sd_id128_t id; |
19f6d710 | 139 | char *n; |
d848b9cb ZJS |
140 | int r; |
141 | ||
142 | r = sd_id128_get_machine(&id); | |
143 | if (r < 0) | |
19f6d710 | 144 | return r; |
d848b9cb | 145 | |
19f6d710 LP |
146 | n = new(char, 33); |
147 | if (!n) | |
148 | return -ENOMEM; | |
d848b9cb | 149 | |
19f6d710 LP |
150 | *ret = sd_id128_to_string(id, n); |
151 | return 0; | |
d848b9cb ZJS |
152 | } |
153 | ||
19f6d710 | 154 | int specifier_boot_id(char specifier, void *data, void *userdata, char **ret) { |
d848b9cb | 155 | sd_id128_t id; |
19f6d710 | 156 | char *n; |
d848b9cb ZJS |
157 | int r; |
158 | ||
159 | r = sd_id128_get_boot(&id); | |
160 | if (r < 0) | |
19f6d710 | 161 | return r; |
d848b9cb | 162 | |
19f6d710 LP |
163 | n = new(char, 33); |
164 | if (!n) | |
165 | return -ENOMEM; | |
d848b9cb | 166 | |
19f6d710 LP |
167 | *ret = sd_id128_to_string(id, n); |
168 | return 0; | |
d848b9cb ZJS |
169 | } |
170 | ||
19f6d710 LP |
171 | int specifier_host_name(char specifier, void *data, void *userdata, char **ret) { |
172 | char *n; | |
173 | ||
174 | n = gethostname_malloc(); | |
175 | if (!n) | |
176 | return -ENOMEM; | |
177 | ||
178 | *ret = n; | |
179 | return 0; | |
d848b9cb | 180 | } |
6aaa8c2f | 181 | |
19f6d710 | 182 | int specifier_kernel_release(char specifier, void *data, void *userdata, char **ret) { |
6aaa8c2f | 183 | struct utsname uts; |
19f6d710 | 184 | char *n; |
6aaa8c2f ZJS |
185 | int r; |
186 | ||
187 | r = uname(&uts); | |
188 | if (r < 0) | |
19f6d710 LP |
189 | return -errno; |
190 | ||
191 | n = strdup(uts.release); | |
192 | if (!n) | |
193 | return -ENOMEM; | |
6aaa8c2f | 194 | |
19f6d710 LP |
195 | *ret = n; |
196 | return 0; | |
6aaa8c2f | 197 | } |
e82f30d1 | 198 | |
36444d22 LP |
199 | int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { |
200 | char *t; | |
201 | ||
202 | /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able | |
203 | * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed. | |
204 | ||
c987fefc | 205 | * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with |
36444d22 LP |
206 | * specifer_user_id() below. |
207 | */ | |
208 | ||
209 | t = uid_to_name(getuid()); | |
210 | if (!t) | |
211 | return -ENOMEM; | |
212 | ||
213 | *ret = t; | |
214 | return 0; | |
215 | } | |
216 | ||
217 | int specifier_user_id(char specifier, void *data, void *userdata, char **ret) { | |
218 | ||
219 | if (asprintf(ret, UID_FMT, getuid()) < 0) | |
220 | return -ENOMEM; | |
221 | ||
222 | return 0; | |
223 | } | |
224 | ||
225 | int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { | |
226 | ||
227 | /* On PID 1 (which runs as root) this will not result in NSS, | |
228 | * which is good. See above */ | |
229 | ||
230 | return get_home_dir(ret); | |
231 | } | |
232 | ||
233 | int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { | |
234 | ||
235 | /* On PID 1 (which runs as root) this will not result in NSS, | |
236 | * which is good. See above */ | |
237 | ||
238 | return get_shell(ret); | |
239 | } | |
240 | ||
e82f30d1 LP |
241 | int specifier_escape_strv(char **l, char ***ret) { |
242 | char **z, **p, **q; | |
243 | ||
244 | assert(ret); | |
245 | ||
246 | if (strv_isempty(l)) { | |
247 | *ret = NULL; | |
248 | return 0; | |
249 | } | |
250 | ||
251 | z = new(char*, strv_length(l)+1); | |
252 | if (!z) | |
253 | return -ENOMEM; | |
254 | ||
255 | for (p = l, q = z; *p; p++, q++) { | |
256 | ||
257 | *q = specifier_escape(*p); | |
258 | if (!*q) { | |
259 | strv_free(z); | |
260 | return -ENOMEM; | |
261 | } | |
262 | } | |
263 | ||
264 | *q = NULL; | |
265 | *ret = z; | |
266 | ||
267 | return 0; | |
268 | } |