]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/unit-printf.c
Merge pull request #179 from l10n-tw/master
[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 "unit.h"
23 #include "specifier.h"
24 #include "strv.h"
25 #include "unit-name.h"
26 #include "unit-printf.h"
27 #include "macro.h"
28 #include "cgroup-util.h"
29 #include "formats-util.h"
30
31 static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
32 Unit *u = userdata;
33
34 assert(u);
35
36 return unit_name_to_prefix_and_instance(u->id, ret);
37 }
38
39 static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
40 Unit *u = userdata;
41
42 assert(u);
43
44 return unit_name_to_prefix(u->id, ret);
45 }
46
47 static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
48 _cleanup_free_ char *p = NULL;
49 Unit *u = userdata;
50 int r;
51
52 assert(u);
53
54 r = unit_name_to_prefix(u->id, &p);
55 if (r < 0)
56 return r;
57
58 return unit_name_unescape(p, ret);
59 }
60
61 static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
62 Unit *u = userdata;
63
64 assert(u);
65
66 if (!u->instance)
67 return -EINVAL;
68
69 return unit_name_unescape(u->instance, ret);
70 }
71
72 static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
73 Unit *u = userdata;
74
75 assert(u);
76
77 if (u->instance)
78 return unit_name_path_unescape(u->instance, ret);
79 else
80 return unit_name_to_path(u->id, ret);
81 }
82
83 static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
84 Unit *u = userdata;
85 char *n;
86
87 assert(u);
88
89 if (u->cgroup_path)
90 n = strdup(u->cgroup_path);
91 else
92 n = unit_default_cgroup_path(u);
93 if (!n)
94 return -ENOMEM;
95
96 *ret = n;
97 return 0;
98 }
99
100 static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) {
101 Unit *u = userdata;
102 char *n;
103
104 assert(u);
105
106 n = strdup(u->manager->cgroup_root);
107 if (!n)
108 return -ENOMEM;
109
110 *ret = n;
111 return 0;
112 }
113
114 static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) {
115 Unit *u = userdata;
116 char *n;
117
118 assert(u);
119
120 if (UNIT_ISSET(u->slice)) {
121 Unit *slice;
122
123 slice = UNIT_DEREF(u->slice);
124
125 if (slice->cgroup_path)
126 n = strdup(slice->cgroup_path);
127 else
128 n = unit_default_cgroup_path(slice);
129 } else
130 n = strdup(u->manager->cgroup_root);
131
132 *ret = n;
133 return 0;
134 }
135
136 static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) {
137 Unit *u = userdata;
138 const char *e;
139 char *n = NULL;
140
141 assert(u);
142
143 if (u->manager->running_as == MANAGER_SYSTEM)
144 e = "/run";
145 else {
146 e = getenv("XDG_RUNTIME_DIR");
147 if (!e)
148 return -EOPNOTSUPP;
149 }
150
151 n = strdup(e);
152 if (!n)
153 return -ENOMEM;
154
155 *ret = n;
156 return 0;
157 }
158
159 static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
160 char *printed = NULL;
161 Unit *u = userdata;
162 ExecContext *c;
163 int r = 0;
164
165 assert(u);
166
167 c = unit_get_exec_context(u);
168 if (!c)
169 return -EINVAL;
170
171 if (u->manager->running_as == MANAGER_SYSTEM) {
172
173 /* We cannot use NSS from PID 1, hence try to make the
174 * best of it in that case, and fail if we can't help
175 * it */
176
177 if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
178 printed = strdup(specifier == 'u' ? "root" : "0");
179 else {
180 if (specifier == 'u')
181 printed = strdup(c->user);
182 else {
183 uid_t uid;
184
185 r = parse_uid(c->user, &uid);
186 if (r < 0)
187 return -ENODATA;
188
189 r = asprintf(&printed, UID_FMT, uid);
190 }
191 }
192
193 } else {
194 _cleanup_free_ char *tmp = NULL;
195 const char *username = NULL;
196 uid_t uid;
197
198 if (c->user)
199 username = c->user;
200 else
201 /* get USER env from env or our own uid */
202 username = tmp = getusername_malloc();
203
204 /* fish username from passwd */
205 r = get_user_creds(&username, &uid, NULL, NULL, NULL);
206 if (r < 0)
207 return r;
208
209 if (specifier == 'u')
210 printed = strdup(username);
211 else
212 r = asprintf(&printed, UID_FMT, uid);
213 }
214
215 if (r < 0 || !printed)
216 return -ENOMEM;
217
218 *ret = printed;
219 return 0;
220 }
221
222 static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
223 Unit *u = userdata;
224 ExecContext *c;
225 char *n;
226 int r;
227
228 assert(u);
229
230 c = unit_get_exec_context(u);
231 if (!c)
232 return -EOPNOTSUPP;
233
234 if (u->manager->running_as == MANAGER_SYSTEM) {
235
236 /* We cannot use NSS from PID 1, hence try to make the
237 * best of it if we can, but fail if we can't */
238
239 if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
240 n = strdup("/root");
241 else
242 return -EOPNOTSUPP;
243
244 } else {
245
246 /* return HOME if set, otherwise from passwd */
247 if (!c || !c->user) {
248 r = get_home_dir(&n);
249 if (r < 0)
250 return r;
251 } else {
252 const char *username, *home;
253
254 username = c->user;
255 r = get_user_creds(&username, NULL, NULL, &home, NULL);
256 if (r < 0)
257 return r;
258
259 n = strdup(home);
260 }
261 }
262
263 if (!n)
264 return -ENOMEM;
265
266 *ret = n;
267 return 0;
268 }
269
270 static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
271 Unit *u = userdata;
272 ExecContext *c;
273 char *n;
274 int r;
275
276 assert(u);
277
278 c = unit_get_exec_context(u);
279 if (!c)
280 return -EOPNOTSUPP;
281
282 if (u->manager->running_as == MANAGER_SYSTEM) {
283
284 /* We cannot use NSS from PID 1, hence try to make the
285 * best of it if we can, but fail if we can't */
286
287 if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
288 n = strdup("/bin/sh");
289 else
290 return -EOPNOTSUPP;
291
292 } else {
293
294 /* return /bin/sh for root, otherwise the value from passwd */
295 if (!c->user) {
296 r = get_shell(&n);
297 if (r < 0)
298 return r;
299 } else {
300 const char *username, *shell;
301
302 username = c->user;
303 r = get_user_creds(&username, NULL, NULL, NULL, &shell);
304 if (r < 0)
305 return r;
306
307 n = strdup(shell);
308 }
309 }
310
311 if (!n)
312 return -ENOMEM;
313
314 *ret = n;
315 return 0;
316 }
317
318 int unit_name_printf(Unit *u, const char* format, char **ret) {
319
320 /*
321 * This will use the passed string as format string and
322 * replace the following specifiers:
323 *
324 * %n: the full id of the unit (foo@bar.waldo)
325 * %N: the id of the unit without the suffix (foo@bar)
326 * %p: the prefix (foo)
327 * %i: the instance (bar)
328 */
329
330 const Specifier table[] = {
331 { 'n', specifier_string, u->id },
332 { 'N', specifier_prefix_and_instance, NULL },
333 { 'p', specifier_prefix, NULL },
334 { 'i', specifier_string, u->instance },
335 { 0, NULL, NULL }
336 };
337
338 assert(u);
339 assert(format);
340 assert(ret);
341
342 return specifier_printf(format, table, u, ret);
343 }
344
345 int unit_full_printf(Unit *u, const char *format, char **ret) {
346
347 /* This is similar to unit_name_printf() but also supports
348 * unescaping. Also, adds a couple of additional codes:
349 *
350 * %f the instance if set, otherwise the id
351 * %c cgroup path of unit
352 * %r where units in this slice are placed in the cgroup tree
353 * %R the root of this systemd's instance tree
354 * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
355 * %U the UID of the configured user or running user
356 * %u the username of the configured user or running user
357 * %h the homedir of the configured user or running user
358 * %s the shell of the configured user or running user
359 * %m the machine ID of the running system
360 * %H the host name of the running system
361 * %b the boot ID of the running system
362 * %v `uname -r` of the running system
363 */
364
365 const Specifier table[] = {
366 { 'n', specifier_string, u->id },
367 { 'N', specifier_prefix_and_instance, NULL },
368 { 'p', specifier_prefix, NULL },
369 { 'P', specifier_prefix_unescaped, NULL },
370 { 'i', specifier_string, u->instance },
371 { 'I', specifier_instance_unescaped, NULL },
372
373 { 'f', specifier_filename, NULL },
374 { 'c', specifier_cgroup, NULL },
375 { 'r', specifier_cgroup_slice, NULL },
376 { 'R', specifier_cgroup_root, NULL },
377 { 't', specifier_runtime, NULL },
378 { 'U', specifier_user_name, NULL },
379 { 'u', specifier_user_name, NULL },
380 { 'h', specifier_user_home, NULL },
381 { 's', specifier_user_shell, NULL },
382
383 { 'm', specifier_machine_id, NULL },
384 { 'H', specifier_host_name, NULL },
385 { 'b', specifier_boot_id, NULL },
386 { 'v', specifier_kernel_release, NULL },
387 {}
388 };
389
390 assert(u);
391 assert(format);
392 assert(ret);
393
394 return specifier_printf(format, table, u, ret);
395 }
396
397 int unit_full_printf_strv(Unit *u, char **l, char ***ret) {
398 size_t n;
399 char **r, **i, **j;
400 int q;
401
402 /* Applies unit_full_printf to every entry in l */
403
404 assert(u);
405
406 n = strv_length(l);
407 r = new(char*, n+1);
408 if (!r)
409 return -ENOMEM;
410
411 for (i = l, j = r; *i; i++, j++) {
412 q = unit_full_printf(u, *i, j);
413 if (q < 0)
414 goto fail;
415 }
416
417 *j = NULL;
418 *ret = r;
419 return 0;
420
421 fail:
422 for (j--; j >= r; j--)
423 free(*j);
424
425 free(r);
426 return q;
427 }