]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-printf.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / core / unit-printf.c
CommitLineData
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 18static 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 26static 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 34static 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 48static 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
56static 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
76static 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 87static 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
98static 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 102static 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 121static 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
137static 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 163static 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 177int 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 218int 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 287int 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
311fail:
312 for (j--; j >= r; j--)
313 free(*j);
314
315 free(r);
19f6d710 316 return q;
41f9172f 317}