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