]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/unit-printf.c
7c8bf991507232fb44f0d1e1b8850caa2671b04d
[thirdparty/systemd.git] / src / core / unit-printf.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "sd-path.h"
4
5 #include "alloc-util.h"
6 #include "creds-util.h"
7 #include "env-util.h"
8 #include "fd-util.h"
9 #include "fileio.h"
10 #include "manager.h"
11 #include "specifier.h"
12 #include "string-util.h"
13 #include "unit.h"
14 #include "unit-name.h"
15 #include "unit-printf.h"
16
17 static int specifier_prefix_and_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
18 const Unit *u = ASSERT_PTR(userdata);
19
20 return unit_name_to_prefix_and_instance(u->id, ret);
21 }
22
23 static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
24 const Unit *u = ASSERT_PTR(userdata);
25
26 return unit_name_to_prefix(u->id, ret);
27 }
28
29 static int specifier_prefix_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
30 _cleanup_free_ char *p = NULL;
31 const Unit *u = ASSERT_PTR(userdata);
32 int r;
33
34 r = unit_name_to_prefix(u->id, &p);
35 if (r < 0)
36 return r;
37
38 return unit_name_unescape(p, ret);
39 }
40
41 static int specifier_instance_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
42 const Unit *u = ASSERT_PTR(userdata);
43
44 return unit_name_unescape(strempty(u->instance), ret);
45 }
46
47 static int specifier_last_component(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
48 const Unit *u = ASSERT_PTR(userdata);
49 _cleanup_free_ char *prefix = NULL;
50 char *dash;
51 int r;
52
53 r = unit_name_to_prefix(u->id, &prefix);
54 if (r < 0)
55 return r;
56
57 dash = strrchr(prefix, '-');
58 if (dash)
59 return specifier_string(specifier, dash + 1, root, userdata, ret);
60
61 *ret = TAKE_PTR(prefix);
62 return 0;
63 }
64
65 static int specifier_last_component_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
66 _cleanup_free_ char *p = NULL;
67 int r;
68
69 r = specifier_last_component(specifier, data, root, userdata, &p);
70 if (r < 0)
71 return r;
72
73 return unit_name_unescape(p, ret);
74 }
75
76 static int specifier_filename(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
77 const Unit *u = ASSERT_PTR(userdata);
78
79 if (u->instance)
80 return unit_name_path_unescape(u->instance, ret);
81 else
82 return unit_name_to_path(u->id, ret);
83 }
84
85 static void bad_specifier(const Unit *u, char specifier) {
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
89 static int specifier_cgroup(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
90 const Unit *u = ASSERT_PTR(userdata);
91
92 bad_specifier(u, specifier);
93
94 return unit_get_cgroup_path_with_fallback(u, ret);
95 }
96
97 static int specifier_cgroup_root(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
98 const Unit *u = ASSERT_PTR(userdata);
99
100 bad_specifier(u, specifier);
101
102 return strdup_to(ret, u->manager->cgroup_root);
103 }
104
105 static int specifier_cgroup_slice(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
106 const Unit *u = ASSERT_PTR(userdata), *slice;
107
108 bad_specifier(u, specifier);
109
110 slice = UNIT_GET_SLICE(u);
111 if (slice)
112 return unit_get_cgroup_path_with_fallback(slice, ret);
113
114 return strdup_to(ret, u->manager->cgroup_root);
115 }
116
117 static int specifier_special_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
118 const Unit *u = ASSERT_PTR(userdata);
119
120 return strdup_to(ret, u->manager->prefix[PTR_TO_UINT(data)]);
121 }
122
123 static 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
137 static 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
145 int unit_name_printf(const Unit *u, const char* format, char **ret) {
146 /*
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):
149 *
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)
153 * %i: the instance (bar)
154 * %j: the last component of the prefix (aaa)
155 */
156
157 const Specifier table[] = {
158 { 'i', specifier_string, u->instance },
159 { 'j', specifier_last_component, NULL },
160 { 'n', specifier_string, u->id },
161 { 'N', specifier_prefix_and_instance, NULL },
162 { 'p', specifier_prefix, NULL },
163
164 COMMON_SYSTEM_SPECIFIERS,
165
166 COMMON_CREDS_SPECIFIERS(u->manager->runtime_scope),
167 {}
168 };
169
170 assert(u);
171 assert(format);
172 assert(ret);
173
174 return specifier_printf(format, UNIT_NAME_MAX, table, NULL, u, ret);
175 }
176
177 int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, char **ret) {
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):
180 *
181 * %f: the unescaped instance if set, otherwise the id unescaped as path
182 *
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)
186 *
187 * %C: the cache directory root (e.g. /var/cache or $XDG_CACHE_HOME)
188 * %d: the credentials directory ($CREDENTIALS_DIRECTORY)
189 * %D: the shared data root (e.g. /usr/share or $XDG_DATA_HOME)
190 * %E: the configuration directory root (e.g. /etc or $XDG_CONFIG_HOME)
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)
193 * %t: the runtime directory root (e.g. /run or $XDG_RUNTIME_DIR)
194 *
195 * %h: the homedir of the running user
196 * %s: the shell of the running user
197 *
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.
201 */
202
203 assert(u);
204 assert(format);
205 assert(ret);
206
207 const Specifier table[] = {
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 },
212 { 'n', specifier_string, u->id },
213 { 'N', specifier_prefix_and_instance, NULL },
214 { 'p', specifier_prefix, NULL },
215 { 'P', specifier_prefix_unescaped, NULL },
216
217 { 'f', specifier_filename, NULL },
218 { 'y', specifier_real_path, u->fragment_path },
219 { 'Y', specifier_real_directory, u->fragment_path },
220
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 */
224
225 { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
226 { 'd', specifier_credentials_dir, NULL },
227 { 'D', specifier_shared_data_dir, NULL },
228 { 'E', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CONFIGURATION) },
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) },
232
233 { 'h', specifier_user_home, NULL },
234 { 's', specifier_user_shell, NULL },
235
236 COMMON_SYSTEM_SPECIFIERS,
237
238 COMMON_CREDS_SPECIFIERS(u->manager->runtime_scope),
239
240 COMMON_TMP_SPECIFIERS,
241 {}
242 };
243
244 return specifier_printf(format, max_length, table, NULL, u, ret);
245 }
246
247 int 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
251 int 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
255 int unit_fd_printf(const Unit *u, const char *text, char **ret) {
256 return unit_full_printf_full(u, text, FDNAME_MAX, ret);
257 }
258
259 int 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
263 int unit_env_printf(const Unit *u, const char *text, char **ret) {
264 return unit_full_printf_full(u, text, sc_arg_max(), ret);
265 }