]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
41f9172f | 2 | /*** |
41f9172f | 3 | Copyright 2010 Lennart Poettering |
41f9172f LP |
4 | ***/ |
5 | ||
b5efdb8a | 6 | #include "alloc-util.h" |
07630cea | 7 | #include "cgroup-util.h" |
f97b34a6 | 8 | #include "format-util.h" |
07630cea | 9 | #include "macro.h" |
41f9172f | 10 | #include "specifier.h" |
07630cea | 11 | #include "string-util.h" |
41f9172f LP |
12 | #include "strv.h" |
13 | #include "unit-name.h" | |
14 | #include "unit-printf.h" | |
b1d4f8e1 LP |
15 | #include "unit.h" |
16 | #include "user-util.h" | |
41f9172f | 17 | |
19f6d710 | 18 | static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 19 | Unit *u = userdata; |
19f6d710 | 20 | |
41f9172f LP |
21 | assert(u); |
22 | ||
7410616c | 23 | return unit_name_to_prefix_and_instance(u->id, ret); |
41f9172f LP |
24 | } |
25 | ||
19f6d710 | 26 | static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 27 | Unit *u = userdata; |
19f6d710 | 28 | |
41f9172f LP |
29 | assert(u); |
30 | ||
7410616c | 31 | return unit_name_to_prefix(u->id, ret); |
41f9172f LP |
32 | } |
33 | ||
19f6d710 | 34 | static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) { |
19f6d710 | 35 | _cleanup_free_ char *p = NULL; |
7410616c LP |
36 | Unit *u = userdata; |
37 | int r; | |
41f9172f LP |
38 | |
39 | assert(u); | |
40 | ||
7410616c LP |
41 | r = unit_name_to_prefix(u->id, &p); |
42 | if (r < 0) | |
43 | return r; | |
41f9172f | 44 | |
7410616c | 45 | return unit_name_unescape(p, ret); |
41f9172f LP |
46 | } |
47 | ||
19f6d710 | 48 | static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 49 | Unit *u = userdata; |
19f6d710 | 50 | |
41f9172f LP |
51 | assert(u); |
52 | ||
115cbf7e | 53 | return unit_name_unescape(strempty(u->instance), ret); |
41f9172f LP |
54 | } |
55 | ||
250e9fad ZJS |
56 | static int specifier_last_component(char specifier, void *data, void *userdata, char **ret) { |
57 | Unit *u = userdata; | |
58 | _cleanup_free_ char *prefix = NULL; | |
59 | char *dash; | |
60 | int r; | |
61 | ||
62 | assert(u); | |
63 | ||
64 | r = unit_name_to_prefix(u->id, &prefix); | |
65 | if (r < 0) | |
66 | return r; | |
67 | ||
68 | dash = strrchr(prefix, '-'); | |
69 | if (dash) | |
70 | return specifier_string(specifier, dash + 1, userdata, ret); | |
71 | ||
72 | *ret = TAKE_PTR(prefix); | |
73 | return 0; | |
74 | } | |
75 | ||
76 | static int specifier_last_component_unescaped(char specifier, void *data, void *userdata, char **ret) { | |
77 | _cleanup_free_ char *p = NULL; | |
78 | int r; | |
79 | ||
80 | r = specifier_last_component(specifier, data, userdata, &p); | |
81 | if (r < 0) | |
82 | return r; | |
83 | ||
84 | return unit_name_unescape(p, ret); | |
85 | } | |
86 | ||
19f6d710 | 87 | static int specifier_filename(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 88 | Unit *u = userdata; |
19f6d710 | 89 | |
41f9172f LP |
90 | assert(u); |
91 | ||
92 | if (u->instance) | |
7410616c | 93 | return unit_name_path_unescape(u->instance, ret); |
19f6d710 | 94 | else |
7410616c | 95 | return unit_name_to_path(u->id, ret); |
41f9172f LP |
96 | } |
97 | ||
1b89b0c4 LP |
98 | static void bad_specifier(Unit *u, char specifier) { |
99 | log_unit_warning(u, "Specifier '%%%c' used in unit configuration, which is deprecated. Please update your unit file, as it does not work as intended.", specifier); | |
100 | } | |
101 | ||
19f6d710 | 102 | static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 103 | Unit *u = userdata; |
19f6d710 LP |
104 | char *n; |
105 | ||
41f9172f LP |
106 | assert(u); |
107 | ||
1b89b0c4 LP |
108 | bad_specifier(u, specifier); |
109 | ||
2cfbd749 LP |
110 | if (u->cgroup_path) |
111 | n = strdup(u->cgroup_path); | |
112 | else | |
113 | n = unit_default_cgroup_path(u); | |
19f6d710 LP |
114 | if (!n) |
115 | return -ENOMEM; | |
116 | ||
117 | *ret = n; | |
118 | return 0; | |
41f9172f LP |
119 | } |
120 | ||
19f6d710 | 121 | static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 122 | Unit *u = userdata; |
19f6d710 | 123 | char *n; |
41f9172f | 124 | |
9444b1f2 | 125 | assert(u); |
41f9172f | 126 | |
1b89b0c4 LP |
127 | bad_specifier(u, specifier); |
128 | ||
696fd1ef LP |
129 | n = strdup(u->manager->cgroup_root); |
130 | if (!n) | |
131 | return -ENOMEM; | |
41f9172f | 132 | |
696fd1ef LP |
133 | *ret = n; |
134 | return 0; | |
135 | } | |
19f6d710 | 136 | |
696fd1ef LP |
137 | static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) { |
138 | Unit *u = userdata; | |
139 | char *n; | |
140 | ||
141 | assert(u); | |
142 | ||
1b89b0c4 LP |
143 | bad_specifier(u, specifier); |
144 | ||
696fd1ef LP |
145 | if (UNIT_ISSET(u->slice)) { |
146 | Unit *slice; | |
147 | ||
148 | slice = UNIT_DEREF(u->slice); | |
149 | ||
150 | if (slice->cgroup_path) | |
151 | n = strdup(slice->cgroup_path); | |
152 | else | |
153 | n = unit_default_cgroup_path(slice); | |
154 | } else | |
155 | n = strdup(u->manager->cgroup_root); | |
115cbf7e EV |
156 | if (!n) |
157 | return -ENOMEM; | |
41f9172f | 158 | |
19f6d710 LP |
159 | *ret = n; |
160 | return 0; | |
41f9172f LP |
161 | } |
162 | ||
14068e17 | 163 | static int specifier_special_directory(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 164 | Unit *u = userdata; |
19f6d710 LP |
165 | char *n = NULL; |
166 | ||
41f9172f LP |
167 | assert(u); |
168 | ||
14068e17 | 169 | n = strdup(u->manager->prefix[PTR_TO_UINT(data)]); |
2cfbd749 LP |
170 | if (!n) |
171 | return -ENOMEM; | |
19f6d710 LP |
172 | |
173 | *ret = n; | |
174 | return 0; | |
41f9172f LP |
175 | } |
176 | ||
19f6d710 | 177 | int unit_name_printf(Unit *u, const char* format, char **ret) { |
41f9172f LP |
178 | |
179 | /* | |
b1801e64 LP |
180 | * This will use the passed string as format string and replace the following specifiers (which should all be |
181 | * safe for inclusion in unit names): | |
41f9172f LP |
182 | * |
183 | * %n: the full id of the unit (foo@bar.waldo) | |
184 | * %N: the id of the unit without the suffix (foo@bar) | |
185 | * %p: the prefix (foo) | |
186 | * %i: the instance (bar) | |
b1801e64 LP |
187 | * |
188 | * %U: the UID of the running user | |
189 | * %u: the username of the running user | |
190 | * | |
191 | * %m: the machine ID of the running system | |
192 | * %H: the host name of the running system | |
193 | * %b: the boot ID of the running system | |
41f9172f LP |
194 | */ |
195 | ||
196 | const Specifier table[] = { | |
197 | { 'n', specifier_string, u->id }, | |
198 | { 'N', specifier_prefix_and_instance, NULL }, | |
199 | { 'p', specifier_prefix, NULL }, | |
200 | { 'i', specifier_string, u->instance }, | |
b1801e64 LP |
201 | |
202 | { 'U', specifier_user_id, NULL }, | |
203 | { 'u', specifier_user_name, NULL }, | |
204 | ||
205 | { 'm', specifier_machine_id, NULL }, | |
206 | { 'H', specifier_host_name, NULL }, | |
207 | { 'b', specifier_boot_id, NULL }, | |
208 | {} | |
41f9172f LP |
209 | }; |
210 | ||
211 | assert(u); | |
212 | assert(format); | |
19f6d710 | 213 | assert(ret); |
41f9172f | 214 | |
19f6d710 | 215 | return specifier_printf(format, table, u, ret); |
41f9172f LP |
216 | } |
217 | ||
19f6d710 | 218 | int unit_full_printf(Unit *u, const char *format, char **ret) { |
41f9172f | 219 | |
b1801e64 LP |
220 | /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of additional codes |
221 | * (which are likely not suitable for unescaped inclusion in unit names): | |
222 | * | |
223 | * %f: the unescaped instance if set, otherwise the id unescaped as path | |
14068e17 | 224 | * |
1b89b0c4 LP |
225 | * %c: cgroup path of unit (deprecated) |
226 | * %r: where units in this slice are placed in the cgroup tree (deprecated) | |
227 | * %R: the root of this systemd's instance tree (deprecated) | |
14068e17 LP |
228 | * |
229 | * %t: the runtime directory root (e.g. /run or $XDG_RUNTIME_DIR) | |
230 | * %S: the state directory root (e.g. /var/lib or $XDG_CONFIG_HOME) | |
231 | * %C: the cache directory root (e.g. /var/cache or $XDG_CACHE_HOME) | |
232 | * %L: the log directory root (e.g. /var/log or $XDG_CONFIG_HOME/log) | |
b294e594 LP |
233 | * %T: the temporary directory (e.g. /tmp, or $TMPDIR, $TEMP, $TMP) |
234 | * %V: the temporary directory for large, persistent stuff (e.g. /var/tmp, or $TMPDIR, $TEMP, $TMP) | |
b1801e64 LP |
235 | * |
236 | * %h: the homedir of the running user | |
237 | * %s: the shell of the running user | |
41f9172f | 238 | * |
b1801e64 | 239 | * %v: `uname -r` of the running system |
03fc9c72 LP |
240 | * |
241 | * NOTICE: When you add new entries here, please be careful: specifiers which depend on settings of the unit | |
242 | * file itself are broken by design, as they would resolve differently depending on whether they are used | |
243 | * before or after the relevant configuration setting. Hence: don't add them. | |
41f9172f LP |
244 | */ |
245 | ||
246 | const Specifier table[] = { | |
250e9fad ZJS |
247 | { 'n', specifier_string, u->id }, |
248 | { 'N', specifier_prefix_and_instance, NULL }, | |
249 | { 'p', specifier_prefix, NULL }, | |
250 | { 'P', specifier_prefix_unescaped, NULL }, | |
251 | { 'i', specifier_string, u->instance }, | |
252 | { 'I', specifier_instance_unescaped, NULL }, | |
253 | { 'j', specifier_last_component, NULL }, | |
254 | { 'J', specifier_last_component_unescaped, NULL }, | |
255 | ||
256 | { 'f', specifier_filename, NULL }, | |
257 | { 'c', specifier_cgroup, NULL }, | |
258 | { 'r', specifier_cgroup_slice, NULL }, | |
259 | { 'R', specifier_cgroup_root, NULL }, | |
b294e594 | 260 | |
250e9fad ZJS |
261 | { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) }, |
262 | { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) }, | |
263 | { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) }, | |
264 | { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) }, | |
b294e594 LP |
265 | { 'T', specifier_tmp_dir, NULL }, |
266 | { 'V', specifier_var_tmp_dir, NULL }, | |
250e9fad ZJS |
267 | |
268 | { 'U', specifier_user_id, NULL }, | |
269 | { 'u', specifier_user_name, NULL }, | |
270 | { 'h', specifier_user_home, NULL }, | |
271 | { 's', specifier_user_shell, NULL }, | |
272 | ||
273 | { 'm', specifier_machine_id, NULL }, | |
274 | { 'H', specifier_host_name, NULL }, | |
275 | { 'b', specifier_boot_id, NULL }, | |
276 | { 'v', specifier_kernel_release, NULL }, | |
6aaa8c2f | 277 | {} |
41f9172f LP |
278 | }; |
279 | ||
19f6d710 | 280 | assert(u); |
41f9172f | 281 | assert(format); |
19f6d710 | 282 | assert(ret); |
41f9172f | 283 | |
19f6d710 | 284 | return specifier_printf(format, table, u, ret); |
41f9172f LP |
285 | } |
286 | ||
19f6d710 | 287 | int unit_full_printf_strv(Unit *u, char **l, char ***ret) { |
41f9172f LP |
288 | size_t n; |
289 | char **r, **i, **j; | |
19f6d710 | 290 | int q; |
41f9172f LP |
291 | |
292 | /* Applies unit_full_printf to every entry in l */ | |
293 | ||
294 | assert(u); | |
295 | ||
296 | n = strv_length(l); | |
297 | r = new(char*, n+1); | |
298 | if (!r) | |
19f6d710 | 299 | return -ENOMEM; |
41f9172f LP |
300 | |
301 | for (i = l, j = r; *i; i++, j++) { | |
19f6d710 LP |
302 | q = unit_full_printf(u, *i, j); |
303 | if (q < 0) | |
41f9172f LP |
304 | goto fail; |
305 | } | |
306 | ||
307 | *j = NULL; | |
19f6d710 LP |
308 | *ret = r; |
309 | return 0; | |
41f9172f LP |
310 | |
311 | fail: | |
312 | for (j--; j >= r; j--) | |
313 | free(*j); | |
314 | ||
315 | free(r); | |
19f6d710 | 316 | return q; |
41f9172f | 317 | } |