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