]>
Commit | Line | Data |
---|---|---|
41f9172f LP |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright 2010 Lennart Poettering | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
9 | under the terms of the GNU Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
22 | #include "systemd/sd-id128.h" | |
23 | #include "unit.h" | |
24 | #include "specifier.h" | |
25 | #include "path-util.h" | |
26 | #include "strv.h" | |
27 | #include "unit-name.h" | |
28 | #include "unit-printf.h" | |
29 | ||
30 | static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) { | |
31 | Unit *u = userdata; | |
32 | assert(u); | |
33 | ||
34 | return unit_name_to_prefix_and_instance(u->id); | |
35 | } | |
36 | ||
37 | static char *specifier_prefix(char specifier, void *data, void *userdata) { | |
38 | Unit *u = userdata; | |
39 | assert(u); | |
40 | ||
41 | return unit_name_to_prefix(u->id); | |
42 | } | |
43 | ||
44 | static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) { | |
45 | Unit *u = userdata; | |
46 | char *p, *r; | |
47 | ||
48 | assert(u); | |
49 | ||
50 | p = unit_name_to_prefix(u->id); | |
51 | if (!p) | |
52 | return NULL; | |
53 | ||
54 | r = unit_name_unescape(p); | |
55 | free(p); | |
56 | ||
57 | return r; | |
58 | } | |
59 | ||
60 | static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) { | |
61 | Unit *u = userdata; | |
62 | assert(u); | |
63 | ||
64 | if (u->instance) | |
65 | return unit_name_unescape(u->instance); | |
66 | ||
67 | return strdup(""); | |
68 | } | |
69 | ||
70 | static char *specifier_filename(char specifier, void *data, void *userdata) { | |
71 | Unit *u = userdata; | |
72 | assert(u); | |
73 | ||
74 | if (u->instance) | |
75 | return unit_name_path_unescape(u->instance); | |
76 | ||
77 | return unit_name_to_path(u->id); | |
78 | } | |
79 | ||
80 | static char *specifier_cgroup(char specifier, void *data, void *userdata) { | |
81 | Unit *u = userdata; | |
82 | assert(u); | |
83 | ||
84 | return unit_default_cgroup_path(u); | |
85 | } | |
86 | ||
87 | static char *specifier_cgroup_root(char specifier, void *data, void *userdata) { | |
88 | Unit *u = userdata; | |
89 | char *p; | |
90 | assert(u); | |
91 | ||
92 | if (specifier == 'r') | |
93 | return strdup(u->manager->cgroup_hierarchy); | |
94 | ||
95 | if (path_get_parent(u->manager->cgroup_hierarchy, &p) < 0) | |
96 | return strdup(""); | |
97 | ||
98 | if (streq(p, "/")) { | |
99 | free(p); | |
100 | return strdup(""); | |
101 | } | |
102 | ||
103 | return p; | |
104 | } | |
105 | ||
106 | static char *specifier_runtime(char specifier, void *data, void *userdata) { | |
107 | Unit *u = userdata; | |
108 | assert(u); | |
109 | ||
67445f4e | 110 | if (u->manager->running_as == SYSTEMD_USER) { |
41f9172f LP |
111 | const char *e; |
112 | ||
113 | e = getenv("XDG_RUNTIME_DIR"); | |
114 | if (e) | |
115 | return strdup(e); | |
116 | } | |
117 | ||
118 | return strdup("/run"); | |
119 | } | |
120 | ||
121 | static char *specifier_user_name(char specifier, void *data, void *userdata) { | |
3ef63c31 LP |
122 | Unit *u = userdata; |
123 | ExecContext *c; | |
41f9172f LP |
124 | int r; |
125 | const char *username; | |
126 | ||
6569cae1 LP |
127 | assert(u); |
128 | ||
3ef63c31 LP |
129 | c = unit_get_exec_context(u); |
130 | if (!c) | |
131 | return NULL; | |
132 | ||
41f9172f | 133 | /* get USER env from our own env if set */ |
3ef63c31 | 134 | if (!c->user) |
41f9172f LP |
135 | return getusername_malloc(); |
136 | ||
137 | /* fish username from passwd */ | |
3ef63c31 | 138 | username = c->user; |
41f9172f LP |
139 | r = get_user_creds(&username, NULL, NULL, NULL, NULL); |
140 | if (r < 0) | |
141 | return NULL; | |
142 | ||
143 | return strdup(username); | |
144 | } | |
145 | ||
146 | static char *specifier_user_home(char specifier, void *data, void *userdata) { | |
3ef63c31 LP |
147 | Unit *u = userdata; |
148 | ExecContext *c; | |
41f9172f LP |
149 | int r; |
150 | const char *username, *home; | |
151 | ||
6569cae1 LP |
152 | assert(u); |
153 | ||
3ef63c31 LP |
154 | c = unit_get_exec_context(u); |
155 | if (!c) | |
156 | return NULL; | |
157 | ||
41f9172f | 158 | /* return HOME if set, otherwise from passwd */ |
3ef63c31 | 159 | if (!c->user) { |
41f9172f LP |
160 | char *h; |
161 | ||
162 | r = get_home_dir(&h); | |
163 | if (r < 0) | |
164 | return NULL; | |
165 | ||
166 | return h; | |
167 | } | |
168 | ||
3ef63c31 | 169 | username = c->user; |
41f9172f LP |
170 | r = get_user_creds(&username, NULL, NULL, &home, NULL); |
171 | if (r < 0) | |
172 | return NULL; | |
173 | ||
174 | return strdup(home); | |
175 | } | |
176 | ||
177 | static char *specifier_user_shell(char specifier, void *data, void *userdata) { | |
3ef63c31 LP |
178 | Unit *u = userdata; |
179 | ExecContext *c; | |
41f9172f LP |
180 | int r; |
181 | const char *username, *shell; | |
182 | ||
6569cae1 LP |
183 | assert(u); |
184 | ||
3ef63c31 LP |
185 | c = unit_get_exec_context(u); |
186 | if (!c) | |
187 | return NULL; | |
188 | ||
41f9172f | 189 | /* return HOME if set, otherwise from passwd */ |
3ef63c31 | 190 | if (!c->user) { |
41f9172f LP |
191 | char *sh; |
192 | ||
193 | r = get_shell(&sh); | |
194 | if (r < 0) | |
195 | return strdup("/bin/sh"); | |
196 | ||
197 | return sh; | |
198 | } | |
199 | ||
3ef63c31 | 200 | username = c->user; |
41f9172f LP |
201 | r = get_user_creds(&username, NULL, NULL, NULL, &shell); |
202 | if (r < 0) | |
203 | return strdup("/bin/sh"); | |
204 | ||
205 | return strdup(shell); | |
206 | } | |
207 | ||
6569cae1 LP |
208 | static char *specifier_machine_id(char specifier, void *data, void *userdata) { |
209 | sd_id128_t id; | |
210 | char *buf; | |
211 | int r; | |
212 | ||
213 | r = sd_id128_get_machine(&id); | |
214 | if (r < 0) | |
215 | return NULL; | |
216 | ||
217 | buf = new(char, 33); | |
218 | if (!buf) | |
219 | return NULL; | |
220 | ||
221 | return sd_id128_to_string(id, buf); | |
222 | } | |
223 | ||
224 | static char *specifier_boot_id(char specifier, void *data, void *userdata) { | |
225 | sd_id128_t id; | |
226 | char *buf; | |
227 | int r; | |
228 | ||
229 | r = sd_id128_get_boot(&id); | |
230 | if (r < 0) | |
231 | return NULL; | |
232 | ||
233 | buf = new(char, 33); | |
234 | if (!buf) | |
235 | return NULL; | |
236 | ||
237 | return sd_id128_to_string(id, buf); | |
238 | } | |
239 | ||
240 | static char *specifier_host_name(char specifier, void *data, void *userdata) { | |
241 | return gethostname_malloc(); | |
242 | } | |
243 | ||
41f9172f LP |
244 | char *unit_name_printf(Unit *u, const char* format) { |
245 | ||
246 | /* | |
247 | * This will use the passed string as format string and | |
248 | * replace the following specifiers: | |
249 | * | |
250 | * %n: the full id of the unit (foo@bar.waldo) | |
251 | * %N: the id of the unit without the suffix (foo@bar) | |
252 | * %p: the prefix (foo) | |
253 | * %i: the instance (bar) | |
254 | */ | |
255 | ||
256 | const Specifier table[] = { | |
257 | { 'n', specifier_string, u->id }, | |
258 | { 'N', specifier_prefix_and_instance, NULL }, | |
259 | { 'p', specifier_prefix, NULL }, | |
260 | { 'i', specifier_string, u->instance }, | |
261 | { 0, NULL, NULL } | |
262 | }; | |
263 | ||
264 | assert(u); | |
265 | assert(format); | |
266 | ||
267 | return specifier_printf(format, table, u); | |
268 | } | |
269 | ||
270 | char *unit_full_printf(Unit *u, const char *format) { | |
271 | ||
272 | /* This is similar to unit_name_printf() but also supports | |
273 | * unescaping. Also, adds a couple of additional codes: | |
274 | * | |
275 | * %f the the instance if set, otherwise the id | |
276 | * %c cgroup path of unit | |
277 | * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711") | |
278 | * %R parent of root cgroup path (e.g. "/usr/lennart/shared") | |
279 | * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) | |
280 | * %u the username of the configured user or running user | |
281 | * %h the homedir of the configured user or running user | |
282 | * %s the shell of the configured user or running user | |
6569cae1 LP |
283 | * %m the machine ID of the running system |
284 | * %b the boot ID of the running system | |
285 | * %H the host name of the running system | |
41f9172f LP |
286 | */ |
287 | ||
288 | const Specifier table[] = { | |
289 | { 'n', specifier_string, u->id }, | |
290 | { 'N', specifier_prefix_and_instance, NULL }, | |
291 | { 'p', specifier_prefix, NULL }, | |
292 | { 'P', specifier_prefix_unescaped, NULL }, | |
293 | { 'i', specifier_string, u->instance }, | |
294 | { 'I', specifier_instance_unescaped, NULL }, | |
295 | ||
296 | { 'f', specifier_filename, NULL }, | |
297 | { 'c', specifier_cgroup, NULL }, | |
298 | { 'r', specifier_cgroup_root, NULL }, | |
299 | { 'R', specifier_cgroup_root, NULL }, | |
300 | { 't', specifier_runtime, NULL }, | |
301 | { 'u', specifier_user_name, NULL }, | |
302 | { 'h', specifier_user_home, NULL }, | |
303 | { 's', specifier_user_shell, NULL }, | |
6569cae1 LP |
304 | |
305 | { 'm', specifier_machine_id, NULL }, | |
306 | { 'H', specifier_host_name, NULL }, | |
307 | { 'b', specifier_boot_id, NULL }, | |
41f9172f LP |
308 | { 0, NULL, NULL } |
309 | }; | |
310 | ||
311 | assert(u); | |
312 | assert(format); | |
313 | ||
314 | return specifier_printf(format, table, u); | |
315 | } | |
316 | ||
317 | char **unit_full_printf_strv(Unit *u, char **l) { | |
318 | size_t n; | |
319 | char **r, **i, **j; | |
320 | ||
321 | /* Applies unit_full_printf to every entry in l */ | |
322 | ||
323 | assert(u); | |
324 | ||
325 | n = strv_length(l); | |
326 | r = new(char*, n+1); | |
327 | if (!r) | |
328 | return NULL; | |
329 | ||
330 | for (i = l, j = r; *i; i++, j++) { | |
331 | *j = unit_full_printf(u, *i); | |
332 | if (!*j) | |
333 | goto fail; | |
334 | } | |
335 | ||
336 | *j = NULL; | |
337 | return r; | |
338 | ||
339 | fail: | |
340 | for (j--; j >= r; j--) | |
341 | free(*j); | |
342 | ||
343 | free(r); | |
344 | ||
345 | return NULL; | |
346 | } |