]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/unit-printf.c
unit-printf: before resolving exec context specifiers check whether the object actual...
[thirdparty/systemd.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 }