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