chiark / gitweb /
core: fix %h, %s, %p handling in templates in user session
[elogind.git] / src / core / unit-printf.c
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
110         if (u->manager->running_as == SYSTEMD_USER) {
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) {
122         Unit *u = userdata;
123         ExecContext *c;
124         int r;
125         const char *username;
126
127         assert(u);
128
129         c = unit_get_exec_context(u);
130
131         /* get USER env from our own env if set */
132         if (!c || !c->user)
133                 return getusername_malloc();
134
135         /* fish username from passwd */
136         username = c->user;
137         r = get_user_creds(&username, NULL, NULL, NULL, NULL);
138         if (r < 0)
139                 return NULL;
140
141         return strdup(username);
142 }
143
144 static char *specifier_user_home(char specifier, void *data, void *userdata) {
145         Unit *u = userdata;
146         ExecContext *c;
147         int r;
148         const char *username, *home;
149
150         assert(u);
151
152         c = unit_get_exec_context(u);
153
154         /* return HOME if set, otherwise from passwd */
155         if (!c || !c->user) {
156                 char *h;
157
158                 r = get_home_dir(&h);
159                 if (r < 0)
160                         return NULL;
161
162                 return h;
163         }
164
165         username = c->user;
166         r = get_user_creds(&username, NULL, NULL, &home, NULL);
167         if (r < 0)
168                return NULL;
169
170         return strdup(home);
171 }
172
173 static char *specifier_user_shell(char specifier, void *data, void *userdata) {
174         Unit *u = userdata;
175         ExecContext *c;
176         int r;
177         const char *username, *shell;
178
179         assert(u);
180
181         c = unit_get_exec_context(u);
182
183         /* return HOME if set, otherwise from passwd */
184         if (!c || !c->user) {
185                 char *sh;
186
187                 r = get_shell(&sh);
188                 if (r < 0)
189                         return strdup("/bin/sh");
190
191                 return sh;
192         }
193
194         username = c->user;
195         r = get_user_creds(&username, NULL, NULL, NULL, &shell);
196         if (r < 0)
197                 return strdup("/bin/sh");
198
199         return strdup(shell);
200 }
201
202 static char *specifier_machine_id(char specifier, void *data, void *userdata) {
203         sd_id128_t id;
204         char *buf;
205         int r;
206
207         r = sd_id128_get_machine(&id);
208         if (r < 0)
209                 return NULL;
210
211         buf = new(char, 33);
212         if (!buf)
213                 return NULL;
214
215         return sd_id128_to_string(id, buf);
216 }
217
218 static char *specifier_boot_id(char specifier, void *data, void *userdata) {
219         sd_id128_t id;
220         char *buf;
221         int r;
222
223         r = sd_id128_get_boot(&id);
224         if (r < 0)
225                 return NULL;
226
227         buf = new(char, 33);
228         if (!buf)
229                 return NULL;
230
231         return sd_id128_to_string(id, buf);
232 }
233
234 static char *specifier_host_name(char specifier, void *data, void *userdata) {
235         return gethostname_malloc();
236 }
237
238 char *unit_name_printf(Unit *u, const char* format) {
239
240         /*
241          * This will use the passed string as format string and
242          * replace the following specifiers:
243          *
244          * %n: the full id of the unit                 (foo@bar.waldo)
245          * %N: the id of the unit without the suffix   (foo@bar)
246          * %p: the prefix                              (foo)
247          * %i: the instance                            (bar)
248          */
249
250         const Specifier table[] = {
251                 { 'n', specifier_string,              u->id },
252                 { 'N', specifier_prefix_and_instance, NULL },
253                 { 'p', specifier_prefix,              NULL },
254                 { 'i', specifier_string,              u->instance },
255                 { 0, NULL, NULL }
256         };
257
258         assert(u);
259         assert(format);
260
261         return specifier_printf(format, table, u);
262 }
263
264 char *unit_full_printf(Unit *u, const char *format) {
265
266         /* This is similar to unit_name_printf() but also supports
267          * unescaping. Also, adds a couple of additional codes:
268          *
269          * %f the the instance if set, otherwise the id
270          * %c cgroup path of unit
271          * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
272          * %R parent of root cgroup path (e.g. "/usr/lennart/shared")
273          * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
274          * %u the username of the configured user or running user
275          * %h the homedir of the configured user or running user
276          * %s the shell of the configured user or running user
277          * %m the machine ID of the running system
278          * %b the boot ID of the running system
279          * %H the host name of the running system
280          */
281
282         const Specifier table[] = {
283                 { 'n', specifier_string,              u->id },
284                 { 'N', specifier_prefix_and_instance, NULL },
285                 { 'p', specifier_prefix,              NULL },
286                 { 'P', specifier_prefix_unescaped,    NULL },
287                 { 'i', specifier_string,              u->instance },
288                 { 'I', specifier_instance_unescaped,  NULL },
289
290                 { 'f', specifier_filename,            NULL },
291                 { 'c', specifier_cgroup,              NULL },
292                 { 'r', specifier_cgroup_root,         NULL },
293                 { 'R', specifier_cgroup_root,         NULL },
294                 { 't', specifier_runtime,             NULL },
295                 { 'u', specifier_user_name,           NULL },
296                 { 'h', specifier_user_home,           NULL },
297                 { 's', specifier_user_shell,          NULL },
298
299                 { 'm', specifier_machine_id,          NULL },
300                 { 'H', specifier_host_name,           NULL },
301                 { 'b', specifier_boot_id,             NULL },
302                 { 0, NULL, NULL }
303         };
304
305         assert(u);
306         assert(format);
307
308         return specifier_printf(format, table, u);
309 }
310
311 char **unit_full_printf_strv(Unit *u, char **l) {
312         size_t n;
313         char **r, **i, **j;
314
315         /* Applies unit_full_printf to every entry in l */
316
317         assert(u);
318
319         n = strv_length(l);
320         r = new(char*, n+1);
321         if (!r)
322                 return NULL;
323
324         for (i = l, j = r; *i; i++, j++) {
325                 *j = unit_full_printf(u, *i);
326                 if (!*j)
327                         goto fail;
328         }
329
330         *j = NULL;
331         return r;
332
333 fail:
334         for (j--; j >= r; j--)
335                 free(*j);
336
337         free(r);
338
339         return NULL;
340 }