]>
Commit | Line | Data |
---|---|---|
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 | 17 | static 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 | 23 | static 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 | 29 | static 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 | 41 | static 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 | 47 | static 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 | 65 | static 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 | 76 | static 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 | 85 | static 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 | 89 | static 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 | 97 | static 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 | 105 | static 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 | 117 | static 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 |
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 | ||
cc51085a AV |
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 | ||
a2262bca | 145 | int 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 | 177 | int 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 | |
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 | } |