udev: String substitutions can be done in ENV, too
[systemd_ALT.git] / src / core / unit-printf.c
blob9f95984eb630419f1a31cde6e45a100103097fed
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "cgroup-util.h"
5 #include "format-util.h"
6 #include "macro.h"
7 #include "specifier.h"
8 #include "string-util.h"
9 #include "strv.h"
10 #include "unit-name.h"
11 #include "unit-printf.h"
12 #include "unit.h"
13 #include "user-util.h"
15 static int specifier_prefix_and_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
16 const Unit *u = ASSERT_PTR(userdata);
18 return unit_name_to_prefix_and_instance(u->id, ret);
21 static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
22 const Unit *u = ASSERT_PTR(userdata);
24 return unit_name_to_prefix(u->id, ret);
27 static int specifier_prefix_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
28 _cleanup_free_ char *p = NULL;
29 const Unit *u = ASSERT_PTR(userdata);
30 int r;
32 r = unit_name_to_prefix(u->id, &p);
33 if (r < 0)
34 return r;
36 return unit_name_unescape(p, ret);
39 static int specifier_instance_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
40 const Unit *u = ASSERT_PTR(userdata);
42 return unit_name_unescape(strempty(u->instance), ret);
45 static int specifier_last_component(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
46 const Unit *u = ASSERT_PTR(userdata);
47 _cleanup_free_ char *prefix = NULL;
48 char *dash;
49 int r;
51 r = unit_name_to_prefix(u->id, &prefix);
52 if (r < 0)
53 return r;
55 dash = strrchr(prefix, '-');
56 if (dash)
57 return specifier_string(specifier, dash + 1, root, userdata, ret);
59 *ret = TAKE_PTR(prefix);
60 return 0;
63 static int specifier_last_component_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
64 _cleanup_free_ char *p = NULL;
65 int r;
67 r = specifier_last_component(specifier, data, root, userdata, &p);
68 if (r < 0)
69 return r;
71 return unit_name_unescape(p, ret);
74 static int specifier_filename(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
75 const Unit *u = ASSERT_PTR(userdata);
77 if (u->instance)
78 return unit_name_path_unescape(u->instance, ret);
79 else
80 return unit_name_to_path(u->id, ret);
83 static void bad_specifier(const Unit *u, char specifier) {
84 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 static int specifier_cgroup(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
88 const Unit *u = ASSERT_PTR(userdata);
90 bad_specifier(u, specifier);
92 if (u->cgroup_path) {
93 char *n;
95 n = strdup(u->cgroup_path);
96 if (!n)
97 return -ENOMEM;
99 *ret = n;
100 return 0;
103 return unit_default_cgroup_path(u, ret);
106 static int specifier_cgroup_root(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
107 const Unit *u = ASSERT_PTR(userdata);
108 char *n;
110 bad_specifier(u, specifier);
112 n = strdup(u->manager->cgroup_root);
113 if (!n)
114 return -ENOMEM;
116 *ret = n;
117 return 0;
120 static int specifier_cgroup_slice(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
121 const Unit *u = ASSERT_PTR(userdata), *slice;
122 char *n;
124 bad_specifier(u, specifier);
126 slice = UNIT_GET_SLICE(u);
127 if (slice) {
128 if (slice->cgroup_path)
129 n = strdup(slice->cgroup_path);
130 else
131 return unit_default_cgroup_path(slice, ret);
132 } else
133 n = strdup(u->manager->cgroup_root);
134 if (!n)
135 return -ENOMEM;
137 *ret = n;
138 return 0;
141 static int specifier_special_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
142 const Unit *u = ASSERT_PTR(userdata);
143 char *n;
145 n = strdup(u->manager->prefix[PTR_TO_UINT(data)]);
146 if (!n)
147 return -ENOMEM;
149 *ret = n;
150 return 0;
153 static int specifier_credentials_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
154 const Unit *u = ASSERT_PTR(userdata);
155 char *d;
157 assert(ret);
159 d = strjoin(u->manager->prefix[EXEC_DIRECTORY_RUNTIME], "/credentials/", u->id);
160 if (!d)
161 return -ENOMEM;
163 *ret = d;
164 return 0;
167 int unit_name_printf(const Unit *u, const char* format, char **ret) {
169 * This will use the passed string as format string and replace the following specifiers (which should all be
170 * safe for inclusion in unit names):
172 * %n: the full id of the unit (foo-aaa@bar.waldo)
173 * %N: the id of the unit without the suffix (foo-aaa@bar)
174 * %p: the prefix (foo-aaa)
175 * %i: the instance (bar)
176 * %j: the last component of the prefix (aaa)
179 const Specifier table[] = {
180 { 'i', specifier_string, u->instance },
181 { 'j', specifier_last_component, NULL },
182 { 'n', specifier_string, u->id },
183 { 'N', specifier_prefix_and_instance, NULL },
184 { 'p', specifier_prefix, NULL },
186 COMMON_SYSTEM_SPECIFIERS,
188 COMMON_CREDS_SPECIFIERS(u->manager->runtime_scope),
192 assert(u);
193 assert(format);
194 assert(ret);
196 return specifier_printf(format, UNIT_NAME_MAX, table, NULL, u, ret);
199 int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, char **ret) {
200 /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of
201 * additional codes (which are likely not suitable for unescaped inclusion in unit names):
203 * %f: the unescaped instance if set, otherwise the id unescaped as path
205 * %c: cgroup path of unit (deprecated)
206 * %r: where units in this slice are placed in the cgroup tree (deprecated)
207 * %R: the root of this systemd's instance tree (deprecated)
209 * %C: the cache directory root (e.g. /var/cache or $XDG_CACHE_HOME)
210 * %d: the credentials directory ($CREDENTIALS_DIRECTORY)
211 * %E: the configuration directory root (e.g. /etc or $XDG_CONFIG_HOME)
212 * %L: the log directory root (e.g. /var/log or $XDG_STATE_HOME/log)
213 * %S: the state directory root (e.g. /var/lib or $XDG_STATE_HOME)
214 * %t: the runtime directory root (e.g. /run or $XDG_RUNTIME_DIR)
216 * %h: the homedir of the running user
217 * %s: the shell of the running user
219 * NOTICE: When you add new entries here, please be careful: specifiers which depend on settings of
220 * the unit file itself are broken by design, as they would resolve differently depending on whether
221 * they are used before or after the relevant configuration setting. Hence: don't add them.
224 assert(u);
225 assert(format);
226 assert(ret);
228 const Specifier table[] = {
229 { 'i', specifier_string, u->instance },
230 { 'I', specifier_instance_unescaped, NULL },
231 { 'j', specifier_last_component, NULL },
232 { 'J', specifier_last_component_unescaped, NULL },
233 { 'n', specifier_string, u->id },
234 { 'N', specifier_prefix_and_instance, NULL },
235 { 'p', specifier_prefix, NULL },
236 { 'P', specifier_prefix_unescaped, NULL },
238 { 'f', specifier_filename, NULL },
239 { 'y', specifier_real_path, u->fragment_path },
240 { 'Y', specifier_real_directory, u->fragment_path },
242 { 'c', specifier_cgroup, NULL }, /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
243 { 'r', specifier_cgroup_slice, NULL }, /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
244 { 'R', specifier_cgroup_root, NULL }, /* deprecated, see 1b89b0c499cd4bf0ff389caab4ecaae6e75f9d4e */
246 { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
247 { 'd', specifier_credentials_dir, NULL },
248 { 'E', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CONFIGURATION) },
249 { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) },
250 { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) },
251 { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) },
253 { 'h', specifier_user_home, NULL },
254 { 's', specifier_user_shell, NULL },
256 COMMON_SYSTEM_SPECIFIERS,
258 COMMON_CREDS_SPECIFIERS(u->manager->runtime_scope),
260 COMMON_TMP_SPECIFIERS,
264 return specifier_printf(format, max_length, table, NULL, u, ret);