1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "cgroup-util.h"
5 #include "format-util.h"
8 #include "string-util.h"
10 #include "unit-name.h"
11 #include "unit-printf.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
);
32 r
= unit_name_to_prefix(u
->id
, &p
);
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
;
51 r
= unit_name_to_prefix(u
->id
, &prefix
);
55 dash
= strrchr(prefix
, '-');
57 return specifier_string(specifier
, dash
+ 1, root
, userdata
, ret
);
59 *ret
= TAKE_PTR(prefix
);
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
;
67 r
= specifier_last_component(specifier
, data
, root
, userdata
, &p
);
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
);
78 return unit_name_path_unescape(u
->instance
, ret
);
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
);
95 n
= strdup(u
->cgroup_path
);
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
);
110 bad_specifier(u
, specifier
);
112 n
= strdup(u
->manager
->cgroup_root
);
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
;
124 bad_specifier(u
, specifier
);
126 slice
= UNIT_GET_SLICE(u
);
128 if (slice
->cgroup_path
)
129 n
= strdup(slice
->cgroup_path
);
131 return unit_default_cgroup_path(slice
, ret
);
133 n
= strdup(u
->manager
->cgroup_root
);
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
);
145 n
= strdup(u
->manager
->prefix
[PTR_TO_UINT(data
)]);
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
);
159 d
= strjoin(u
->manager
->prefix
[EXEC_DIRECTORY_RUNTIME
], "/credentials/", u
->id
);
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
),
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.
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
);