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