]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/unit-printf.c
core: resolve more specifiers in unit_name_printf()
[thirdparty/systemd.git] / src / core / unit-printf.c
CommitLineData
41f9172f
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
b5efdb8a 20#include "alloc-util.h"
07630cea 21#include "cgroup-util.h"
f97b34a6 22#include "format-util.h"
07630cea 23#include "macro.h"
41f9172f 24#include "specifier.h"
07630cea 25#include "string-util.h"
41f9172f
LP
26#include "strv.h"
27#include "unit-name.h"
28#include "unit-printf.h"
b1d4f8e1
LP
29#include "unit.h"
30#include "user-util.h"
41f9172f 31
19f6d710 32static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
41f9172f 33 Unit *u = userdata;
19f6d710 34
41f9172f
LP
35 assert(u);
36
7410616c 37 return unit_name_to_prefix_and_instance(u->id, ret);
41f9172f
LP
38}
39
19f6d710 40static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
41f9172f 41 Unit *u = userdata;
19f6d710 42
41f9172f
LP
43 assert(u);
44
7410616c 45 return unit_name_to_prefix(u->id, ret);
41f9172f
LP
46}
47
19f6d710 48static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
19f6d710 49 _cleanup_free_ char *p = NULL;
7410616c
LP
50 Unit *u = userdata;
51 int r;
41f9172f
LP
52
53 assert(u);
54
7410616c
LP
55 r = unit_name_to_prefix(u->id, &p);
56 if (r < 0)
57 return r;
41f9172f 58
7410616c 59 return unit_name_unescape(p, ret);
41f9172f
LP
60}
61
19f6d710 62static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
41f9172f 63 Unit *u = userdata;
19f6d710 64
41f9172f
LP
65 assert(u);
66
115cbf7e 67 return unit_name_unescape(strempty(u->instance), ret);
41f9172f
LP
68}
69
19f6d710 70static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
41f9172f 71 Unit *u = userdata;
19f6d710 72
41f9172f
LP
73 assert(u);
74
75 if (u->instance)
7410616c 76 return unit_name_path_unescape(u->instance, ret);
19f6d710 77 else
7410616c 78 return unit_name_to_path(u->id, ret);
41f9172f
LP
79}
80
19f6d710 81static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
41f9172f 82 Unit *u = userdata;
19f6d710
LP
83 char *n;
84
41f9172f
LP
85 assert(u);
86
2cfbd749
LP
87 if (u->cgroup_path)
88 n = strdup(u->cgroup_path);
89 else
90 n = unit_default_cgroup_path(u);
19f6d710
LP
91 if (!n)
92 return -ENOMEM;
93
94 *ret = n;
95 return 0;
41f9172f
LP
96}
97
19f6d710 98static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) {
41f9172f 99 Unit *u = userdata;
19f6d710 100 char *n;
41f9172f 101
9444b1f2 102 assert(u);
41f9172f 103
696fd1ef
LP
104 n = strdup(u->manager->cgroup_root);
105 if (!n)
106 return -ENOMEM;
41f9172f 107
696fd1ef
LP
108 *ret = n;
109 return 0;
110}
19f6d710 111
696fd1ef
LP
112static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) {
113 Unit *u = userdata;
114 char *n;
115
116 assert(u);
117
118 if (UNIT_ISSET(u->slice)) {
119 Unit *slice;
120
121 slice = UNIT_DEREF(u->slice);
122
123 if (slice->cgroup_path)
124 n = strdup(slice->cgroup_path);
125 else
126 n = unit_default_cgroup_path(slice);
127 } else
128 n = strdup(u->manager->cgroup_root);
115cbf7e
EV
129 if (!n)
130 return -ENOMEM;
41f9172f 131
19f6d710
LP
132 *ret = n;
133 return 0;
41f9172f
LP
134}
135
19f6d710 136static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) {
41f9172f 137 Unit *u = userdata;
2cfbd749 138 const char *e;
19f6d710
LP
139 char *n = NULL;
140
41f9172f
LP
141 assert(u);
142
92dd7c49
LP
143 e = manager_get_runtime_prefix(u->manager);
144 if (!e)
145 return -EOPNOTSUPP;
2cfbd749
LP
146 n = strdup(e);
147 if (!n)
148 return -ENOMEM;
19f6d710
LP
149
150 *ret = n;
151 return 0;
41f9172f
LP
152}
153
19f6d710 154static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
79413b67 155 char *t;
2cfbd749 156
79413b67
LP
157 /* If we are UID 0 (root), this will not result in NSS,
158 * otherwise it might. This is good, as we want to be able to
159 * run this in PID 1, where our user ID is 0, but where NSS
160 * lookups are not allowed. */
067d851d 161
79413b67
LP
162 t = getusername_malloc();
163 if (!t)
19f6d710
LP
164 return -ENOMEM;
165
79413b67 166 *ret = t;
19f6d710 167 return 0;
41f9172f
LP
168}
169
79413b67 170static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
41f9172f 171
79413b67 172 if (asprintf(ret, UID_FMT, getuid()) < 0)
19f6d710
LP
173 return -ENOMEM;
174
19f6d710 175 return 0;
41f9172f
LP
176}
177
79413b67 178static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
2cfbd749 179
79413b67
LP
180 /* On PID 1 (which runs as root) this will not result in NSS,
181 * which is good. See above */
2cfbd749 182
79413b67
LP
183 return get_home_dir(ret);
184}
2cfbd749 185
79413b67 186static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
41f9172f 187
79413b67
LP
188 /* On PID 1 (which runs as root) this will not result in NSS,
189 * which is good. See above */
41f9172f 190
79413b67 191 return get_shell(ret);
41f9172f
LP
192}
193
19f6d710 194int unit_name_printf(Unit *u, const char* format, char **ret) {
41f9172f
LP
195
196 /*
b1801e64
LP
197 * This will use the passed string as format string and replace the following specifiers (which should all be
198 * safe for inclusion in unit names):
41f9172f
LP
199 *
200 * %n: the full id of the unit (foo@bar.waldo)
201 * %N: the id of the unit without the suffix (foo@bar)
202 * %p: the prefix (foo)
203 * %i: the instance (bar)
b1801e64
LP
204 *
205 * %U: the UID of the running user
206 * %u: the username of the running user
207 *
208 * %m: the machine ID of the running system
209 * %H: the host name of the running system
210 * %b: the boot ID of the running system
41f9172f
LP
211 */
212
213 const Specifier table[] = {
214 { 'n', specifier_string, u->id },
215 { 'N', specifier_prefix_and_instance, NULL },
216 { 'p', specifier_prefix, NULL },
217 { 'i', specifier_string, u->instance },
b1801e64
LP
218
219 { 'U', specifier_user_id, NULL },
220 { 'u', specifier_user_name, NULL },
221
222 { 'm', specifier_machine_id, NULL },
223 { 'H', specifier_host_name, NULL },
224 { 'b', specifier_boot_id, NULL },
225 {}
41f9172f
LP
226 };
227
228 assert(u);
229 assert(format);
19f6d710 230 assert(ret);
41f9172f 231
19f6d710 232 return specifier_printf(format, table, u, ret);
41f9172f
LP
233}
234
19f6d710 235int unit_full_printf(Unit *u, const char *format, char **ret) {
41f9172f 236
b1801e64
LP
237 /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of additional codes
238 * (which are likely not suitable for unescaped inclusion in unit names):
239 *
240 * %f: the unescaped instance if set, otherwise the id unescaped as path
241 * %c: cgroup path of unit
242 * %r: where units in this slice are placed in the cgroup tree
243 * %R: the root of this systemd's instance tree
244 * %t: the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
245 *
246 * %h: the homedir of the running user
247 * %s: the shell of the running user
41f9172f 248 *
b1801e64 249 * %v: `uname -r` of the running system
41f9172f
LP
250 */
251
252 const Specifier table[] = {
253 { 'n', specifier_string, u->id },
254 { 'N', specifier_prefix_and_instance, NULL },
255 { 'p', specifier_prefix, NULL },
256 { 'P', specifier_prefix_unescaped, NULL },
257 { 'i', specifier_string, u->instance },
258 { 'I', specifier_instance_unescaped, NULL },
259
260 { 'f', specifier_filename, NULL },
261 { 'c', specifier_cgroup, NULL },
696fd1ef 262 { 'r', specifier_cgroup_slice, NULL },
41f9172f
LP
263 { 'R', specifier_cgroup_root, NULL },
264 { 't', specifier_runtime, NULL },
79413b67
LP
265
266 { 'U', specifier_user_id, NULL },
41f9172f
LP
267 { 'u', specifier_user_name, NULL },
268 { 'h', specifier_user_home, NULL },
269 { 's', specifier_user_shell, NULL },
6569cae1
LP
270
271 { 'm', specifier_machine_id, NULL },
272 { 'H', specifier_host_name, NULL },
273 { 'b', specifier_boot_id, NULL },
6aaa8c2f
ZJS
274 { 'v', specifier_kernel_release, NULL },
275 {}
41f9172f
LP
276 };
277
19f6d710 278 assert(u);
41f9172f 279 assert(format);
19f6d710 280 assert(ret);
41f9172f 281
19f6d710 282 return specifier_printf(format, table, u, ret);
41f9172f
LP
283}
284
19f6d710 285int unit_full_printf_strv(Unit *u, char **l, char ***ret) {
41f9172f
LP
286 size_t n;
287 char **r, **i, **j;
19f6d710 288 int q;
41f9172f
LP
289
290 /* Applies unit_full_printf to every entry in l */
291
292 assert(u);
293
294 n = strv_length(l);
295 r = new(char*, n+1);
296 if (!r)
19f6d710 297 return -ENOMEM;
41f9172f
LP
298
299 for (i = l, j = r; *i; i++, j++) {
19f6d710
LP
300 q = unit_full_printf(u, *i, j);
301 if (q < 0)
41f9172f
LP
302 goto fail;
303 }
304
305 *j = NULL;
19f6d710
LP
306 *ret = r;
307 return 0;
41f9172f
LP
308
309fail:
310 for (j--; j >= r; j--)
311 free(*j);
312
313 free(r);
19f6d710 314 return q;
41f9172f 315}