chiark / gitweb /
Move generic specifier functions to shared
[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 == 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         uid_t uid;
127         char *printed = NULL;
128
129         assert(u);
130
131         c = unit_get_exec_context(u);
132
133         /* get USER env from our own env if set */
134         if (!c || !c->user)
135                 return getusername_malloc();
136
137         /* fish username from passwd */
138         username = c->user;
139         r = get_user_creds(&username, &uid, NULL, NULL, NULL);
140         if (r < 0)
141                 return NULL;
142
143         switch (specifier) {
144                 case 'U':
145                         if (asprintf(&printed, "%d", uid) < 0)
146                                 return NULL;
147                         break;
148                 case 'u':
149                         printed = strdup(username);
150                         break;
151         }
152
153         return printed;
154 }
155
156 static char *specifier_user_home(char specifier, void *data, void *userdata) {
157         Unit *u = userdata;
158         ExecContext *c;
159         int r;
160         const char *username, *home;
161
162         assert(u);
163
164         c = unit_get_exec_context(u);
165
166         /* return HOME if set, otherwise from passwd */
167         if (!c || !c->user) {
168                 char *h;
169
170                 r = get_home_dir(&h);
171                 if (r < 0)
172                         return NULL;
173
174                 return h;
175         }
176
177         username = c->user;
178         r = get_user_creds(&username, NULL, NULL, &home, NULL);
179         if (r < 0)
180                return NULL;
181
182         return strdup(home);
183 }
184
185 static char *specifier_user_shell(char specifier, void *data, void *userdata) {
186         Unit *u = userdata;
187         ExecContext *c;
188         int r;
189         const char *username, *shell;
190
191         assert(u);
192
193         c = unit_get_exec_context(u);
194
195         /* return HOME if set, otherwise from passwd */
196         if (!c || !c->user) {
197                 char *sh;
198
199                 r = get_shell(&sh);
200                 if (r < 0)
201                         return strdup("/bin/sh");
202
203                 return sh;
204         }
205
206         username = c->user;
207         r = get_user_creds(&username, NULL, NULL, NULL, &shell);
208         if (r < 0)
209                 return strdup("/bin/sh");
210
211         return strdup(shell);
212 }
213
214 char *unit_name_printf(Unit *u, const char* format) {
215
216         /*
217          * This will use the passed string as format string and
218          * replace the following specifiers:
219          *
220          * %n: the full id of the unit                 (foo@bar.waldo)
221          * %N: the id of the unit without the suffix   (foo@bar)
222          * %p: the prefix                              (foo)
223          * %i: the instance                            (bar)
224          */
225
226         const Specifier table[] = {
227                 { 'n', specifier_string,              u->id },
228                 { 'N', specifier_prefix_and_instance, NULL },
229                 { 'p', specifier_prefix,              NULL },
230                 { 'i', specifier_string,              u->instance },
231                 { 0, NULL, NULL }
232         };
233
234         assert(u);
235         assert(format);
236
237         return specifier_printf(format, table, u);
238 }
239
240 char *unit_full_printf(Unit *u, const char *format) {
241
242         /* This is similar to unit_name_printf() but also supports
243          * unescaping. Also, adds a couple of additional codes:
244          *
245          * %f the the instance if set, otherwise the id
246          * %c cgroup path of unit
247          * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
248          * %R parent of root cgroup path (e.g. "/usr/lennart/shared")
249          * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
250          * %u the username of the configured user or running user
251          * %h the homedir of the configured user or running user
252          * %s the shell of the configured user or running user
253          * %m the machine ID of the running system
254          * %b the boot ID of the running system
255          * %H the host name of the running system
256          */
257
258         const Specifier table[] = {
259                 { 'n', specifier_string,              u->id },
260                 { 'N', specifier_prefix_and_instance, NULL },
261                 { 'p', specifier_prefix,              NULL },
262                 { 'P', specifier_prefix_unescaped,    NULL },
263                 { 'i', specifier_string,              u->instance },
264                 { 'I', specifier_instance_unescaped,  NULL },
265
266                 { 'f', specifier_filename,            NULL },
267                 { 'c', specifier_cgroup,              NULL },
268                 { 'r', specifier_cgroup_root,         NULL },
269                 { 'R', specifier_cgroup_root,         NULL },
270                 { 't', specifier_runtime,             NULL },
271                 { 'U', specifier_user_name,           NULL },
272                 { 'u', specifier_user_name,           NULL },
273                 { 'h', specifier_user_home,           NULL },
274                 { 's', specifier_user_shell,          NULL },
275
276                 { 'm', specifier_machine_id,          NULL },
277                 { 'H', specifier_host_name,           NULL },
278                 { 'b', specifier_boot_id,             NULL },
279                 { 0, NULL, NULL }
280         };
281
282         assert(u);
283         assert(format);
284
285         return specifier_printf(format, table, u);
286 }
287
288 char **unit_full_printf_strv(Unit *u, char **l) {
289         size_t n;
290         char **r, **i, **j;
291
292         /* Applies unit_full_printf to every entry in l */
293
294         assert(u);
295
296         n = strv_length(l);
297         r = new(char*, n+1);
298         if (!r)
299                 return NULL;
300
301         for (i = l, j = r; *i; i++, j++) {
302                 *j = unit_full_printf(u, *i);
303                 if (!*j)
304                         goto fail;
305         }
306
307         *j = NULL;
308         return r;
309
310 fail:
311         for (j--; j >= r; j--)
312                 free(*j);
313
314         free(r);
315
316         return NULL;
317 }