]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/unit-printf.c
a8eb60a3d4264de1f6b464f6ea5db2bda68fa468
[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 == 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 }