chiark / gitweb /
automount: log info about triggering process
[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 #include "macro.h"
30 #include "cgroup-util.h"
31 #include "special.h"
32
33 static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
34         Unit *u = userdata;
35         char *n;
36
37         assert(u);
38
39         n = unit_name_to_prefix_and_instance(u->id);
40         if (!n)
41                 return -ENOMEM;
42
43         *ret = n;
44         return 0;
45 }
46
47 static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
48         Unit *u = userdata;
49         char *n;
50
51         assert(u);
52
53         n = unit_name_to_prefix(u->id);
54         if (!n)
55                 return -ENOMEM;
56
57         *ret = n;
58         return 0;
59 }
60
61 static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
62         Unit *u = userdata;
63         _cleanup_free_ char *p = NULL;
64         char *n;
65
66         assert(u);
67
68         p = unit_name_to_prefix(u->id);
69         if (!p)
70                 return -ENOMEM;
71
72         n = unit_name_unescape(p);
73         if (!n)
74                 return -ENOMEM;
75
76         *ret = n;
77         return 0;
78 }
79
80 static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
81         Unit *u = userdata;
82         char *n;
83
84         assert(u);
85
86         if (u->instance)
87                 n = unit_name_unescape(u->instance);
88         else
89                 n = strdup("");
90
91         if (!n)
92                 return -ENOMEM;
93
94         *ret = n;
95         return 0;
96 }
97
98 static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
99         Unit *u = userdata;
100         char *n;
101
102         assert(u);
103
104         if (u->instance)
105                 n = unit_name_path_unescape(u->instance);
106         else
107                 n = unit_name_to_path(u->id);
108
109         if (!n)
110                 return -ENOMEM;
111
112         *ret = n;
113         return 0;
114 }
115
116 static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
117         Unit *u = userdata;
118         char *n;
119
120         assert(u);
121
122         n = unit_default_cgroup_path(u);
123         if (!n)
124                 return -ENOMEM;
125
126         *ret = n;
127         return 0;
128 }
129
130 static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) {
131         Unit *u = userdata;
132         const char *slice;
133         char *n;
134         int r;
135
136         assert(u);
137
138         slice = unit_slice_name(u);
139         if (specifier == 'R' || !slice)
140                 n = strdup(u->manager->cgroup_root);
141         else {
142                 _cleanup_free_ char *p = NULL;
143
144                 r = cg_slice_to_path(slice, &p);
145                 if (r < 0)
146                         return r;
147
148                 n = strjoin(u->manager->cgroup_root, "/", p, NULL);
149                 if (!n)
150                         return -ENOMEM;
151         }
152
153         *ret = n;
154         return 0;
155 }
156
157 static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) {
158         Unit *u = userdata;
159         char *n = NULL;
160
161         assert(u);
162
163         if (u->manager->running_as == SYSTEMD_USER) {
164                 const char *e;
165
166                 e = getenv("XDG_RUNTIME_DIR");
167                 if (e) {
168                         n = strdup(e);
169                         if (!n)
170                                 return -ENOMEM;
171                 }
172         }
173
174         if (!n) {
175                 n = strdup("/run");
176                 if (!n)
177                         return -ENOMEM;
178         }
179
180         *ret = n;
181         return 0;
182 }
183
184 static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
185         Unit *u = userdata;
186         ExecContext *c;
187         int r;
188         const char *username;
189         _cleanup_free_ char *tmp = NULL;
190         uid_t uid;
191         char *printed = NULL;
192
193         assert(u);
194
195         c = unit_get_exec_context(u);
196
197         if (c && c->user)
198                 username = c->user;
199         else
200                 /* get USER env from env or our own uid */
201                 username = tmp = getusername_malloc();
202
203         /* fish username from passwd */
204         r = get_user_creds(&username, &uid, NULL, NULL, NULL);
205         if (r < 0)
206                 return r;
207
208         switch (specifier) {
209                 case 'U':
210                         if (asprintf(&printed, "%d", uid) < 0)
211                                 return -ENOMEM;
212                         break;
213                 case 'u':
214                         printed = strdup(username);
215                         break;
216         }
217
218         if (!printed)
219                 return -ENOMEM;
220
221         *ret = printed;
222         return 0;
223 }
224
225 static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
226         Unit *u = userdata;
227         ExecContext *c;
228         int r;
229         const char *username, *home;
230         char *n;
231
232         assert(u);
233
234         c = unit_get_exec_context(u);
235
236         /* return HOME if set, otherwise from passwd */
237         if (!c || !c->user) {
238                 char *h;
239
240                 r = get_home_dir(&h);
241                 if (r < 0)
242                         return r;
243
244                 *ret = h;
245                 return 0;
246         }
247
248         username = c->user;
249         r = get_user_creds(&username, NULL, NULL, &home, NULL);
250         if (r < 0)
251                return r;
252
253         n = strdup(home);
254         if (!n)
255                 return -ENOMEM;
256
257         *ret = n;
258         return 0;
259 }
260
261 static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
262         Unit *u = userdata;
263         ExecContext *c;
264         int r;
265         const char *username, *shell;
266         char *n;
267
268         assert(u);
269
270         c = unit_get_exec_context(u);
271
272         if (c && c->user)
273                 username = c->user;
274         else
275                 username = "root";
276
277         /* return /bin/sh for root, otherwise the value from passwd */
278         r = get_user_creds(&username, NULL, NULL, NULL, &shell);
279         if (r < 0)
280                 return r;
281
282         n = strdup(shell);
283         if (!n)
284                 return -ENOMEM;
285
286         *ret = n;
287         return 0;
288 }
289
290 int unit_name_printf(Unit *u, const char* format, char **ret) {
291
292         /*
293          * This will use the passed string as format string and
294          * replace the following specifiers:
295          *
296          * %n: the full id of the unit                 (foo@bar.waldo)
297          * %N: the id of the unit without the suffix   (foo@bar)
298          * %p: the prefix                              (foo)
299          * %i: the instance                            (bar)
300          */
301
302         const Specifier table[] = {
303                 { 'n', specifier_string,              u->id },
304                 { 'N', specifier_prefix_and_instance, NULL },
305                 { 'p', specifier_prefix,              NULL },
306                 { 'i', specifier_string,              u->instance },
307                 { 0, NULL, NULL }
308         };
309
310         assert(u);
311         assert(format);
312         assert(ret);
313
314         return specifier_printf(format, table, u, ret);
315 }
316
317 int unit_full_printf(Unit *u, const char *format, char **ret) {
318
319         /* This is similar to unit_name_printf() but also supports
320          * unescaping. Also, adds a couple of additional codes:
321          *
322          * %f the the instance if set, otherwise the id
323          * %c cgroup path of unit
324          * %r where units in this slice are place in the cgroup tree
325          * %R the root of this systemd's instance tree
326          * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
327          * %U the UID of the configured user or running user
328          * %u the username of the configured user or running user
329          * %h the homedir of the configured user or running user
330          * %s the shell of the configured user or running user
331          * %m the machine ID of the running system
332          * %H the host name of the running system
333          * %b the boot ID of the running system
334          * %v `uname -r` of the running system
335          */
336
337         const Specifier table[] = {
338                 { 'n', specifier_string,              u->id },
339                 { 'N', specifier_prefix_and_instance, NULL },
340                 { 'p', specifier_prefix,              NULL },
341                 { 'P', specifier_prefix_unescaped,    NULL },
342                 { 'i', specifier_string,              u->instance },
343                 { 'I', specifier_instance_unescaped,  NULL },
344
345                 { 'f', specifier_filename,            NULL },
346                 { 'c', specifier_cgroup,              NULL },
347                 { 'r', specifier_cgroup_root,         NULL },
348                 { 'R', specifier_cgroup_root,         NULL },
349                 { 't', specifier_runtime,             NULL },
350                 { 'U', specifier_user_name,           NULL },
351                 { 'u', specifier_user_name,           NULL },
352                 { 'h', specifier_user_home,           NULL },
353                 { 's', specifier_user_shell,          NULL },
354
355                 { 'm', specifier_machine_id,          NULL },
356                 { 'H', specifier_host_name,           NULL },
357                 { 'b', specifier_boot_id,             NULL },
358                 { 'v', specifier_kernel_release,      NULL },
359                 {}
360         };
361
362         assert(u);
363         assert(format);
364         assert(ret);
365
366         return specifier_printf(format, table, u, ret);
367 }
368
369 int unit_full_printf_strv(Unit *u, char **l, char ***ret) {
370         size_t n;
371         char **r, **i, **j;
372         int q;
373
374         /* Applies unit_full_printf to every entry in l */
375
376         assert(u);
377
378         n = strv_length(l);
379         r = new(char*, n+1);
380         if (!r)
381                 return -ENOMEM;
382
383         for (i = l, j = r; *i; i++, j++) {
384                 q = unit_full_printf(u, *i, j);
385                 if (q < 0)
386                         goto fail;
387         }
388
389         *j = NULL;
390         *ret = r;
391         return 0;
392
393 fail:
394         for (j--; j >= r; j--)
395                 free(*j);
396
397         free(r);
398         return q;
399 }