]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/core/unit-printf.c
io.systemd.Unit.List fix context/runtime split (#38172)
[thirdparty/systemd.git] / src / core / unit-printf.c
... / ...
CommitLineData
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
17static 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
23static 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
29static 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
41static 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
47static 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
65static 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
76static 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
85static 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
89static 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
97static 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
105static 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
117static 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
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
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
145int 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
177int 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
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}