chiark / gitweb /
unit-printf: before resolving exec context specifiers check whether the object actual...
[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 == MANAGER_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         c = unit_get_exec_context(u);
128         if (!c)
129                 return NULL;
130
131         /* get USER env from our own env if set */
132         if (!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         c = unit_get_exec_context(u);
151         if (!c)
152                 return NULL;
153
154         /* return HOME if set, otherwise from passwd */
155         if (!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         c = unit_get_exec_context(u);
180         if (!c)
181                 return NULL;
182
183         /* return HOME if set, otherwise from passwd */
184         if (!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 char *unit_name_printf(Unit *u, const char* format) {
203
204         /*
205          * This will use the passed string as format string and
206          * replace the following specifiers:
207          *
208          * %n: the full id of the unit                 (foo@bar.waldo)
209          * %N: the id of the unit without the suffix   (foo@bar)
210          * %p: the prefix                              (foo)
211          * %i: the instance                            (bar)
212          */
213
214         const Specifier table[] = {
215                 { 'n', specifier_string,              u->id },
216                 { 'N', specifier_prefix_and_instance, NULL },
217                 { 'p', specifier_prefix,              NULL },
218                 { 'i', specifier_string,              u->instance },
219                 { 0, NULL, NULL }
220         };
221
222         assert(u);
223         assert(format);
224
225         return specifier_printf(format, table, u);
226 }
227
228 char *unit_full_printf(Unit *u, const char *format) {
229
230         /* This is similar to unit_name_printf() but also supports
231          * unescaping. Also, adds a couple of additional codes:
232          *
233          * %f the the instance if set, otherwise the id
234          * %c cgroup path of unit
235          * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
236          * %R parent of root cgroup path (e.g. "/usr/lennart/shared")
237          * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
238          * %u the username of the configured user or running user
239          * %h the homedir of the configured user or running user
240          * %s the shell of the configured user or running user
241          */
242
243         const Specifier table[] = {
244                 { 'n', specifier_string,              u->id },
245                 { 'N', specifier_prefix_and_instance, NULL },
246                 { 'p', specifier_prefix,              NULL },
247                 { 'P', specifier_prefix_unescaped,    NULL },
248                 { 'i', specifier_string,              u->instance },
249                 { 'I', specifier_instance_unescaped,  NULL },
250
251                 { 'f', specifier_filename,            NULL },
252                 { 'c', specifier_cgroup,              NULL },
253                 { 'r', specifier_cgroup_root,         NULL },
254                 { 'R', specifier_cgroup_root,         NULL },
255                 { 't', specifier_runtime,             NULL },
256                 { 'u', specifier_user_name,           NULL },
257                 { 'h', specifier_user_home,           NULL },
258                 { 's', specifier_user_shell,          NULL },
259                 { 0, NULL, NULL }
260         };
261
262         assert(u);
263         assert(format);
264
265         return specifier_printf(format, table, u);
266 }
267
268 char **unit_full_printf_strv(Unit *u, char **l) {
269         size_t n;
270         char **r, **i, **j;
271
272         /* Applies unit_full_printf to every entry in l */
273
274         assert(u);
275
276         n = strv_length(l);
277         r = new(char*, n+1);
278         if (!r)
279                 return NULL;
280
281         for (i = l, j = r; *i; i++, j++) {
282                 *j = unit_full_printf(u, *i);
283                 if (!*j)
284                         goto fail;
285         }
286
287         *j = NULL;
288         return r;
289
290 fail:
291         for (j--; j >= r; j--)
292                 free(*j);
293
294         free(r);
295
296         return NULL;
297 }