]>
Commit | Line | Data |
---|---|---|
41f9172f LP |
1 | /*** |
2 | This file is part of systemd. | |
3 | ||
4 | Copyright 2010 Lennart Poettering | |
5 | ||
6 | systemd is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU Lesser General Public License as published by | |
8 | the Free Software Foundation; either version 2.1 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | systemd is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public License | |
17 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
18 | ***/ | |
19 | ||
b5efdb8a | 20 | #include "alloc-util.h" |
07630cea | 21 | #include "cgroup-util.h" |
f97b34a6 | 22 | #include "format-util.h" |
07630cea | 23 | #include "macro.h" |
41f9172f | 24 | #include "specifier.h" |
07630cea | 25 | #include "string-util.h" |
41f9172f LP |
26 | #include "strv.h" |
27 | #include "unit-name.h" | |
28 | #include "unit-printf.h" | |
b1d4f8e1 LP |
29 | #include "unit.h" |
30 | #include "user-util.h" | |
41f9172f | 31 | |
19f6d710 | 32 | static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 33 | Unit *u = userdata; |
19f6d710 | 34 | |
41f9172f LP |
35 | assert(u); |
36 | ||
7410616c | 37 | return unit_name_to_prefix_and_instance(u->id, ret); |
41f9172f LP |
38 | } |
39 | ||
19f6d710 | 40 | static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 41 | Unit *u = userdata; |
19f6d710 | 42 | |
41f9172f LP |
43 | assert(u); |
44 | ||
7410616c | 45 | return unit_name_to_prefix(u->id, ret); |
41f9172f LP |
46 | } |
47 | ||
19f6d710 | 48 | static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) { |
19f6d710 | 49 | _cleanup_free_ char *p = NULL; |
7410616c LP |
50 | Unit *u = userdata; |
51 | int r; | |
41f9172f LP |
52 | |
53 | assert(u); | |
54 | ||
7410616c LP |
55 | r = unit_name_to_prefix(u->id, &p); |
56 | if (r < 0) | |
57 | return r; | |
41f9172f | 58 | |
7410616c | 59 | return unit_name_unescape(p, ret); |
41f9172f LP |
60 | } |
61 | ||
19f6d710 | 62 | static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 63 | Unit *u = userdata; |
19f6d710 | 64 | |
41f9172f LP |
65 | assert(u); |
66 | ||
115cbf7e | 67 | return unit_name_unescape(strempty(u->instance), ret); |
41f9172f LP |
68 | } |
69 | ||
19f6d710 | 70 | static int specifier_filename(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 71 | Unit *u = userdata; |
19f6d710 | 72 | |
41f9172f LP |
73 | assert(u); |
74 | ||
75 | if (u->instance) | |
7410616c | 76 | return unit_name_path_unescape(u->instance, ret); |
19f6d710 | 77 | else |
7410616c | 78 | return unit_name_to_path(u->id, ret); |
41f9172f LP |
79 | } |
80 | ||
19f6d710 | 81 | static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 82 | Unit *u = userdata; |
19f6d710 LP |
83 | char *n; |
84 | ||
41f9172f LP |
85 | assert(u); |
86 | ||
2cfbd749 LP |
87 | if (u->cgroup_path) |
88 | n = strdup(u->cgroup_path); | |
89 | else | |
90 | n = unit_default_cgroup_path(u); | |
19f6d710 LP |
91 | if (!n) |
92 | return -ENOMEM; | |
93 | ||
94 | *ret = n; | |
95 | return 0; | |
41f9172f LP |
96 | } |
97 | ||
19f6d710 | 98 | static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 99 | Unit *u = userdata; |
19f6d710 | 100 | char *n; |
41f9172f | 101 | |
9444b1f2 | 102 | assert(u); |
41f9172f | 103 | |
696fd1ef LP |
104 | n = strdup(u->manager->cgroup_root); |
105 | if (!n) | |
106 | return -ENOMEM; | |
41f9172f | 107 | |
696fd1ef LP |
108 | *ret = n; |
109 | return 0; | |
110 | } | |
19f6d710 | 111 | |
696fd1ef LP |
112 | static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) { |
113 | Unit *u = userdata; | |
114 | char *n; | |
115 | ||
116 | assert(u); | |
117 | ||
118 | if (UNIT_ISSET(u->slice)) { | |
119 | Unit *slice; | |
120 | ||
121 | slice = UNIT_DEREF(u->slice); | |
122 | ||
123 | if (slice->cgroup_path) | |
124 | n = strdup(slice->cgroup_path); | |
125 | else | |
126 | n = unit_default_cgroup_path(slice); | |
127 | } else | |
128 | n = strdup(u->manager->cgroup_root); | |
115cbf7e EV |
129 | if (!n) |
130 | return -ENOMEM; | |
41f9172f | 131 | |
19f6d710 LP |
132 | *ret = n; |
133 | return 0; | |
41f9172f LP |
134 | } |
135 | ||
19f6d710 | 136 | static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 137 | Unit *u = userdata; |
2cfbd749 | 138 | const char *e; |
19f6d710 LP |
139 | char *n = NULL; |
140 | ||
41f9172f LP |
141 | assert(u); |
142 | ||
92dd7c49 LP |
143 | e = manager_get_runtime_prefix(u->manager); |
144 | if (!e) | |
145 | return -EOPNOTSUPP; | |
2cfbd749 LP |
146 | n = strdup(e); |
147 | if (!n) | |
148 | return -ENOMEM; | |
19f6d710 LP |
149 | |
150 | *ret = n; | |
151 | return 0; | |
41f9172f LP |
152 | } |
153 | ||
19f6d710 | 154 | static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { |
79413b67 | 155 | char *t; |
2cfbd749 | 156 | |
79413b67 LP |
157 | /* If we are UID 0 (root), this will not result in NSS, |
158 | * otherwise it might. This is good, as we want to be able to | |
159 | * run this in PID 1, where our user ID is 0, but where NSS | |
160 | * lookups are not allowed. */ | |
067d851d | 161 | |
79413b67 LP |
162 | t = getusername_malloc(); |
163 | if (!t) | |
19f6d710 LP |
164 | return -ENOMEM; |
165 | ||
79413b67 | 166 | *ret = t; |
19f6d710 | 167 | return 0; |
41f9172f LP |
168 | } |
169 | ||
79413b67 | 170 | static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 171 | |
79413b67 | 172 | if (asprintf(ret, UID_FMT, getuid()) < 0) |
19f6d710 LP |
173 | return -ENOMEM; |
174 | ||
19f6d710 | 175 | return 0; |
41f9172f LP |
176 | } |
177 | ||
79413b67 | 178 | static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { |
2cfbd749 | 179 | |
79413b67 LP |
180 | /* On PID 1 (which runs as root) this will not result in NSS, |
181 | * which is good. See above */ | |
2cfbd749 | 182 | |
79413b67 LP |
183 | return get_home_dir(ret); |
184 | } | |
2cfbd749 | 185 | |
79413b67 | 186 | static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { |
41f9172f | 187 | |
79413b67 LP |
188 | /* On PID 1 (which runs as root) this will not result in NSS, |
189 | * which is good. See above */ | |
41f9172f | 190 | |
79413b67 | 191 | return get_shell(ret); |
41f9172f LP |
192 | } |
193 | ||
19f6d710 | 194 | int unit_name_printf(Unit *u, const char* format, char **ret) { |
41f9172f LP |
195 | |
196 | /* | |
b1801e64 LP |
197 | * This will use the passed string as format string and replace the following specifiers (which should all be |
198 | * safe for inclusion in unit names): | |
41f9172f LP |
199 | * |
200 | * %n: the full id of the unit (foo@bar.waldo) | |
201 | * %N: the id of the unit without the suffix (foo@bar) | |
202 | * %p: the prefix (foo) | |
203 | * %i: the instance (bar) | |
b1801e64 LP |
204 | * |
205 | * %U: the UID of the running user | |
206 | * %u: the username of the running user | |
207 | * | |
208 | * %m: the machine ID of the running system | |
209 | * %H: the host name of the running system | |
210 | * %b: the boot ID of the running system | |
41f9172f LP |
211 | */ |
212 | ||
213 | const Specifier table[] = { | |
214 | { 'n', specifier_string, u->id }, | |
215 | { 'N', specifier_prefix_and_instance, NULL }, | |
216 | { 'p', specifier_prefix, NULL }, | |
217 | { 'i', specifier_string, u->instance }, | |
b1801e64 LP |
218 | |
219 | { 'U', specifier_user_id, NULL }, | |
220 | { 'u', specifier_user_name, NULL }, | |
221 | ||
222 | { 'm', specifier_machine_id, NULL }, | |
223 | { 'H', specifier_host_name, NULL }, | |
224 | { 'b', specifier_boot_id, NULL }, | |
225 | {} | |
41f9172f LP |
226 | }; |
227 | ||
228 | assert(u); | |
229 | assert(format); | |
19f6d710 | 230 | assert(ret); |
41f9172f | 231 | |
19f6d710 | 232 | return specifier_printf(format, table, u, ret); |
41f9172f LP |
233 | } |
234 | ||
19f6d710 | 235 | int unit_full_printf(Unit *u, const char *format, char **ret) { |
41f9172f | 236 | |
b1801e64 LP |
237 | /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of additional codes |
238 | * (which are likely not suitable for unescaped inclusion in unit names): | |
239 | * | |
240 | * %f: the unescaped instance if set, otherwise the id unescaped as path | |
241 | * %c: cgroup path of unit | |
242 | * %r: where units in this slice are placed in the cgroup tree | |
243 | * %R: the root of this systemd's instance tree | |
244 | * %t: the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) | |
245 | * | |
246 | * %h: the homedir of the running user | |
247 | * %s: the shell of the running user | |
41f9172f | 248 | * |
b1801e64 | 249 | * %v: `uname -r` of the running system |
41f9172f LP |
250 | */ |
251 | ||
252 | const Specifier table[] = { | |
253 | { 'n', specifier_string, u->id }, | |
254 | { 'N', specifier_prefix_and_instance, NULL }, | |
255 | { 'p', specifier_prefix, NULL }, | |
256 | { 'P', specifier_prefix_unescaped, NULL }, | |
257 | { 'i', specifier_string, u->instance }, | |
258 | { 'I', specifier_instance_unescaped, NULL }, | |
259 | ||
260 | { 'f', specifier_filename, NULL }, | |
261 | { 'c', specifier_cgroup, NULL }, | |
696fd1ef | 262 | { 'r', specifier_cgroup_slice, NULL }, |
41f9172f LP |
263 | { 'R', specifier_cgroup_root, NULL }, |
264 | { 't', specifier_runtime, NULL }, | |
79413b67 LP |
265 | |
266 | { 'U', specifier_user_id, NULL }, | |
41f9172f LP |
267 | { 'u', specifier_user_name, NULL }, |
268 | { 'h', specifier_user_home, NULL }, | |
269 | { 's', specifier_user_shell, NULL }, | |
6569cae1 LP |
270 | |
271 | { 'm', specifier_machine_id, NULL }, | |
272 | { 'H', specifier_host_name, NULL }, | |
273 | { 'b', specifier_boot_id, NULL }, | |
6aaa8c2f ZJS |
274 | { 'v', specifier_kernel_release, NULL }, |
275 | {} | |
41f9172f LP |
276 | }; |
277 | ||
19f6d710 | 278 | assert(u); |
41f9172f | 279 | assert(format); |
19f6d710 | 280 | assert(ret); |
41f9172f | 281 | |
19f6d710 | 282 | return specifier_printf(format, table, u, ret); |
41f9172f LP |
283 | } |
284 | ||
19f6d710 | 285 | int unit_full_printf_strv(Unit *u, char **l, char ***ret) { |
41f9172f LP |
286 | size_t n; |
287 | char **r, **i, **j; | |
19f6d710 | 288 | int q; |
41f9172f LP |
289 | |
290 | /* Applies unit_full_printf to every entry in l */ | |
291 | ||
292 | assert(u); | |
293 | ||
294 | n = strv_length(l); | |
295 | r = new(char*, n+1); | |
296 | if (!r) | |
19f6d710 | 297 | return -ENOMEM; |
41f9172f LP |
298 | |
299 | for (i = l, j = r; *i; i++, j++) { | |
19f6d710 LP |
300 | q = unit_full_printf(u, *i, j); |
301 | if (q < 0) | |
41f9172f LP |
302 | goto fail; |
303 | } | |
304 | ||
305 | *j = NULL; | |
19f6d710 LP |
306 | *ret = r; |
307 | return 0; | |
41f9172f LP |
308 | |
309 | fail: | |
310 | for (j--; j >= r; j--) | |
311 | free(*j); | |
312 | ||
313 | free(r); | |
19f6d710 | 314 | return q; |
41f9172f | 315 | } |