]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-printf.c
tree-wide: use "hostname" spelling everywhere
[thirdparty/systemd.git] / src / core / unit-printf.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
41f9172f 2
b5efdb8a 3#include "alloc-util.h"
07630cea 4#include "cgroup-util.h"
f97b34a6 5#include "format-util.h"
07630cea 6#include "macro.h"
41f9172f 7#include "specifier.h"
07630cea 8#include "string-util.h"
41f9172f
LP
9#include "strv.h"
10#include "unit-name.h"
11#include "unit-printf.h"
b1d4f8e1
LP
12#include "unit.h"
13#include "user-util.h"
41f9172f 14
303ee601
ZJS
15static int specifier_prefix_and_instance(char specifier, const void *data, const void *userdata, char **ret) {
16 const Unit *u = userdata;
19f6d710 17
41f9172f
LP
18 assert(u);
19
7410616c 20 return unit_name_to_prefix_and_instance(u->id, ret);
41f9172f
LP
21}
22
303ee601
ZJS
23static int specifier_prefix(char specifier, const void *data, const void *userdata, char **ret) {
24 const Unit *u = userdata;
19f6d710 25
41f9172f
LP
26 assert(u);
27
7410616c 28 return unit_name_to_prefix(u->id, ret);
41f9172f
LP
29}
30
303ee601 31static int specifier_prefix_unescaped(char specifier, const void *data, const void *userdata, char **ret) {
19f6d710 32 _cleanup_free_ char *p = NULL;
303ee601 33 const Unit *u = userdata;
7410616c 34 int r;
41f9172f
LP
35
36 assert(u);
37
7410616c
LP
38 r = unit_name_to_prefix(u->id, &p);
39 if (r < 0)
40 return r;
41f9172f 41
7410616c 42 return unit_name_unescape(p, ret);
41f9172f
LP
43}
44
303ee601
ZJS
45static int specifier_instance_unescaped(char specifier, const void *data, const void *userdata, char **ret) {
46 const Unit *u = userdata;
19f6d710 47
41f9172f
LP
48 assert(u);
49
115cbf7e 50 return unit_name_unescape(strempty(u->instance), ret);
41f9172f
LP
51}
52
303ee601
ZJS
53static int specifier_last_component(char specifier, const void *data, const void *userdata, char **ret) {
54 const Unit *u = userdata;
250e9fad
ZJS
55 _cleanup_free_ char *prefix = NULL;
56 char *dash;
57 int r;
58
59 assert(u);
60
61 r = unit_name_to_prefix(u->id, &prefix);
62 if (r < 0)
63 return r;
64
65 dash = strrchr(prefix, '-');
66 if (dash)
67 return specifier_string(specifier, dash + 1, userdata, ret);
68
69 *ret = TAKE_PTR(prefix);
70 return 0;
71}
72
303ee601 73static int specifier_last_component_unescaped(char specifier, const void *data, const void *userdata, char **ret) {
250e9fad
ZJS
74 _cleanup_free_ char *p = NULL;
75 int r;
76
77 r = specifier_last_component(specifier, data, userdata, &p);
78 if (r < 0)
79 return r;
80
81 return unit_name_unescape(p, ret);
82}
83
303ee601
ZJS
84static int specifier_filename(char specifier, const void *data, const void *userdata, char **ret) {
85 const Unit *u = userdata;
19f6d710 86
41f9172f
LP
87 assert(u);
88
89 if (u->instance)
7410616c 90 return unit_name_path_unescape(u->instance, ret);
19f6d710 91 else
7410616c 92 return unit_name_to_path(u->id, ret);
41f9172f
LP
93}
94
303ee601 95static void bad_specifier(const Unit *u, char specifier) {
1b89b0c4
LP
96 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);
97}
98
303ee601
ZJS
99static int specifier_cgroup(char specifier, const void *data, const void *userdata, char **ret) {
100 const Unit *u = userdata;
19f6d710
LP
101 char *n;
102
41f9172f
LP
103 assert(u);
104
1b89b0c4
LP
105 bad_specifier(u, specifier);
106
2cfbd749
LP
107 if (u->cgroup_path)
108 n = strdup(u->cgroup_path);
109 else
110 n = unit_default_cgroup_path(u);
19f6d710
LP
111 if (!n)
112 return -ENOMEM;
113
114 *ret = n;
115 return 0;
41f9172f
LP
116}
117
303ee601
ZJS
118static int specifier_cgroup_root(char specifier, const void *data, const void *userdata, char **ret) {
119 const Unit *u = userdata;
19f6d710 120 char *n;
41f9172f 121
9444b1f2 122 assert(u);
41f9172f 123
1b89b0c4
LP
124 bad_specifier(u, specifier);
125
696fd1ef
LP
126 n = strdup(u->manager->cgroup_root);
127 if (!n)
128 return -ENOMEM;
41f9172f 129
696fd1ef
LP
130 *ret = n;
131 return 0;
132}
19f6d710 133
303ee601
ZJS
134static int specifier_cgroup_slice(char specifier, const void *data, const void *userdata, char **ret) {
135 const Unit *u = userdata;
696fd1ef
LP
136 char *n;
137
138 assert(u);
139
1b89b0c4
LP
140 bad_specifier(u, specifier);
141
696fd1ef 142 if (UNIT_ISSET(u->slice)) {
303ee601 143 const Unit *slice;
696fd1ef
LP
144
145 slice = UNIT_DEREF(u->slice);
146
147 if (slice->cgroup_path)
148 n = strdup(slice->cgroup_path);
149 else
150 n = unit_default_cgroup_path(slice);
151 } else
152 n = strdup(u->manager->cgroup_root);
115cbf7e
EV
153 if (!n)
154 return -ENOMEM;
41f9172f 155
19f6d710
LP
156 *ret = n;
157 return 0;
41f9172f
LP
158}
159
303ee601
ZJS
160static int specifier_special_directory(char specifier, const void *data, const void *userdata, char **ret) {
161 const Unit *u = userdata;
19f6d710
LP
162 char *n = NULL;
163
41f9172f
LP
164 assert(u);
165
14068e17 166 n = strdup(u->manager->prefix[PTR_TO_UINT(data)]);
2cfbd749
LP
167 if (!n)
168 return -ENOMEM;
19f6d710
LP
169
170 *ret = n;
171 return 0;
41f9172f
LP
172}
173
a2262bca 174int unit_name_printf(const Unit *u, const char* format, char **ret) {
41f9172f
LP
175
176 /*
b1801e64
LP
177 * This will use the passed string as format string and replace the following specifiers (which should all be
178 * safe for inclusion in unit names):
41f9172f
LP
179 *
180 * %n: the full id of the unit (foo@bar.waldo)
181 * %N: the id of the unit without the suffix (foo@bar)
182 * %p: the prefix (foo)
183 * %i: the instance (bar)
b1801e64
LP
184 *
185 * %U: the UID of the running user
186 * %u: the username of the running user
187 *
188 * %m: the machine ID of the running system
38b38500 189 * %H: the hostname of the running system
b1801e64 190 * %b: the boot ID of the running system
41f9172f
LP
191 */
192
193 const Specifier table[] = {
194 { 'n', specifier_string, u->id },
195 { 'N', specifier_prefix_and_instance, NULL },
196 { 'p', specifier_prefix, NULL },
197 { 'i', specifier_string, u->instance },
8eab7668 198 { 'j', specifier_last_component, NULL },
b1801e64 199
b75f0c69
DC
200 { 'g', specifier_group_name, NULL },
201 { 'G', specifier_group_id, NULL },
b1801e64
LP
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
a2262bca 218int unit_full_printf(const Unit *u, const char *format, char **ret) {
b1801e64
LP
219 /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of additional codes
220 * (which are likely not suitable for unescaped inclusion in unit names):
221 *
222 * %f: the unescaped instance if set, otherwise the id unescaped as path
14068e17 223 *
1b89b0c4
LP
224 * %c: cgroup path of unit (deprecated)
225 * %r: where units in this slice are placed in the cgroup tree (deprecated)
226 * %R: the root of this systemd's instance tree (deprecated)
14068e17
LP
227 *
228 * %t: the runtime directory root (e.g. /run or $XDG_RUNTIME_DIR)
229 * %S: the state directory root (e.g. /var/lib or $XDG_CONFIG_HOME)
230 * %C: the cache directory root (e.g. /var/cache or $XDG_CACHE_HOME)
231 * %L: the log directory root (e.g. /var/log or $XDG_CONFIG_HOME/log)
969309c2 232 * %E: the configuration directory root (e.g. /etc or $XDG_CONFIG_HOME)
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
48f48b8c
ZJS
246 assert(u);
247 assert(format);
248 assert(ret);
249
41f9172f 250 const Specifier table[] = {
250e9fad
ZJS
251 { 'n', specifier_string, u->id },
252 { 'N', specifier_prefix_and_instance, NULL },
253 { 'p', specifier_prefix, NULL },
254 { 'P', specifier_prefix_unescaped, NULL },
255 { 'i', specifier_string, u->instance },
256 { 'I', specifier_instance_unescaped, NULL },
257 { 'j', specifier_last_component, NULL },
258 { 'J', specifier_last_component_unescaped, NULL },
259
260 { 'f', specifier_filename, NULL },
261 { 'c', specifier_cgroup, NULL },
262 { 'r', specifier_cgroup_slice, NULL },
263 { 'R', specifier_cgroup_root, NULL },
b294e594 264
250e9fad
ZJS
265 { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) },
266 { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) },
267 { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
268 { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) },
969309c2 269 { 'E', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CONFIGURATION) },
b294e594
LP
270 { 'T', specifier_tmp_dir, NULL },
271 { 'V', specifier_var_tmp_dir, NULL },
250e9fad 272
b75f0c69
DC
273 { 'g', specifier_group_name, NULL },
274 { 'G', specifier_group_id, NULL },
250e9fad
ZJS
275 { 'U', specifier_user_id, NULL },
276 { 'u', specifier_user_name, NULL },
277 { 'h', specifier_user_home, NULL },
278 { 's', specifier_user_shell, NULL },
279
280 { 'm', specifier_machine_id, NULL },
281 { 'H', specifier_host_name, NULL },
282 { 'b', specifier_boot_id, NULL },
283 { 'v', specifier_kernel_release, NULL },
6aaa8c2f 284 {}
41f9172f
LP
285 };
286
19f6d710 287 return specifier_printf(format, table, u, ret);
41f9172f 288}