]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-printf.c
io.systemd.Unit.List fix context/runtime split (#38172)
[thirdparty/systemd.git] / src / core / unit-printf.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
41f9172f 2
1cf40697
DDM
3#include "sd-path.h"
4
b5efdb8a 5#include "alloc-util.h"
836e4e7e
DDM
6#include "creds-util.h"
7#include "env-util.h"
8#include "fd-util.h"
9#include "fileio.h"
4ea4abb6 10#include "manager.h"
41f9172f 11#include "specifier.h"
07630cea 12#include "string-util.h"
1cf40697 13#include "unit.h"
41f9172f
LP
14#include "unit-name.h"
15#include "unit-printf.h"
16
de61a04b 17static int specifier_prefix_and_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 18 const Unit *u = ASSERT_PTR(userdata);
41f9172f 19
7410616c 20 return unit_name_to_prefix_and_instance(u->id, ret);
41f9172f
LP
21}
22
de61a04b 23static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 24 const Unit *u = ASSERT_PTR(userdata);
41f9172f 25
7410616c 26 return unit_name_to_prefix(u->id, ret);
41f9172f
LP
27}
28
de61a04b 29static int specifier_prefix_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
19f6d710 30 _cleanup_free_ char *p = NULL;
601dc59b 31 const Unit *u = ASSERT_PTR(userdata);
7410616c 32 int r;
41f9172f 33
7410616c
LP
34 r = unit_name_to_prefix(u->id, &p);
35 if (r < 0)
36 return r;
41f9172f 37
7410616c 38 return unit_name_unescape(p, ret);
41f9172f
LP
39}
40
de61a04b 41static int specifier_instance_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 42 const Unit *u = ASSERT_PTR(userdata);
41f9172f 43
115cbf7e 44 return unit_name_unescape(strempty(u->instance), ret);
41f9172f
LP
45}
46
de61a04b 47static int specifier_last_component(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 48 const Unit *u = ASSERT_PTR(userdata);
250e9fad
ZJS
49 _cleanup_free_ char *prefix = NULL;
50 char *dash;
51 int r;
52
250e9fad
ZJS
53 r = unit_name_to_prefix(u->id, &prefix);
54 if (r < 0)
55 return r;
56
57 dash = strrchr(prefix, '-');
58 if (dash)
de61a04b 59 return specifier_string(specifier, dash + 1, root, userdata, ret);
250e9fad
ZJS
60
61 *ret = TAKE_PTR(prefix);
62 return 0;
63}
64
de61a04b 65static int specifier_last_component_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
250e9fad
ZJS
66 _cleanup_free_ char *p = NULL;
67 int r;
68
de61a04b 69 r = specifier_last_component(specifier, data, root, userdata, &p);
250e9fad
ZJS
70 if (r < 0)
71 return r;
72
73 return unit_name_unescape(p, ret);
74}
75
de61a04b 76static int specifier_filename(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 77 const Unit *u = ASSERT_PTR(userdata);
41f9172f
LP
78
79 if (u->instance)
7410616c 80 return unit_name_path_unescape(u->instance, ret);
19f6d710 81 else
7410616c 82 return unit_name_to_path(u->id, ret);
41f9172f
LP
83}
84
303ee601 85static void bad_specifier(const Unit *u, char specifier) {
1b89b0c4
LP
86 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);
87}
88
de61a04b 89static int specifier_cgroup(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 90 const Unit *u = ASSERT_PTR(userdata);
19f6d710 91
1b89b0c4
LP
92 bad_specifier(u, specifier);
93
9fe837d5 94 return unit_get_cgroup_path_with_fallback(u, ret);
41f9172f
LP
95}
96
de61a04b 97static int specifier_cgroup_root(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 98 const Unit *u = ASSERT_PTR(userdata);
41f9172f 99
1b89b0c4
LP
100 bad_specifier(u, specifier);
101
045d9424 102 return strdup_to(ret, u->manager->cgroup_root);
696fd1ef 103}
19f6d710 104
de61a04b 105static int specifier_cgroup_slice(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 106 const Unit *u = ASSERT_PTR(userdata), *slice;
696fd1ef 107
1b89b0c4
LP
108 bad_specifier(u, specifier);
109
12f64221 110 slice = UNIT_GET_SLICE(u);
9fe837d5
MY
111 if (slice)
112 return unit_get_cgroup_path_with_fallback(slice, ret);
045d9424
ZJS
113
114 return strdup_to(ret, u->manager->cgroup_root);
41f9172f
LP
115}
116
de61a04b 117static int specifier_special_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
601dc59b 118 const Unit *u = ASSERT_PTR(userdata);
19f6d710 119
045d9424 120 return strdup_to(ret, u->manager->prefix[PTR_TO_UINT(data)]);
41f9172f
LP
121}
122
43b9b205
FS
123static int specifier_credentials_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
124 const Unit *u = ASSERT_PTR(userdata);
125 char *d;
126
127 assert(ret);
128
129 d = strjoin(u->manager->prefix[EXEC_DIRECTORY_RUNTIME], "/credentials/", u->id);
130 if (!d)
131 return -ENOMEM;
132
133 *ret = d;
134 return 0;
135}
136
cc51085a
AV
137static int specifier_shared_data_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
138 const Unit *u = ASSERT_PTR(userdata);
139
140 assert(ret);
141
142 return sd_path_lookup(MANAGER_IS_SYSTEM(u->manager) ? SD_PATH_SYSTEM_SHARED : SD_PATH_USER_SHARED, NULL, ret);
143}
144
a2262bca 145int unit_name_printf(const Unit *u, const char* format, char **ret) {
41f9172f 146 /*
b1801e64
LP
147 * This will use the passed string as format string and replace the following specifiers (which should all be
148 * safe for inclusion in unit names):
41f9172f 149 *
e93387f3
YW
150 * %n: the full id of the unit (foo-aaa@bar.waldo)
151 * %N: the id of the unit without the suffix (foo-aaa@bar)
152 * %p: the prefix (foo-aaa)
41f9172f 153 * %i: the instance (bar)
751b4400 154 * %j: the last component of the prefix (aaa)
41f9172f
LP
155 */
156
157 const Specifier table[] = {
e93387f3
YW
158 { 'i', specifier_string, u->instance },
159 { 'j', specifier_last_component, NULL },
41f9172f
LP
160 { 'n', specifier_string, u->id },
161 { 'N', specifier_prefix_and_instance, NULL },
162 { 'p', specifier_prefix, NULL },
2824aa07
LP
163
164 COMMON_SYSTEM_SPECIFIERS,
e93387f3 165
4870133b 166 COMMON_CREDS_SPECIFIERS(u->manager->runtime_scope),
b1801e64 167 {}
41f9172f
LP
168 };
169
170 assert(u);
171 assert(format);
19f6d710 172 assert(ret);
41f9172f 173
de61a04b 174 return specifier_printf(format, UNIT_NAME_MAX, table, NULL, u, ret);
41f9172f
LP
175}
176
06536492 177int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, char **ret) {
ec7401d0
ZJS
178 /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of
179 * additional codes (which are likely not suitable for unescaped inclusion in unit names):
b1801e64
LP
180 *
181 * %f: the unescaped instance if set, otherwise the id unescaped as path
14068e17 182 *
1b89b0c4
LP
183 * %c: cgroup path of unit (deprecated)
184 * %r: where units in this slice are placed in the cgroup tree (deprecated)
185 * %R: the root of this systemd's instance tree (deprecated)
14068e17 186 *
14068e17 187 * %C: the cache directory root (e.g. /var/cache or $XDG_CACHE_HOME)
43b9b205 188 * %d: the credentials directory ($CREDENTIALS_DIRECTORY)
cc51085a 189 * %D: the shared data root (e.g. /usr/share or $XDG_DATA_HOME)
969309c2 190 * %E: the configuration directory root (e.g. /etc or $XDG_CONFIG_HOME)
f9c91932
LP
191 * %L: the log directory root (e.g. /var/log or $XDG_STATE_HOME/log)
192 * %S: the state directory root (e.g. /var/lib or $XDG_STATE_HOME)
e93387f3 193 * %t: the runtime directory root (e.g. /run or $XDG_RUNTIME_DIR)
b1801e64
LP
194 *
195 * %h: the homedir of the running user
196 * %s: the shell of the running user
41f9172f 197 *
ec7401d0
ZJS
198 * NOTICE: When you add new entries here, please be careful: specifiers which depend on settings of
199 * the unit file itself are broken by design, as they would resolve differently depending on whether
200 * they are used before or after the relevant configuration setting. Hence: don't add them.
41f9172f
LP
201 */
202
48f48b8c
ZJS
203 assert(u);
204 assert(format);
205 assert(ret);
206
41f9172f 207 const Specifier table[] = {
250e9fad
ZJS
208 { 'i', specifier_string, u->instance },
209 { 'I', specifier_instance_unescaped, NULL },
210 { 'j', specifier_last_component, NULL },
211 { 'J', specifier_last_component_unescaped, NULL },
e93387f3
YW
212 { 'n', specifier_string, u->id },
213 { 'N', specifier_prefix_and_instance, NULL },
214 { 'p', specifier_prefix, NULL },
215 { 'P', specifier_prefix_unescaped, NULL },
250e9fad
ZJS
216
217 { 'f', specifier_filename, NULL },
607f0328
ZJS
218 { 'y', specifier_real_path, u->fragment_path },
219 { 'Y', specifier_real_directory, u->fragment_path },
e93387f3 220
ec7401d0
ZJS
221 { 'c', specifier_cgroup, NULL }, /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
222 { 'r', specifier_cgroup_slice, NULL }, /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
223 { 'R', specifier_cgroup_root, NULL }, /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
b294e594 224
250e9fad 225 { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
43b9b205 226 { 'd', specifier_credentials_dir, NULL },
cc51085a 227 { 'D', specifier_shared_data_dir, NULL },
969309c2 228 { 'E', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CONFIGURATION) },
e93387f3
YW
229 { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) },
230 { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) },
231 { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) },
250e9fad 232
250e9fad
ZJS
233 { 'h', specifier_user_home, NULL },
234 { 's', specifier_user_shell, NULL },
235
2824aa07 236 COMMON_SYSTEM_SPECIFIERS,
e93387f3 237
4870133b 238 COMMON_CREDS_SPECIFIERS(u->manager->runtime_scope),
e93387f3
YW
239
240 COMMON_TMP_SPECIFIERS,
6aaa8c2f 241 {}
41f9172f
LP
242 };
243
de61a04b 244 return specifier_printf(format, max_length, table, NULL, u, ret);
41f9172f 245}
836e4e7e
DDM
246
247int unit_full_printf(const Unit *u, const char *text, char **ret) {
248 return unit_full_printf_full(u, text, LONG_LINE_MAX, ret);
249}
250
251int unit_path_printf(const Unit *u, const char *text, char **ret) {
252 return unit_full_printf_full(u, text, PATH_MAX-1, ret);
253}
254
255int unit_fd_printf(const Unit *u, const char *text, char **ret) {
256 return unit_full_printf_full(u, text, FDNAME_MAX, ret);
257}
258
259int unit_cred_printf(const Unit *u, const char *text, char **ret) {
260 return unit_full_printf_full(u, text, CREDENTIAL_NAME_MAX, ret);
261}
262
263int unit_env_printf(const Unit *u, const char *text, char **ret) {
264 return unit_full_printf_full(u, text, sc_arg_max(), ret);
265}