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