]>
Commit | Line | Data |
---|---|---|
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 | } |