]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/unit-printf.c
unit: split unit_printf() and friends into its own .c file
[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 == 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 }