Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : : /***
3 : : Copyright © 2012 Holger Hans Peter Freyther
4 : : ***/
5 : :
6 : : #include <errno.h>
7 : : #include <fcntl.h>
8 : : #include <linux/fs.h>
9 : : #include <linux/oom.h>
10 : : #if HAVE_SECCOMP
11 : : #include <seccomp.h>
12 : : #endif
13 : : #include <sched.h>
14 : : #include <string.h>
15 : : #include <sys/resource.h>
16 : : #include <sys/stat.h>
17 : :
18 : : #include "af-list.h"
19 : : #include "alloc-util.h"
20 : : #include "all-units.h"
21 : : #include "bpf-firewall.h"
22 : : #include "bus-error.h"
23 : : #include "bus-internal.h"
24 : : #include "bus-util.h"
25 : : #include "cap-list.h"
26 : : #include "capability-util.h"
27 : : #include "cgroup.h"
28 : : #include "conf-parser.h"
29 : : #include "cpu-set-util.h"
30 : : #include "env-util.h"
31 : : #include "errno-list.h"
32 : : #include "escape.h"
33 : : #include "fd-util.h"
34 : : #include "fs-util.h"
35 : : #include "hexdecoct.h"
36 : : #include "io-util.h"
37 : : #include "ioprio.h"
38 : : #include "ip-protocol-list.h"
39 : : #include "journal-util.h"
40 : : #include "limits-util.h"
41 : : #include "load-fragment.h"
42 : : #include "log.h"
43 : : #include "missing.h"
44 : : #include "mountpoint-util.h"
45 : : #include "nulstr-util.h"
46 : : #include "parse-util.h"
47 : : #include "path-util.h"
48 : : #include "process-util.h"
49 : : #if HAVE_SECCOMP
50 : : #include "seccomp-util.h"
51 : : #endif
52 : : #include "securebits-util.h"
53 : : #include "signal-util.h"
54 : : #include "stat-util.h"
55 : : #include "string-util.h"
56 : : #include "strv.h"
57 : : #include "unit-name.h"
58 : : #include "unit-printf.h"
59 : : #include "user-util.h"
60 : : #include "time-util.h"
61 : : #include "web-util.h"
62 : :
63 : 0 : static int parse_socket_protocol(const char *s) {
64 : : int r;
65 : :
66 : 0 : r = parse_ip_protocol(s);
67 [ # # ]: 0 : if (r < 0)
68 : 0 : return r;
69 [ # # # # ]: 0 : if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP))
70 : 0 : return -EPROTONOSUPPORT;
71 : :
72 : 0 : return r;
73 : : }
74 : :
75 : 0 : int parse_crash_chvt(const char *value, int *data) {
76 : : int b;
77 : :
78 [ # # ]: 0 : if (safe_atoi(value, data) >= 0)
79 : 0 : return 0;
80 : :
81 : 0 : b = parse_boolean(value);
82 [ # # ]: 0 : if (b < 0)
83 : 0 : return b;
84 : :
85 [ # # ]: 0 : if (b > 0)
86 : 0 : *data = 0; /* switch to where kmsg goes */
87 : : else
88 : 0 : *data = -1; /* turn off switching */
89 : :
90 : 0 : return 0;
91 : : }
92 : :
93 : 0 : int parse_confirm_spawn(const char *value, char **console) {
94 : : char *s;
95 : : int r;
96 : :
97 [ # # ]: 0 : r = value ? parse_boolean(value) : 1;
98 [ # # ]: 0 : if (r == 0) {
99 : 0 : *console = NULL;
100 : 0 : return 0;
101 [ # # ]: 0 : } else if (r > 0) /* on with default tty */
102 : 0 : s = strdup("/dev/console");
103 [ # # ]: 0 : else if (is_path(value)) /* on with fully qualified path */
104 : 0 : s = strdup(value);
105 : : else /* on with only a tty file name, not a fully qualified path */
106 : 0 : s = path_join("/dev/", value);
107 [ # # ]: 0 : if (!s)
108 : 0 : return -ENOMEM;
109 : :
110 : 0 : *console = s;
111 : 0 : return 0;
112 : : }
113 : :
114 [ # # # # : 0 : DEFINE_CONFIG_PARSE(config_parse_socket_protocol, parse_socket_protocol, "Failed to parse socket protocol");
# # # # #
# # # ]
115 [ # # # # : 0 : DEFINE_CONFIG_PARSE(config_parse_exec_secure_bits, secure_bits_from_string, "Failed to parse secure bits");
# # # # #
# # # ]
116 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode");
# # # # #
# # # ]
117 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
# # # # #
# # # ]
118 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
# # # # #
# # # ]
119 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
# # # # #
# # # ]
120 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
# # # # #
# # # ]
121 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
# # # # #
# # # ]
122 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
# # # # #
# # # ]
123 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_home, protect_home, ProtectHome, "Failed to parse protect home value");
# # # # #
# # # ]
124 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSystem, "Failed to parse protect system value");
# # # # #
# # # ]
125 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
# # # # #
# # # ]
126 [ - + - + : 68 : DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
- + - + -
+ # # ]
127 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
# # # # #
# # # ]
128 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
# # # # #
# # # ]
129 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
# # # # #
# # # ]
130 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
# # # # #
# # # #
# ]
131 [ # # # # : 0 : DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
# # # # #
# # # ]
132 [ - + - + : 8 : DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
- + - + -
+ # # ]
133 [ - + - + : 4 : DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
- + - + -
+ # # ]
134 [ # # # # : 0 : DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
# # # # #
# # # ]
135 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
# # # # #
# # # #
# ]
136 : :
137 : 396 : int config_parse_unit_deps(
138 : : const char *unit,
139 : : const char *filename,
140 : : unsigned line,
141 : : const char *section,
142 : : unsigned section_line,
143 : : const char *lvalue,
144 : : int ltype,
145 : : const char *rvalue,
146 : : void *data,
147 : : void *userdata) {
148 : :
149 : 396 : UnitDependency d = ltype;
150 : 396 : Unit *u = userdata;
151 : : const char *p;
152 : :
153 [ - + ]: 396 : assert(filename);
154 [ - + ]: 396 : assert(lvalue);
155 [ - + ]: 396 : assert(rvalue);
156 : :
157 : 396 : p = rvalue;
158 : 928 : for (;;) {
159 [ + + - - : 1720 : _cleanup_free_ char *word = NULL, *k = NULL;
+ + - - ]
160 : : int r;
161 : :
162 : 1324 : r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
163 [ + + ]: 1324 : if (r == 0)
164 : 396 : break;
165 [ - + ]: 928 : if (r == -ENOMEM)
166 : 0 : return log_oom();
167 [ - + ]: 928 : if (r < 0) {
168 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
169 : 0 : break;
170 : : }
171 : :
172 : 928 : r = unit_name_printf(u, word, &k);
173 [ - + ]: 928 : if (r < 0) {
174 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
175 : 0 : continue;
176 : : }
177 : :
178 : 928 : r = unit_add_dependency_by_name(u, d, k, true, UNIT_DEPENDENCY_FILE);
179 [ - + ]: 928 : if (r < 0)
180 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
181 : : }
182 : :
183 : 396 : return 0;
184 : : }
185 : :
186 : 0 : int config_parse_obsolete_unit_deps(
187 : : const char *unit,
188 : : const char *filename,
189 : : unsigned line,
190 : : const char *section,
191 : : unsigned section_line,
192 : : const char *lvalue,
193 : : int ltype,
194 : : const char *rvalue,
195 : : void *data,
196 : : void *userdata) {
197 : :
198 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
199 : : "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
200 : :
201 : 0 : return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
202 : : }
203 : :
204 : 356 : int config_parse_unit_string_printf(
205 : : const char *unit,
206 : : const char *filename,
207 : : unsigned line,
208 : : const char *section,
209 : : unsigned section_line,
210 : : const char *lvalue,
211 : : int ltype,
212 : : const char *rvalue,
213 : : void *data,
214 : : void *userdata) {
215 : :
216 : 356 : _cleanup_free_ char *k = NULL;
217 : 356 : Unit *u = userdata;
218 : : int r;
219 : :
220 [ - + ]: 356 : assert(filename);
221 [ - + ]: 356 : assert(lvalue);
222 [ - + ]: 356 : assert(rvalue);
223 [ - + ]: 356 : assert(u);
224 : :
225 : 356 : r = unit_full_printf(u, rvalue, &k);
226 [ - + ]: 356 : if (r < 0) {
227 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
228 : 0 : return 0;
229 : : }
230 : :
231 : 356 : return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
232 : : }
233 : :
234 : 176 : int config_parse_unit_strv_printf(
235 : : const char *unit,
236 : : const char *filename,
237 : : unsigned line,
238 : : const char *section,
239 : : unsigned section_line,
240 : : const char *lvalue,
241 : : int ltype,
242 : : const char *rvalue,
243 : : void *data,
244 : : void *userdata) {
245 : :
246 : 176 : Unit *u = userdata;
247 : 176 : _cleanup_free_ char *k = NULL;
248 : : int r;
249 : :
250 [ - + ]: 176 : assert(filename);
251 [ - + ]: 176 : assert(lvalue);
252 [ - + ]: 176 : assert(rvalue);
253 [ - + ]: 176 : assert(u);
254 : :
255 : 176 : r = unit_full_printf(u, rvalue, &k);
256 [ - + ]: 176 : if (r < 0) {
257 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
258 : 0 : return 0;
259 : : }
260 : :
261 : 176 : return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
262 : : }
263 : :
264 : 0 : int config_parse_unit_path_printf(
265 : : const char *unit,
266 : : const char *filename,
267 : : unsigned line,
268 : : const char *section,
269 : : unsigned section_line,
270 : : const char *lvalue,
271 : : int ltype,
272 : : const char *rvalue,
273 : : void *data,
274 : : void *userdata) {
275 : :
276 : 0 : _cleanup_free_ char *k = NULL;
277 : 0 : Unit *u = userdata;
278 : : int r;
279 : 0 : bool fatal = ltype;
280 : :
281 [ # # ]: 0 : assert(filename);
282 [ # # ]: 0 : assert(lvalue);
283 [ # # ]: 0 : assert(rvalue);
284 [ # # ]: 0 : assert(u);
285 : :
286 : : /* Let's not bother with anything that is too long */
287 [ # # ]: 0 : if (strlen(rvalue) >= PATH_MAX) {
288 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
289 : : "%s value too long%s.",
290 : : lvalue, fatal ? "" : ", ignoring");
291 [ # # ]: 0 : return fatal ? -ENAMETOOLONG : 0;
292 : : }
293 : :
294 : 0 : r = unit_full_printf(u, rvalue, &k);
295 [ # # ]: 0 : if (r < 0) {
296 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
297 : : "Failed to resolve unit specifiers in '%s'%s: %m",
298 : : rvalue, fatal ? "" : ", ignoring");
299 [ # # ]: 0 : return fatal ? -ENOEXEC : 0;
300 : : }
301 : :
302 : 0 : return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
303 : : }
304 : :
305 : 0 : int config_parse_unit_path_strv_printf(
306 : : const char *unit,
307 : : const char *filename,
308 : : unsigned line,
309 : : const char *section,
310 : : unsigned section_line,
311 : : const char *lvalue,
312 : : int ltype,
313 : : const char *rvalue,
314 : : void *data,
315 : : void *userdata) {
316 : :
317 : 0 : char ***x = data;
318 : 0 : Unit *u = userdata;
319 : : int r;
320 : : const char *p;
321 : :
322 [ # # ]: 0 : assert(filename);
323 [ # # ]: 0 : assert(lvalue);
324 [ # # ]: 0 : assert(rvalue);
325 [ # # ]: 0 : assert(u);
326 : :
327 [ # # ]: 0 : if (isempty(rvalue)) {
328 : 0 : *x = strv_free(*x);
329 : 0 : return 0;
330 : : }
331 : :
332 : 0 : for (p = rvalue;;) {
333 [ # # # # ]: 0 : _cleanup_free_ char *word = NULL, *k = NULL;
334 : :
335 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
336 [ # # ]: 0 : if (r == 0)
337 : 0 : return 0;
338 [ # # ]: 0 : if (r == -ENOMEM)
339 : 0 : return log_oom();
340 [ # # ]: 0 : if (r < 0) {
341 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
342 : : "Invalid syntax, ignoring: %s", rvalue);
343 : 0 : return 0;
344 : : }
345 : :
346 : 0 : r = unit_full_printf(u, word, &k);
347 [ # # ]: 0 : if (r < 0) {
348 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
349 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
350 : 0 : return 0;
351 : : }
352 : :
353 : 0 : r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
354 [ # # ]: 0 : if (r < 0)
355 : 0 : return 0;
356 : :
357 : 0 : r = strv_consume(x, TAKE_PTR(k));
358 [ # # ]: 0 : if (r < 0)
359 : 0 : return log_oom();
360 : : }
361 : : }
362 : :
363 : 0 : static int patch_var_run(
364 : : const char *unit,
365 : : const char *filename,
366 : : unsigned line,
367 : : const char *lvalue,
368 : : char **path) {
369 : :
370 : : const char *e;
371 : : char *z;
372 : :
373 : 0 : e = path_startswith(*path, "/var/run/");
374 [ # # ]: 0 : if (!e)
375 : 0 : return 0;
376 : :
377 : 0 : z = path_join("/run/", e);
378 [ # # ]: 0 : if (!z)
379 : 0 : return log_oom();
380 : :
381 [ # # ]: 0 : log_syntax(unit, LOG_NOTICE, filename, line, 0,
382 : : "%s= references a path below legacy directory /var/run/, updating %s → %s; "
383 : : "please update the unit file accordingly.", lvalue, *path, z);
384 : :
385 : 0 : free_and_replace(*path, z);
386 : :
387 : 0 : return 1;
388 : : }
389 : :
390 : 0 : int config_parse_socket_listen(
391 : : const char *unit,
392 : : const char *filename,
393 : : unsigned line,
394 : : const char *section,
395 : : unsigned section_line,
396 : : const char *lvalue,
397 : : int ltype,
398 : : const char *rvalue,
399 : : void *data,
400 : : void *userdata) {
401 : :
402 : 0 : _cleanup_free_ SocketPort *p = NULL;
403 : : SocketPort *tail;
404 : : Socket *s;
405 : : int r;
406 : :
407 [ # # ]: 0 : assert(filename);
408 [ # # ]: 0 : assert(lvalue);
409 [ # # ]: 0 : assert(rvalue);
410 [ # # ]: 0 : assert(data);
411 : :
412 : 0 : s = SOCKET(data);
413 : :
414 [ # # ]: 0 : if (isempty(rvalue)) {
415 : : /* An empty assignment removes all ports */
416 : 0 : socket_free_ports(s);
417 : 0 : return 0;
418 : : }
419 : :
420 : 0 : p = new0(SocketPort, 1);
421 [ # # ]: 0 : if (!p)
422 : 0 : return log_oom();
423 : :
424 [ # # ]: 0 : if (ltype != SOCKET_SOCKET) {
425 [ # # ]: 0 : _cleanup_free_ char *k = NULL;
426 : :
427 [ # # ]: 0 : r = unit_full_printf(UNIT(s), rvalue, &k);
428 [ # # ]: 0 : if (r < 0) {
429 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
430 : 0 : return 0;
431 : : }
432 : :
433 : 0 : r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
434 [ # # ]: 0 : if (r < 0)
435 : 0 : return 0;
436 : :
437 [ # # ]: 0 : if (ltype == SOCKET_FIFO) {
438 : 0 : r = patch_var_run(unit, filename, line, lvalue, &k);
439 [ # # ]: 0 : if (r < 0)
440 : 0 : return r;
441 : : }
442 : :
443 : 0 : free_and_replace(p->path, k);
444 : 0 : p->type = ltype;
445 : :
446 [ # # ]: 0 : } else if (streq(lvalue, "ListenNetlink")) {
447 [ # # ]: 0 : _cleanup_free_ char *k = NULL;
448 : :
449 [ # # ]: 0 : r = unit_full_printf(UNIT(s), rvalue, &k);
450 [ # # ]: 0 : if (r < 0) {
451 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
452 : 0 : return 0;
453 : : }
454 : :
455 : 0 : r = socket_address_parse_netlink(&p->address, k);
456 [ # # ]: 0 : if (r < 0) {
457 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
458 : 0 : return 0;
459 : : }
460 : :
461 : 0 : p->type = SOCKET_SOCKET;
462 : :
463 : : } else {
464 [ # # ]: 0 : _cleanup_free_ char *k = NULL;
465 : :
466 [ # # ]: 0 : r = unit_full_printf(UNIT(s), rvalue, &k);
467 [ # # ]: 0 : if (r < 0) {
468 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
469 : 0 : return 0;
470 : : }
471 : :
472 [ # # ]: 0 : if (k[0] == '/') { /* Only for AF_UNIX file system sockets… */
473 : 0 : r = patch_var_run(unit, filename, line, lvalue, &k);
474 [ # # ]: 0 : if (r < 0)
475 : 0 : return r;
476 : : }
477 : :
478 : 0 : r = socket_address_parse_and_warn(&p->address, k);
479 [ # # ]: 0 : if (r < 0) {
480 [ # # ]: 0 : if (r != -EAFNOSUPPORT)
481 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
482 : 0 : return 0;
483 : : }
484 : :
485 [ # # ]: 0 : if (streq(lvalue, "ListenStream"))
486 : 0 : p->address.type = SOCK_STREAM;
487 [ # # ]: 0 : else if (streq(lvalue, "ListenDatagram"))
488 : 0 : p->address.type = SOCK_DGRAM;
489 : : else {
490 [ # # ]: 0 : assert(streq(lvalue, "ListenSequentialPacket"));
491 : 0 : p->address.type = SOCK_SEQPACKET;
492 : : }
493 : :
494 [ # # # # ]: 0 : if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
495 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
496 : 0 : return 0;
497 : : }
498 : :
499 : 0 : p->type = SOCKET_SOCKET;
500 : : }
501 : :
502 : 0 : p->fd = -1;
503 : 0 : p->auxiliary_fds = NULL;
504 : 0 : p->n_auxiliary_fds = 0;
505 : 0 : p->socket = s;
506 : :
507 [ # # # # ]: 0 : LIST_FIND_TAIL(port, s->ports, tail);
508 [ # # # # : 0 : LIST_INSERT_AFTER(port, s->ports, tail, p);
# # # # ]
509 : :
510 : 0 : p = NULL;
511 : :
512 : 0 : return 0;
513 : : }
514 : :
515 : 0 : int config_parse_exec_nice(
516 : : const char *unit,
517 : : const char *filename,
518 : : unsigned line,
519 : : const char *section,
520 : : unsigned section_line,
521 : : const char *lvalue,
522 : : int ltype,
523 : : const char *rvalue,
524 : : void *data,
525 : : void *userdata) {
526 : :
527 : 0 : ExecContext *c = data;
528 : : int priority, r;
529 : :
530 [ # # ]: 0 : assert(filename);
531 [ # # ]: 0 : assert(lvalue);
532 [ # # ]: 0 : assert(rvalue);
533 [ # # ]: 0 : assert(data);
534 : :
535 [ # # ]: 0 : if (isempty(rvalue)) {
536 : 0 : c->nice_set = false;
537 : 0 : return 0;
538 : : }
539 : :
540 : 0 : r = parse_nice(rvalue, &priority);
541 [ # # ]: 0 : if (r < 0) {
542 [ # # ]: 0 : if (r == -ERANGE)
543 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
544 : : else
545 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority '%s', ignoring: %m", rvalue);
546 : 0 : return 0;
547 : : }
548 : :
549 : 0 : c->nice = priority;
550 : 0 : c->nice_set = true;
551 : :
552 : 0 : return 0;
553 : : }
554 : :
555 : 0 : int config_parse_exec_oom_score_adjust(
556 : : const char* unit,
557 : : const char *filename,
558 : : unsigned line,
559 : : const char *section,
560 : : unsigned section_line,
561 : : const char *lvalue,
562 : : int ltype,
563 : : const char *rvalue,
564 : : void *data,
565 : : void *userdata) {
566 : :
567 : 0 : ExecContext *c = data;
568 : : int oa, r;
569 : :
570 [ # # ]: 0 : assert(filename);
571 [ # # ]: 0 : assert(lvalue);
572 [ # # ]: 0 : assert(rvalue);
573 [ # # ]: 0 : assert(data);
574 : :
575 [ # # ]: 0 : if (isempty(rvalue)) {
576 : 0 : c->oom_score_adjust_set = false;
577 : 0 : return 0;
578 : : }
579 : :
580 : 0 : r = parse_oom_score_adjust(rvalue, &oa);
581 [ # # ]: 0 : if (r < 0) {
582 [ # # ]: 0 : if (r == -ERANGE)
583 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
584 : : else
585 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value '%s', ignoring: %m", rvalue);
586 : 0 : return 0;
587 : : }
588 : :
589 : 0 : c->oom_score_adjust = oa;
590 : 0 : c->oom_score_adjust_set = true;
591 : :
592 : 0 : return 0;
593 : : }
594 : :
595 : 312 : int config_parse_exec(
596 : : const char *unit,
597 : : const char *filename,
598 : : unsigned line,
599 : : const char *section,
600 : : unsigned section_line,
601 : : const char *lvalue,
602 : : int ltype,
603 : : const char *rvalue,
604 : : void *data,
605 : : void *userdata) {
606 : :
607 : 312 : ExecCommand **e = data;
608 : 312 : Unit *u = userdata;
609 : : const char *p;
610 : : bool semicolon;
611 : : int r;
612 : :
613 [ - + ]: 312 : assert(filename);
614 [ - + ]: 312 : assert(lvalue);
615 [ - + ]: 312 : assert(rvalue);
616 [ - + ]: 312 : assert(e);
617 : :
618 : 312 : e += ltype;
619 : 312 : rvalue += strspn(rvalue, WHITESPACE);
620 : :
621 [ + + ]: 312 : if (isempty(rvalue)) {
622 : : /* An empty assignment resets the list */
623 : 8 : *e = exec_command_free_list(*e);
624 : 8 : return 0;
625 : : }
626 : :
627 : 304 : p = rvalue;
628 : : do {
629 [ + + + + ]: 412 : _cleanup_free_ char *path = NULL, *firstword = NULL;
630 : 320 : ExecCommandFlags flags = 0;
631 : 320 : bool ignore = false, separate_argv0 = false;
632 [ + + ]: 320 : _cleanup_free_ ExecCommand *nce = NULL;
633 [ + + ]: 320 : _cleanup_strv_free_ char **n = NULL;
634 : 320 : size_t nlen = 0, nbufsize = 0;
635 : : const char *f;
636 : :
637 : 320 : semicolon = false;
638 : :
639 : 320 : r = extract_first_word_and_warn(&p, &firstword, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
640 [ + + ]: 320 : if (r <= 0)
641 : 8 : return 0;
642 : :
643 : 312 : f = firstword;
644 : : for (;;) {
645 : : /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
646 : : * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
647 : : * argv[0]; if it's prefixed with :, we will not do environment variable substitution;
648 : : * if it's prefixed with +, it will be run with full privileges and no sandboxing; if
649 : : * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
650 : : * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
651 : : * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
652 : : * other sandboxing, with some special exceptions for changing UID.
653 : : *
654 : : * The idea is that '!!' may be used to write services that can take benefit of systemd's
655 : : * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
656 : : * privilege dropping within the daemon if the kernel does not offer that. */
657 : :
658 [ + + + + ]: 396 : if (*f == '-' && !(flags & EXEC_COMMAND_IGNORE_FAILURE)) {
659 : 44 : flags |= EXEC_COMMAND_IGNORE_FAILURE;
660 : 44 : ignore = true;
661 [ + + + - ]: 352 : } else if (*f == '@' && !separate_argv0)
662 : 40 : separate_argv0 = true;
663 [ - + # # ]: 312 : else if (*f == ':' && !(flags & EXEC_COMMAND_NO_ENV_EXPAND))
664 : 0 : flags |= EXEC_COMMAND_NO_ENV_EXPAND;
665 [ - + # # ]: 312 : else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
666 : 0 : flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
667 [ - + # # ]: 312 : else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
668 : 0 : flags |= EXEC_COMMAND_NO_SETUID;
669 [ - + # # ]: 312 : else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))) {
670 : 0 : flags &= ~EXEC_COMMAND_NO_SETUID;
671 : 0 : flags |= EXEC_COMMAND_AMBIENT_MAGIC;
672 : : } else
673 : : break;
674 : 84 : f++;
675 : : }
676 : :
677 : 312 : r = unit_full_printf(u, f, &path);
678 [ - + ]: 312 : if (r < 0) {
679 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
680 : : "Failed to resolve unit specifiers in '%s'%s: %m",
681 : : f, ignore ? ", ignoring" : "");
682 [ # # ]: 0 : return ignore ? 0 : -ENOEXEC;
683 : : }
684 : :
685 [ + + ]: 312 : if (isempty(path)) {
686 : : /* First word is either "-" or "@" with no command. */
687 [ + - + - ]: 8 : log_syntax(unit, LOG_ERR, filename, line, 0,
688 : : "Empty path in command line%s: '%s'",
689 : : ignore ? ", ignoring" : "", rvalue);
690 [ + - ]: 8 : return ignore ? 0 : -ENOEXEC;
691 : : }
692 [ + + ]: 304 : if (!string_is_safe(path)) {
693 [ + - - + ]: 48 : log_syntax(unit, LOG_ERR, filename, line, 0,
694 : : "Executable name contains special characters%s: %s",
695 : : ignore ? ", ignoring" : "", path);
696 [ - + ]: 48 : return ignore ? 0 : -ENOEXEC;
697 : : }
698 [ + + ]: 256 : if (endswith(path, "/")) {
699 [ + - - + ]: 4 : log_syntax(unit, LOG_ERR, filename, line, 0,
700 : : "Executable path specifies a directory%s: %s",
701 : : ignore ? ", ignoring" : "", path);
702 [ - + ]: 4 : return ignore ? 0 : -ENOEXEC;
703 : : }
704 : :
705 [ + + ]: 252 : if (!path_is_absolute(path)) {
706 : : const char *prefix;
707 : 12 : bool found = false;
708 : :
709 [ + + ]: 12 : if (!filename_is_valid(path)) {
710 [ + - + - ]: 8 : log_syntax(unit, LOG_ERR, filename, line, 0,
711 : : "Neither a valid executable name nor an absolute path%s: %s",
712 : : ignore ? ", ignoring" : "", path);
713 [ + - ]: 8 : return ignore ? 0 : -ENOEXEC;
714 : : }
715 : :
716 : : /* Resolve a single-component name to a full path */
717 [ + - + + ]: 20 : NULSTR_FOREACH(prefix, DEFAULT_PATH_NULSTR) {
718 [ + - - ]: 16 : _cleanup_free_ char *fullpath = NULL;
719 : :
720 : 16 : fullpath = path_join(prefix, path);
721 [ - + ]: 16 : if (!fullpath)
722 : 0 : return log_oom();
723 : :
724 [ - + ]: 16 : if (access(fullpath, F_OK) >= 0) {
725 : 0 : free_and_replace(path, fullpath);
726 : 0 : found = true;
727 : 0 : break;
728 : : }
729 : : }
730 : :
731 [ + - ]: 4 : if (!found) {
732 [ + - - + ]: 4 : log_syntax(unit, LOG_ERR, filename, line, 0,
733 : : "Executable \"%s\" not found in path \"%s\"%s",
734 : : path, DEFAULT_PATH, ignore ? ", ignoring" : "");
735 [ - + ]: 4 : return ignore ? 0 : -ENOEXEC;
736 : : }
737 : : }
738 : :
739 [ + + ]: 240 : if (!separate_argv0) {
740 : 204 : char *w = NULL;
741 : :
742 [ - + ]: 204 : if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
743 : 0 : return log_oom();
744 : :
745 : 204 : w = strdup(path);
746 [ - + ]: 204 : if (!w)
747 : 0 : return log_oom();
748 : 204 : n[nlen++] = w;
749 : 204 : n[nlen] = NULL;
750 : : }
751 : :
752 : 240 : path_simplify(path, false);
753 : :
754 [ + + ]: 380 : while (!isempty(p)) {
755 [ + + + + : 196 : _cleanup_free_ char *word = NULL, *resolved = NULL;
+ + + + ]
756 : :
757 : : /* Check explicitly for an unquoted semicolon as
758 : : * command separator token. */
759 [ + + + + : 164 : if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
+ - ]
760 : 16 : p++;
761 : 16 : p += strspn(p, WHITESPACE);
762 : 16 : semicolon = true;
763 : 16 : break;
764 : : }
765 : :
766 : : /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
767 : : * extract_first_word() would return the same for all of those. */
768 [ + + + + : 148 : if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
+ + + + ]
769 : : char *w;
770 : :
771 : 8 : p += 2;
772 : 8 : p += strspn(p, WHITESPACE);
773 : :
774 [ - + ]: 8 : if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
775 : 0 : return log_oom();
776 : :
777 : 8 : w = strdup(";");
778 [ - + ]: 8 : if (!w)
779 : 0 : return log_oom();
780 : 8 : n[nlen++] = w;
781 : 8 : n[nlen] = NULL;
782 : 8 : continue;
783 : : }
784 : :
785 : 140 : r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
786 [ - + ]: 140 : if (r == 0)
787 : 0 : break;
788 [ + + ]: 140 : if (r < 0)
789 [ - + ]: 8 : return ignore ? 0 : -ENOEXEC;
790 : :
791 : 132 : r = unit_full_printf(u, word, &resolved);
792 [ - + ]: 132 : if (r < 0) {
793 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
794 : : "Failed to resolve unit specifiers in %s%s: %m",
795 : : word, ignore ? ", ignoring" : "");
796 [ # # ]: 0 : return ignore ? 0 : -ENOEXEC;
797 : : }
798 : :
799 [ - + ]: 132 : if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
800 : 0 : return log_oom();
801 : :
802 : 132 : n[nlen++] = TAKE_PTR(resolved);
803 : 132 : n[nlen] = NULL;
804 : : }
805 : :
806 [ + + - + ]: 232 : if (!n || !n[0]) {
807 [ + - - + ]: 4 : log_syntax(unit, LOG_ERR, filename, line, 0,
808 : : "Empty executable name or zeroeth argument%s: %s",
809 : : ignore ? ", ignoring" : "", rvalue);
810 [ - + ]: 4 : return ignore ? 0 : -ENOEXEC;
811 : : }
812 : :
813 : 228 : nce = new0(ExecCommand, 1);
814 [ - + ]: 228 : if (!nce)
815 : 0 : return log_oom();
816 : :
817 : 228 : nce->argv = TAKE_PTR(n);
818 : 228 : nce->path = TAKE_PTR(path);
819 : 228 : nce->flags = flags;
820 : :
821 : 228 : exec_command_append_list(e, nce);
822 : :
823 : : /* Do not _cleanup_free_ these. */
824 : 228 : nce = NULL;
825 : :
826 : 228 : rvalue = p;
827 [ + + ]: 228 : } while (semicolon);
828 : :
829 : 212 : return 0;
830 : : }
831 : :
832 : 0 : int config_parse_socket_bindtodevice(
833 : : const char* unit,
834 : : const char *filename,
835 : : unsigned line,
836 : : const char *section,
837 : : unsigned section_line,
838 : : const char *lvalue,
839 : : int ltype,
840 : : const char *rvalue,
841 : : void *data,
842 : : void *userdata) {
843 : :
844 : 0 : Socket *s = data;
845 : :
846 [ # # ]: 0 : assert(filename);
847 [ # # ]: 0 : assert(lvalue);
848 [ # # ]: 0 : assert(rvalue);
849 [ # # ]: 0 : assert(data);
850 : :
851 [ # # # # ]: 0 : if (isempty(rvalue) || streq(rvalue, "*")) {
852 : 0 : s->bind_to_device = mfree(s->bind_to_device);
853 : 0 : return 0;
854 : : }
855 : :
856 [ # # ]: 0 : if (!ifname_valid(rvalue)) {
857 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid interface name, ignoring: %s", rvalue);
858 : 0 : return 0;
859 : : }
860 : :
861 [ # # ]: 0 : if (free_and_strdup(&s->bind_to_device, rvalue) < 0)
862 : 0 : return log_oom();
863 : :
864 : 0 : return 0;
865 : : }
866 : :
867 : 0 : int config_parse_exec_input(
868 : : const char *unit,
869 : : const char *filename,
870 : : unsigned line,
871 : : const char *section,
872 : : unsigned section_line,
873 : : const char *lvalue,
874 : : int ltype,
875 : : const char *rvalue,
876 : : void *data,
877 : : void *userdata) {
878 : :
879 : 0 : ExecContext *c = data;
880 : 0 : Unit *u = userdata;
881 : : const char *n;
882 : : ExecInput ei;
883 : : int r;
884 : :
885 [ # # ]: 0 : assert(data);
886 [ # # ]: 0 : assert(filename);
887 [ # # ]: 0 : assert(line);
888 [ # # ]: 0 : assert(rvalue);
889 : :
890 : 0 : n = startswith(rvalue, "fd:");
891 [ # # ]: 0 : if (n) {
892 [ # # ]: 0 : _cleanup_free_ char *resolved = NULL;
893 : :
894 : 0 : r = unit_full_printf(u, n, &resolved);
895 [ # # ]: 0 : if (r < 0)
896 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", n);
897 : :
898 [ # # ]: 0 : if (isempty(resolved))
899 : 0 : resolved = mfree(resolved);
900 [ # # ]: 0 : else if (!fdname_is_valid(resolved)) {
901 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
902 : 0 : return -ENOEXEC;
903 : : }
904 : :
905 : 0 : free_and_replace(c->stdio_fdname[STDIN_FILENO], resolved);
906 : :
907 : 0 : ei = EXEC_INPUT_NAMED_FD;
908 : :
909 [ # # ]: 0 : } else if ((n = startswith(rvalue, "file:"))) {
910 [ # # ]: 0 : _cleanup_free_ char *resolved = NULL;
911 : :
912 : 0 : r = unit_full_printf(u, n, &resolved);
913 [ # # ]: 0 : if (r < 0)
914 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", n);
915 : :
916 : 0 : r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
917 [ # # ]: 0 : if (r < 0)
918 : 0 : return -ENOEXEC;
919 : :
920 : 0 : free_and_replace(c->stdio_file[STDIN_FILENO], resolved);
921 : :
922 : 0 : ei = EXEC_INPUT_FILE;
923 : :
924 : : } else {
925 : 0 : ei = exec_input_from_string(rvalue);
926 [ # # ]: 0 : if (ei < 0) {
927 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue);
928 : 0 : return 0;
929 : : }
930 : : }
931 : :
932 : 0 : c->std_input = ei;
933 : 0 : return 0;
934 : : }
935 : :
936 : 0 : int config_parse_exec_input_text(
937 : : const char *unit,
938 : : const char *filename,
939 : : unsigned line,
940 : : const char *section,
941 : : unsigned section_line,
942 : : const char *lvalue,
943 : : int ltype,
944 : : const char *rvalue,
945 : : void *data,
946 : : void *userdata) {
947 : :
948 : 0 : _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
949 : 0 : ExecContext *c = data;
950 : 0 : Unit *u = userdata;
951 : : size_t sz;
952 : : void *p;
953 : : int r;
954 : :
955 [ # # ]: 0 : assert(data);
956 [ # # ]: 0 : assert(filename);
957 [ # # ]: 0 : assert(line);
958 [ # # ]: 0 : assert(rvalue);
959 : :
960 [ # # ]: 0 : if (isempty(rvalue)) {
961 : : /* Reset if the empty string is assigned */
962 : 0 : c->stdin_data = mfree(c->stdin_data);
963 : 0 : c->stdin_data_size = 0;
964 : 0 : return 0;
965 : : }
966 : :
967 : 0 : r = cunescape(rvalue, 0, &unescaped);
968 [ # # ]: 0 : if (r < 0)
969 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode C escaped text '%s': %m", rvalue);
970 : :
971 : 0 : r = unit_full_printf(u, unescaped, &resolved);
972 [ # # ]: 0 : if (r < 0)
973 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", unescaped);
974 : :
975 : 0 : sz = strlen(resolved);
976 [ # # ]: 0 : if (c->stdin_data_size + sz + 1 < c->stdin_data_size || /* check for overflow */
977 [ # # ]: 0 : c->stdin_data_size + sz + 1 > EXEC_STDIN_DATA_MAX) {
978 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c->stdin_data_size + sz, (size_t) EXEC_STDIN_DATA_MAX);
979 : 0 : return -E2BIG;
980 : : }
981 : :
982 : 0 : p = realloc(c->stdin_data, c->stdin_data_size + sz + 1);
983 [ # # ]: 0 : if (!p)
984 : 0 : return log_oom();
985 : :
986 : 0 : *((char*) mempcpy((char*) p + c->stdin_data_size, resolved, sz)) = '\n';
987 : :
988 : 0 : c->stdin_data = p;
989 : 0 : c->stdin_data_size += sz + 1;
990 : :
991 : 0 : return 0;
992 : : }
993 : :
994 : 0 : int config_parse_exec_input_data(
995 : : const char *unit,
996 : : const char *filename,
997 : : unsigned line,
998 : : const char *section,
999 : : unsigned section_line,
1000 : : const char *lvalue,
1001 : : int ltype,
1002 : : const char *rvalue,
1003 : : void *data,
1004 : : void *userdata) {
1005 : :
1006 : 0 : _cleanup_free_ void *p = NULL;
1007 : 0 : ExecContext *c = data;
1008 : : size_t sz;
1009 : : void *q;
1010 : : int r;
1011 : :
1012 [ # # ]: 0 : assert(data);
1013 [ # # ]: 0 : assert(filename);
1014 [ # # ]: 0 : assert(line);
1015 [ # # ]: 0 : assert(rvalue);
1016 : :
1017 [ # # ]: 0 : if (isempty(rvalue)) {
1018 : : /* Reset if the empty string is assigned */
1019 : 0 : c->stdin_data = mfree(c->stdin_data);
1020 : 0 : c->stdin_data_size = 0;
1021 : 0 : return 0;
1022 : : }
1023 : :
1024 : 0 : r = unbase64mem(rvalue, (size_t) -1, &p, &sz);
1025 [ # # ]: 0 : if (r < 0)
1026 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode base64 data, ignoring: %s", rvalue);
1027 : :
1028 [ # # ]: 0 : assert(sz > 0);
1029 : :
1030 [ # # ]: 0 : if (c->stdin_data_size + sz < c->stdin_data_size || /* check for overflow */
1031 [ # # ]: 0 : c->stdin_data_size + sz > EXEC_STDIN_DATA_MAX) {
1032 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c->stdin_data_size + sz, (size_t) EXEC_STDIN_DATA_MAX);
1033 : 0 : return -E2BIG;
1034 : : }
1035 : :
1036 : 0 : q = realloc(c->stdin_data, c->stdin_data_size + sz);
1037 [ # # ]: 0 : if (!q)
1038 : 0 : return log_oom();
1039 : :
1040 : 0 : memcpy((uint8_t*) q + c->stdin_data_size, p, sz);
1041 : :
1042 : 0 : c->stdin_data = q;
1043 : 0 : c->stdin_data_size += sz;
1044 : :
1045 : 0 : return 0;
1046 : : }
1047 : :
1048 : 0 : int config_parse_exec_output(
1049 : : const char *unit,
1050 : : const char *filename,
1051 : : unsigned line,
1052 : : const char *section,
1053 : : unsigned section_line,
1054 : : const char *lvalue,
1055 : : int ltype,
1056 : : const char *rvalue,
1057 : : void *data,
1058 : : void *userdata) {
1059 : :
1060 : 0 : _cleanup_free_ char *resolved = NULL;
1061 : : const char *n;
1062 : 0 : ExecContext *c = data;
1063 : 0 : Unit *u = userdata;
1064 : : ExecOutput eo;
1065 : : int r;
1066 : :
1067 [ # # ]: 0 : assert(data);
1068 [ # # ]: 0 : assert(filename);
1069 [ # # ]: 0 : assert(line);
1070 [ # # ]: 0 : assert(lvalue);
1071 [ # # ]: 0 : assert(rvalue);
1072 : :
1073 : 0 : n = startswith(rvalue, "fd:");
1074 [ # # ]: 0 : if (n) {
1075 : 0 : r = unit_full_printf(u, n, &resolved);
1076 [ # # ]: 0 : if (r < 0)
1077 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
1078 : :
1079 [ # # ]: 0 : if (isempty(resolved))
1080 : 0 : resolved = mfree(resolved);
1081 [ # # ]: 0 : else if (!fdname_is_valid(resolved)) {
1082 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
1083 : 0 : return -ENOEXEC;
1084 : : }
1085 : :
1086 : 0 : eo = EXEC_OUTPUT_NAMED_FD;
1087 : :
1088 [ # # ]: 0 : } else if ((n = startswith(rvalue, "file:"))) {
1089 : :
1090 : 0 : r = unit_full_printf(u, n, &resolved);
1091 [ # # ]: 0 : if (r < 0)
1092 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
1093 : :
1094 : 0 : r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
1095 [ # # ]: 0 : if (r < 0)
1096 : 0 : return -ENOEXEC;
1097 : :
1098 : 0 : eo = EXEC_OUTPUT_FILE;
1099 : :
1100 [ # # ]: 0 : } else if ((n = startswith(rvalue, "append:"))) {
1101 : :
1102 : 0 : r = unit_full_printf(u, n, &resolved);
1103 [ # # ]: 0 : if (r < 0)
1104 [ # # ]: 0 : return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
1105 : :
1106 : 0 : r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
1107 [ # # ]: 0 : if (r < 0)
1108 : 0 : return -ENOEXEC;
1109 : :
1110 : 0 : eo = EXEC_OUTPUT_FILE_APPEND;
1111 : : } else {
1112 : 0 : eo = exec_output_from_string(rvalue);
1113 [ # # ]: 0 : if (eo < 0) {
1114 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue);
1115 : 0 : return 0;
1116 : : }
1117 : : }
1118 : :
1119 [ # # ]: 0 : if (streq(lvalue, "StandardOutput")) {
1120 [ # # ]: 0 : if (eo == EXEC_OUTPUT_NAMED_FD)
1121 : 0 : free_and_replace(c->stdio_fdname[STDOUT_FILENO], resolved);
1122 : : else
1123 : 0 : free_and_replace(c->stdio_file[STDOUT_FILENO], resolved);
1124 : :
1125 : 0 : c->std_output = eo;
1126 : :
1127 : : } else {
1128 [ # # ]: 0 : assert(streq(lvalue, "StandardError"));
1129 : :
1130 [ # # ]: 0 : if (eo == EXEC_OUTPUT_NAMED_FD)
1131 : 0 : free_and_replace(c->stdio_fdname[STDERR_FILENO], resolved);
1132 : : else
1133 : 0 : free_and_replace(c->stdio_file[STDERR_FILENO], resolved);
1134 : :
1135 : 0 : c->std_error = eo;
1136 : : }
1137 : :
1138 : 0 : return 0;
1139 : : }
1140 : :
1141 : 0 : int config_parse_exec_io_class(const char *unit,
1142 : : const char *filename,
1143 : : unsigned line,
1144 : : const char *section,
1145 : : unsigned section_line,
1146 : : const char *lvalue,
1147 : : int ltype,
1148 : : const char *rvalue,
1149 : : void *data,
1150 : : void *userdata) {
1151 : :
1152 : 0 : ExecContext *c = data;
1153 : : int x;
1154 : :
1155 [ # # ]: 0 : assert(filename);
1156 [ # # ]: 0 : assert(lvalue);
1157 [ # # ]: 0 : assert(rvalue);
1158 [ # # ]: 0 : assert(data);
1159 : :
1160 [ # # ]: 0 : if (isempty(rvalue)) {
1161 : 0 : c->ioprio_set = false;
1162 : 0 : c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
1163 : 0 : return 0;
1164 : : }
1165 : :
1166 : 0 : x = ioprio_class_from_string(rvalue);
1167 [ # # ]: 0 : if (x < 0) {
1168 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
1169 : 0 : return 0;
1170 : : }
1171 : :
1172 : 0 : c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
1173 : 0 : c->ioprio_set = true;
1174 : :
1175 : 0 : return 0;
1176 : : }
1177 : :
1178 : 0 : int config_parse_exec_io_priority(const char *unit,
1179 : : const char *filename,
1180 : : unsigned line,
1181 : : const char *section,
1182 : : unsigned section_line,
1183 : : const char *lvalue,
1184 : : int ltype,
1185 : : const char *rvalue,
1186 : : void *data,
1187 : : void *userdata) {
1188 : :
1189 : 0 : ExecContext *c = data;
1190 : : int i, r;
1191 : :
1192 [ # # ]: 0 : assert(filename);
1193 [ # # ]: 0 : assert(lvalue);
1194 [ # # ]: 0 : assert(rvalue);
1195 [ # # ]: 0 : assert(data);
1196 : :
1197 [ # # ]: 0 : if (isempty(rvalue)) {
1198 : 0 : c->ioprio_set = false;
1199 : 0 : c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
1200 : 0 : return 0;
1201 : : }
1202 : :
1203 : 0 : r = ioprio_parse_priority(rvalue, &i);
1204 [ # # ]: 0 : if (r < 0) {
1205 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
1206 : 0 : return 0;
1207 : : }
1208 : :
1209 : 0 : c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
1210 : 0 : c->ioprio_set = true;
1211 : :
1212 : 0 : return 0;
1213 : : }
1214 : :
1215 : 12 : int config_parse_exec_cpu_sched_policy(const char *unit,
1216 : : const char *filename,
1217 : : unsigned line,
1218 : : const char *section,
1219 : : unsigned section_line,
1220 : : const char *lvalue,
1221 : : int ltype,
1222 : : const char *rvalue,
1223 : : void *data,
1224 : : void *userdata) {
1225 : :
1226 : 12 : ExecContext *c = data;
1227 : : int x;
1228 : :
1229 [ - + ]: 12 : assert(filename);
1230 [ - + ]: 12 : assert(lvalue);
1231 [ - + ]: 12 : assert(rvalue);
1232 [ - + ]: 12 : assert(data);
1233 : :
1234 [ - + ]: 12 : if (isempty(rvalue)) {
1235 : 0 : c->cpu_sched_set = false;
1236 : 0 : c->cpu_sched_policy = SCHED_OTHER;
1237 : 0 : c->cpu_sched_priority = 0;
1238 : 0 : return 0;
1239 : : }
1240 : :
1241 : 12 : x = sched_policy_from_string(rvalue);
1242 [ - + ]: 12 : if (x < 0) {
1243 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
1244 : 0 : return 0;
1245 : : }
1246 : :
1247 : 12 : c->cpu_sched_policy = x;
1248 : : /* Moving to or from real-time policy? We need to adjust the priority */
1249 [ + - ]: 12 : c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
1250 : 12 : c->cpu_sched_set = true;
1251 : :
1252 : 12 : return 0;
1253 : : }
1254 : :
1255 : 0 : int config_parse_numa_mask(const char *unit,
1256 : : const char *filename,
1257 : : unsigned line,
1258 : : const char *section,
1259 : : unsigned section_line,
1260 : : const char *lvalue,
1261 : : int ltype,
1262 : : const char *rvalue,
1263 : : void *data,
1264 : : void *userdata) {
1265 : : int r;
1266 : 0 : NUMAPolicy *p = data;
1267 : :
1268 [ # # ]: 0 : assert(filename);
1269 [ # # ]: 0 : assert(lvalue);
1270 [ # # ]: 0 : assert(rvalue);
1271 [ # # ]: 0 : assert(data);
1272 : :
1273 : 0 : r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue);
1274 [ # # ]: 0 : if (r < 0) {
1275 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue);
1276 : 0 : return 0;
1277 : : }
1278 : :
1279 : 0 : return r;
1280 : : }
1281 : :
1282 : 28 : int config_parse_exec_cpu_sched_prio(const char *unit,
1283 : : const char *filename,
1284 : : unsigned line,
1285 : : const char *section,
1286 : : unsigned section_line,
1287 : : const char *lvalue,
1288 : : int ltype,
1289 : : const char *rvalue,
1290 : : void *data,
1291 : : void *userdata) {
1292 : :
1293 : 28 : ExecContext *c = data;
1294 : : int i, min, max, r;
1295 : :
1296 [ - + ]: 28 : assert(filename);
1297 [ - + ]: 28 : assert(lvalue);
1298 [ - + ]: 28 : assert(rvalue);
1299 [ - + ]: 28 : assert(data);
1300 : :
1301 : 28 : r = safe_atoi(rvalue, &i);
1302 [ - + ]: 28 : if (r < 0) {
1303 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling priority, ignoring: %s", rvalue);
1304 : 0 : return 0;
1305 : : }
1306 : :
1307 : : /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1308 : 28 : min = sched_get_priority_min(c->cpu_sched_policy);
1309 : 28 : max = sched_get_priority_max(c->cpu_sched_policy);
1310 : :
1311 [ + + + + ]: 28 : if (i < min || i > max) {
1312 [ + - ]: 12 : log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
1313 : 12 : return 0;
1314 : : }
1315 : :
1316 : 16 : c->cpu_sched_priority = i;
1317 : 16 : c->cpu_sched_set = true;
1318 : :
1319 : 16 : return 0;
1320 : : }
1321 : :
1322 : 0 : int config_parse_exec_cpu_affinity(const char *unit,
1323 : : const char *filename,
1324 : : unsigned line,
1325 : : const char *section,
1326 : : unsigned section_line,
1327 : : const char *lvalue,
1328 : : int ltype,
1329 : : const char *rvalue,
1330 : : void *data,
1331 : : void *userdata) {
1332 : :
1333 : 0 : ExecContext *c = data;
1334 : :
1335 [ # # ]: 0 : assert(filename);
1336 [ # # ]: 0 : assert(lvalue);
1337 [ # # ]: 0 : assert(rvalue);
1338 [ # # ]: 0 : assert(data);
1339 : :
1340 : 0 : return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
1341 : : }
1342 : :
1343 : 24 : int config_parse_capability_set(
1344 : : const char *unit,
1345 : : const char *filename,
1346 : : unsigned line,
1347 : : const char *section,
1348 : : unsigned section_line,
1349 : : const char *lvalue,
1350 : : int ltype,
1351 : : const char *rvalue,
1352 : : void *data,
1353 : : void *userdata) {
1354 : :
1355 : 24 : uint64_t *capability_set = data;
1356 : 24 : uint64_t sum = 0, initial = 0;
1357 : 24 : bool invert = false;
1358 : : int r;
1359 : :
1360 [ - + ]: 24 : assert(filename);
1361 [ - + ]: 24 : assert(lvalue);
1362 [ - + ]: 24 : assert(rvalue);
1363 [ - + ]: 24 : assert(data);
1364 : :
1365 [ + + ]: 24 : if (rvalue[0] == '~') {
1366 : 8 : invert = true;
1367 : 8 : rvalue++;
1368 : : }
1369 : :
1370 [ + - ]: 24 : if (streq(lvalue, "CapabilityBoundingSet"))
1371 : 24 : initial = CAP_ALL; /* initialized to all bits on */
1372 : : /* else "AmbientCapabilities" initialized to all bits off */
1373 : :
1374 : 24 : r = capability_set_from_string(rvalue, &sum);
1375 [ - + ]: 24 : if (r < 0) {
1376 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= specifier '%s', ignoring: %m", lvalue, rvalue);
1377 : 0 : return 0;
1378 : : }
1379 : :
1380 [ + + - + ]: 24 : if (sum == 0 || *capability_set == initial)
1381 : : /* "", "~" or uninitialized data -> replace */
1382 [ + + ]: 8 : *capability_set = invert ? ~sum : sum;
1383 : : else {
1384 : : /* previous data -> merge */
1385 [ + + ]: 16 : if (invert)
1386 : 4 : *capability_set &= ~sum;
1387 : : else
1388 : 12 : *capability_set |= sum;
1389 : : }
1390 : :
1391 : 24 : return 0;
1392 : : }
1393 : :
1394 : 0 : int config_parse_exec_selinux_context(
1395 : : const char *unit,
1396 : : const char *filename,
1397 : : unsigned line,
1398 : : const char *section,
1399 : : unsigned section_line,
1400 : : const char *lvalue,
1401 : : int ltype,
1402 : : const char *rvalue,
1403 : : void *data,
1404 : : void *userdata) {
1405 : :
1406 : 0 : ExecContext *c = data;
1407 : 0 : Unit *u = userdata;
1408 : : bool ignore;
1409 : : char *k;
1410 : : int r;
1411 : :
1412 [ # # ]: 0 : assert(filename);
1413 [ # # ]: 0 : assert(lvalue);
1414 [ # # ]: 0 : assert(rvalue);
1415 [ # # ]: 0 : assert(data);
1416 : :
1417 [ # # ]: 0 : if (isempty(rvalue)) {
1418 : 0 : c->selinux_context = mfree(c->selinux_context);
1419 : 0 : c->selinux_context_ignore = false;
1420 : 0 : return 0;
1421 : : }
1422 : :
1423 [ # # ]: 0 : if (rvalue[0] == '-') {
1424 : 0 : ignore = true;
1425 : 0 : rvalue++;
1426 : : } else
1427 : 0 : ignore = false;
1428 : :
1429 : 0 : r = unit_full_printf(u, rvalue, &k);
1430 [ # # ]: 0 : if (r < 0) {
1431 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1432 : : "Failed to resolve unit specifiers in '%s'%s: %m",
1433 : : rvalue, ignore ? ", ignoring" : "");
1434 [ # # ]: 0 : return ignore ? 0 : -ENOEXEC;
1435 : : }
1436 : :
1437 : 0 : free_and_replace(c->selinux_context, k);
1438 : 0 : c->selinux_context_ignore = ignore;
1439 : :
1440 : 0 : return 0;
1441 : : }
1442 : :
1443 : 0 : int config_parse_exec_apparmor_profile(
1444 : : const char *unit,
1445 : : const char *filename,
1446 : : unsigned line,
1447 : : const char *section,
1448 : : unsigned section_line,
1449 : : const char *lvalue,
1450 : : int ltype,
1451 : : const char *rvalue,
1452 : : void *data,
1453 : : void *userdata) {
1454 : :
1455 : 0 : ExecContext *c = data;
1456 : 0 : Unit *u = userdata;
1457 : : bool ignore;
1458 : : char *k;
1459 : : int r;
1460 : :
1461 [ # # ]: 0 : assert(filename);
1462 [ # # ]: 0 : assert(lvalue);
1463 [ # # ]: 0 : assert(rvalue);
1464 [ # # ]: 0 : assert(data);
1465 : :
1466 [ # # ]: 0 : if (isempty(rvalue)) {
1467 : 0 : c->apparmor_profile = mfree(c->apparmor_profile);
1468 : 0 : c->apparmor_profile_ignore = false;
1469 : 0 : return 0;
1470 : : }
1471 : :
1472 [ # # ]: 0 : if (rvalue[0] == '-') {
1473 : 0 : ignore = true;
1474 : 0 : rvalue++;
1475 : : } else
1476 : 0 : ignore = false;
1477 : :
1478 : 0 : r = unit_full_printf(u, rvalue, &k);
1479 [ # # ]: 0 : if (r < 0) {
1480 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1481 : : "Failed to resolve unit specifiers in '%s'%s: %m",
1482 : : rvalue, ignore ? ", ignoring" : "");
1483 [ # # ]: 0 : return ignore ? 0 : -ENOEXEC;
1484 : : }
1485 : :
1486 : 0 : free_and_replace(c->apparmor_profile, k);
1487 : 0 : c->apparmor_profile_ignore = ignore;
1488 : :
1489 : 0 : return 0;
1490 : : }
1491 : :
1492 : 0 : int config_parse_exec_smack_process_label(
1493 : : const char *unit,
1494 : : const char *filename,
1495 : : unsigned line,
1496 : : const char *section,
1497 : : unsigned section_line,
1498 : : const char *lvalue,
1499 : : int ltype,
1500 : : const char *rvalue,
1501 : : void *data,
1502 : : void *userdata) {
1503 : :
1504 : 0 : ExecContext *c = data;
1505 : 0 : Unit *u = userdata;
1506 : : bool ignore;
1507 : : char *k;
1508 : : int r;
1509 : :
1510 [ # # ]: 0 : assert(filename);
1511 [ # # ]: 0 : assert(lvalue);
1512 [ # # ]: 0 : assert(rvalue);
1513 [ # # ]: 0 : assert(data);
1514 : :
1515 [ # # ]: 0 : if (isempty(rvalue)) {
1516 : 0 : c->smack_process_label = mfree(c->smack_process_label);
1517 : 0 : c->smack_process_label_ignore = false;
1518 : 0 : return 0;
1519 : : }
1520 : :
1521 [ # # ]: 0 : if (rvalue[0] == '-') {
1522 : 0 : ignore = true;
1523 : 0 : rvalue++;
1524 : : } else
1525 : 0 : ignore = false;
1526 : :
1527 : 0 : r = unit_full_printf(u, rvalue, &k);
1528 [ # # ]: 0 : if (r < 0) {
1529 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1530 : : "Failed to resolve unit specifiers in '%s'%s: %m",
1531 : : rvalue, ignore ? ", ignoring" : "");
1532 [ # # ]: 0 : return ignore ? 0 : -ENOEXEC;
1533 : : }
1534 : :
1535 : 0 : free_and_replace(c->smack_process_label, k);
1536 : 0 : c->smack_process_label_ignore = ignore;
1537 : :
1538 : 0 : return 0;
1539 : : }
1540 : :
1541 : 0 : int config_parse_timer(
1542 : : const char *unit,
1543 : : const char *filename,
1544 : : unsigned line,
1545 : : const char *section,
1546 : : unsigned section_line,
1547 : : const char *lvalue,
1548 : : int ltype,
1549 : : const char *rvalue,
1550 : : void *data,
1551 : : void *userdata) {
1552 : :
1553 : 0 : _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
1554 : 0 : _cleanup_free_ char *k = NULL;
1555 : 0 : Unit *u = userdata;
1556 : 0 : Timer *t = data;
1557 : 0 : usec_t usec = 0;
1558 : : TimerValue *v;
1559 : : int r;
1560 : :
1561 [ # # ]: 0 : assert(filename);
1562 [ # # ]: 0 : assert(lvalue);
1563 [ # # ]: 0 : assert(rvalue);
1564 [ # # ]: 0 : assert(data);
1565 : :
1566 [ # # ]: 0 : if (isempty(rvalue)) {
1567 : : /* Empty assignment resets list */
1568 : 0 : timer_free_values(t);
1569 : 0 : return 0;
1570 : : }
1571 : :
1572 : 0 : r = unit_full_printf(u, rvalue, &k);
1573 [ # # ]: 0 : if (r < 0) {
1574 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
1575 : 0 : return 0;
1576 : : }
1577 : :
1578 [ # # ]: 0 : if (ltype == TIMER_CALENDAR) {
1579 : 0 : r = calendar_spec_from_string(k, &c);
1580 [ # # ]: 0 : if (r < 0) {
1581 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse calendar specification, ignoring: %s", k);
1582 : 0 : return 0;
1583 : : }
1584 : : } else {
1585 : 0 : r = parse_sec(k, &usec);
1586 [ # # ]: 0 : if (r < 0) {
1587 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse timer value, ignoring: %s", k);
1588 : 0 : return 0;
1589 : : }
1590 : : }
1591 : :
1592 : 0 : v = new(TimerValue, 1);
1593 [ # # ]: 0 : if (!v)
1594 : 0 : return log_oom();
1595 : :
1596 : 0 : *v = (TimerValue) {
1597 : : .base = ltype,
1598 : : .value = usec,
1599 : 0 : .calendar_spec = TAKE_PTR(c),
1600 : : };
1601 : :
1602 [ # # # # ]: 0 : LIST_PREPEND(value, t->values, v);
1603 : :
1604 : 0 : return 0;
1605 : : }
1606 : :
1607 : 4 : int config_parse_trigger_unit(
1608 : : const char *unit,
1609 : : const char *filename,
1610 : : unsigned line,
1611 : : const char *section,
1612 : : unsigned section_line,
1613 : : const char *lvalue,
1614 : : int ltype,
1615 : : const char *rvalue,
1616 : : void *data,
1617 : : void *userdata) {
1618 : :
1619 : 4 : _cleanup_free_ char *p = NULL;
1620 : 4 : Unit *u = data;
1621 : : UnitType type;
1622 : : int r;
1623 : :
1624 [ - + ]: 4 : assert(filename);
1625 [ - + ]: 4 : assert(lvalue);
1626 [ - + ]: 4 : assert(rvalue);
1627 [ - + ]: 4 : assert(data);
1628 : :
1629 [ - + ]: 4 : if (!hashmap_isempty(u->dependencies[UNIT_TRIGGERS])) {
1630 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
1631 : 0 : return 0;
1632 : : }
1633 : :
1634 : 4 : r = unit_name_printf(u, rvalue, &p);
1635 [ - + ]: 4 : if (r < 0) {
1636 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1637 : 0 : return 0;
1638 : : }
1639 : :
1640 : 4 : type = unit_name_to_type(p);
1641 [ - + ]: 4 : if (type < 0) {
1642 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
1643 : 0 : return 0;
1644 : : }
1645 [ - + ]: 4 : if (unit_has_name(u, p)) {
1646 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Units cannot trigger themselves, ignoring: %s", rvalue);
1647 : 0 : return 0;
1648 : : }
1649 : :
1650 : 4 : r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, true, UNIT_DEPENDENCY_FILE);
1651 [ - + ]: 4 : if (r < 0) {
1652 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
1653 : 0 : return 0;
1654 : : }
1655 : :
1656 : 4 : return 0;
1657 : : }
1658 : :
1659 : 28 : int config_parse_path_spec(const char *unit,
1660 : : const char *filename,
1661 : : unsigned line,
1662 : : const char *section,
1663 : : unsigned section_line,
1664 : : const char *lvalue,
1665 : : int ltype,
1666 : : const char *rvalue,
1667 : : void *data,
1668 : : void *userdata) {
1669 : :
1670 : 28 : Path *p = data;
1671 : : PathSpec *s;
1672 : : PathType b;
1673 : 28 : _cleanup_free_ char *k = NULL;
1674 : : int r;
1675 : :
1676 [ - + ]: 28 : assert(filename);
1677 [ - + ]: 28 : assert(lvalue);
1678 [ - + ]: 28 : assert(rvalue);
1679 [ - + ]: 28 : assert(data);
1680 : :
1681 [ - + ]: 28 : if (isempty(rvalue)) {
1682 : : /* Empty assignment clears list */
1683 : 0 : path_free_specs(p);
1684 : 0 : return 0;
1685 : : }
1686 : :
1687 : 28 : b = path_type_from_string(lvalue);
1688 [ - + ]: 28 : if (b < 0) {
1689 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
1690 : 0 : return 0;
1691 : : }
1692 : :
1693 [ + - ]: 28 : r = unit_full_printf(UNIT(p), rvalue, &k);
1694 [ - + ]: 28 : if (r < 0) {
1695 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1696 : 0 : return 0;
1697 : : }
1698 : :
1699 : 28 : r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
1700 [ - + ]: 28 : if (r < 0)
1701 : 0 : return 0;
1702 : :
1703 : 28 : s = new0(PathSpec, 1);
1704 [ - + ]: 28 : if (!s)
1705 : 0 : return log_oom();
1706 : :
1707 [ + - ]: 28 : s->unit = UNIT(p);
1708 : 28 : s->path = TAKE_PTR(k);
1709 : 28 : s->type = b;
1710 : 28 : s->inotify_fd = -1;
1711 : :
1712 [ - + - + ]: 28 : LIST_PREPEND(spec, p->specs, s);
1713 : :
1714 : 28 : return 0;
1715 : : }
1716 : :
1717 : 0 : int config_parse_socket_service(
1718 : : const char *unit,
1719 : : const char *filename,
1720 : : unsigned line,
1721 : : const char *section,
1722 : : unsigned section_line,
1723 : : const char *lvalue,
1724 : : int ltype,
1725 : : const char *rvalue,
1726 : : void *data,
1727 : : void *userdata) {
1728 : :
1729 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1730 : 0 : _cleanup_free_ char *p = NULL;
1731 : 0 : Socket *s = data;
1732 : : Unit *x;
1733 : : int r;
1734 : :
1735 [ # # ]: 0 : assert(filename);
1736 [ # # ]: 0 : assert(lvalue);
1737 [ # # ]: 0 : assert(rvalue);
1738 [ # # ]: 0 : assert(data);
1739 : :
1740 [ # # ]: 0 : r = unit_name_printf(UNIT(s), rvalue, &p);
1741 [ # # ]: 0 : if (r < 0) {
1742 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
1743 : 0 : return -ENOEXEC;
1744 : : }
1745 : :
1746 [ # # ]: 0 : if (!endswith(p, ".service")) {
1747 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service: %s", rvalue);
1748 : 0 : return -ENOEXEC;
1749 : : }
1750 : :
1751 [ # # ]: 0 : r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1752 [ # # ]: 0 : if (r < 0) {
1753 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s: %s", rvalue, bus_error_message(&error, r));
1754 : 0 : return -ENOEXEC;
1755 : : }
1756 : :
1757 [ # # ]: 0 : unit_ref_set(&s->service, UNIT(s), x);
1758 : :
1759 : 0 : return 0;
1760 : : }
1761 : :
1762 : 0 : int config_parse_fdname(
1763 : : const char *unit,
1764 : : const char *filename,
1765 : : unsigned line,
1766 : : const char *section,
1767 : : unsigned section_line,
1768 : : const char *lvalue,
1769 : : int ltype,
1770 : : const char *rvalue,
1771 : : void *data,
1772 : : void *userdata) {
1773 : :
1774 : 0 : _cleanup_free_ char *p = NULL;
1775 : 0 : Socket *s = data;
1776 : : int r;
1777 : :
1778 [ # # ]: 0 : assert(filename);
1779 [ # # ]: 0 : assert(lvalue);
1780 [ # # ]: 0 : assert(rvalue);
1781 [ # # ]: 0 : assert(data);
1782 : :
1783 [ # # ]: 0 : if (isempty(rvalue)) {
1784 : 0 : s->fdname = mfree(s->fdname);
1785 : 0 : return 0;
1786 : : }
1787 : :
1788 [ # # ]: 0 : r = unit_full_printf(UNIT(s), rvalue, &p);
1789 [ # # ]: 0 : if (r < 0) {
1790 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
1791 : 0 : return 0;
1792 : : }
1793 : :
1794 [ # # ]: 0 : if (!fdname_is_valid(p)) {
1795 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
1796 : 0 : return 0;
1797 : : }
1798 : :
1799 : 0 : return free_and_replace(s->fdname, p);
1800 : : }
1801 : :
1802 : 0 : int config_parse_service_sockets(
1803 : : const char *unit,
1804 : : const char *filename,
1805 : : unsigned line,
1806 : : const char *section,
1807 : : unsigned section_line,
1808 : : const char *lvalue,
1809 : : int ltype,
1810 : : const char *rvalue,
1811 : : void *data,
1812 : : void *userdata) {
1813 : :
1814 : 0 : Service *s = data;
1815 : : const char *p;
1816 : : int r;
1817 : :
1818 [ # # ]: 0 : assert(filename);
1819 [ # # ]: 0 : assert(lvalue);
1820 [ # # ]: 0 : assert(rvalue);
1821 [ # # ]: 0 : assert(data);
1822 : :
1823 : 0 : p = rvalue;
1824 : 0 : for (;;) {
1825 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *k = NULL;
# # # # ]
1826 : :
1827 : 0 : r = extract_first_word(&p, &word, NULL, 0);
1828 [ # # ]: 0 : if (r == 0)
1829 : 0 : break;
1830 [ # # ]: 0 : if (r == -ENOMEM)
1831 : 0 : return log_oom();
1832 [ # # ]: 0 : if (r < 0) {
1833 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
1834 : 0 : break;
1835 : : }
1836 : :
1837 [ # # ]: 0 : r = unit_name_printf(UNIT(s), word, &k);
1838 [ # # ]: 0 : if (r < 0) {
1839 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
1840 : 0 : continue;
1841 : : }
1842 : :
1843 [ # # ]: 0 : if (!endswith(k, ".socket")) {
1844 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
1845 : 0 : continue;
1846 : : }
1847 : :
1848 [ # # ]: 0 : r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, true, UNIT_DEPENDENCY_FILE);
1849 [ # # ]: 0 : if (r < 0)
1850 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1851 : :
1852 [ # # ]: 0 : r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, true, UNIT_DEPENDENCY_FILE);
1853 [ # # ]: 0 : if (r < 0)
1854 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1855 : : }
1856 : :
1857 : 0 : return 0;
1858 : : }
1859 : :
1860 : 0 : int config_parse_bus_name(
1861 : : const char *unit,
1862 : : const char *filename,
1863 : : unsigned line,
1864 : : const char *section,
1865 : : unsigned section_line,
1866 : : const char *lvalue,
1867 : : int ltype,
1868 : : const char *rvalue,
1869 : : void *data,
1870 : : void *userdata) {
1871 : :
1872 : 0 : _cleanup_free_ char *k = NULL;
1873 : 0 : Unit *u = userdata;
1874 : : int r;
1875 : :
1876 [ # # ]: 0 : assert(filename);
1877 [ # # ]: 0 : assert(lvalue);
1878 [ # # ]: 0 : assert(rvalue);
1879 [ # # ]: 0 : assert(u);
1880 : :
1881 : 0 : r = unit_full_printf(u, rvalue, &k);
1882 [ # # ]: 0 : if (r < 0) {
1883 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1884 : 0 : return 0;
1885 : : }
1886 : :
1887 [ # # ]: 0 : if (!service_name_is_valid(k)) {
1888 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name, ignoring: %s", k);
1889 : 0 : return 0;
1890 : : }
1891 : :
1892 : 0 : return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1893 : : }
1894 : :
1895 : 0 : int config_parse_service_timeout(
1896 : : const char *unit,
1897 : : const char *filename,
1898 : : unsigned line,
1899 : : const char *section,
1900 : : unsigned section_line,
1901 : : const char *lvalue,
1902 : : int ltype,
1903 : : const char *rvalue,
1904 : : void *data,
1905 : : void *userdata) {
1906 : :
1907 : 0 : Service *s = userdata;
1908 : : usec_t usec;
1909 : : int r;
1910 : :
1911 [ # # ]: 0 : assert(filename);
1912 [ # # ]: 0 : assert(lvalue);
1913 [ # # ]: 0 : assert(rvalue);
1914 [ # # ]: 0 : assert(s);
1915 : :
1916 : : /* This is called for two cases: TimeoutSec= and TimeoutStartSec=. */
1917 : :
1918 : : /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1919 : : * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1920 : : * all other timeouts. */
1921 : 0 : r = parse_sec_fix_0(rvalue, &usec);
1922 [ # # ]: 0 : if (r < 0) {
1923 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1924 : 0 : return 0;
1925 : : }
1926 : :
1927 : 0 : s->start_timeout_defined = true;
1928 : 0 : s->timeout_start_usec = usec;
1929 : :
1930 [ # # ]: 0 : if (streq(lvalue, "TimeoutSec"))
1931 : 0 : s->timeout_stop_usec = usec;
1932 : :
1933 : 0 : return 0;
1934 : : }
1935 : :
1936 : 0 : int config_parse_service_timeout_abort(
1937 : : const char *unit,
1938 : : const char *filename,
1939 : : unsigned line,
1940 : : const char *section,
1941 : : unsigned section_line,
1942 : : const char *lvalue,
1943 : : int ltype,
1944 : : const char *rvalue,
1945 : : void *data,
1946 : : void *userdata) {
1947 : :
1948 : 0 : Service *s = userdata;
1949 : : int r;
1950 : :
1951 [ # # ]: 0 : assert(filename);
1952 [ # # ]: 0 : assert(lvalue);
1953 [ # # ]: 0 : assert(rvalue);
1954 [ # # ]: 0 : assert(s);
1955 : :
1956 : 0 : rvalue += strspn(rvalue, WHITESPACE);
1957 [ # # ]: 0 : if (isempty(rvalue)) {
1958 : 0 : s->timeout_abort_set = false;
1959 : 0 : return 0;
1960 : : }
1961 : :
1962 : 0 : r = parse_sec(rvalue, &s->timeout_abort_usec);
1963 [ # # ]: 0 : if (r < 0) {
1964 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse TimeoutAbortSec= setting, ignoring: %s", rvalue);
1965 : 0 : return 0;
1966 : : }
1967 : :
1968 : 0 : s->timeout_abort_set = true;
1969 : 0 : return 0;
1970 : : }
1971 : :
1972 : 0 : int config_parse_sec_fix_0(
1973 : : const char *unit,
1974 : : const char *filename,
1975 : : unsigned line,
1976 : : const char *section,
1977 : : unsigned section_line,
1978 : : const char *lvalue,
1979 : : int ltype,
1980 : : const char *rvalue,
1981 : : void *data,
1982 : : void *userdata) {
1983 : :
1984 : 0 : usec_t *usec = data;
1985 : : int r;
1986 : :
1987 [ # # ]: 0 : assert(filename);
1988 [ # # ]: 0 : assert(lvalue);
1989 [ # # ]: 0 : assert(rvalue);
1990 [ # # ]: 0 : assert(usec);
1991 : :
1992 : : /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1993 : : * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1994 : : * timeout. */
1995 : :
1996 : 0 : r = parse_sec_fix_0(rvalue, usec);
1997 [ # # ]: 0 : if (r < 0) {
1998 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1999 : 0 : return 0;
2000 : : }
2001 : :
2002 : 0 : return 0;
2003 : : }
2004 : :
2005 : 0 : int config_parse_user_group(
2006 : : const char *unit,
2007 : : const char *filename,
2008 : : unsigned line,
2009 : : const char *section,
2010 : : unsigned section_line,
2011 : : const char *lvalue,
2012 : : int ltype,
2013 : : const char *rvalue,
2014 : : void *data,
2015 : : void *userdata) {
2016 : :
2017 : 0 : _cleanup_free_ char *k = NULL;
2018 : 0 : char **user = data;
2019 : 0 : Unit *u = userdata;
2020 : : int r;
2021 : :
2022 [ # # ]: 0 : assert(filename);
2023 [ # # ]: 0 : assert(lvalue);
2024 [ # # ]: 0 : assert(rvalue);
2025 [ # # ]: 0 : assert(u);
2026 : :
2027 [ # # ]: 0 : if (isempty(rvalue)) {
2028 : 0 : *user = mfree(*user);
2029 : 0 : return 0;
2030 : : }
2031 : :
2032 : 0 : r = unit_full_printf(u, rvalue, &k);
2033 [ # # ]: 0 : if (r < 0) {
2034 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
2035 : 0 : return -ENOEXEC;
2036 : : }
2037 : :
2038 [ # # ]: 0 : if (!valid_user_group_name_or_id(k)) {
2039 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
2040 : 0 : return -ENOEXEC;
2041 : : }
2042 : :
2043 : 0 : return free_and_replace(*user, k);
2044 : : }
2045 : :
2046 : 0 : int config_parse_user_group_strv(
2047 : : const char *unit,
2048 : : const char *filename,
2049 : : unsigned line,
2050 : : const char *section,
2051 : : unsigned section_line,
2052 : : const char *lvalue,
2053 : : int ltype,
2054 : : const char *rvalue,
2055 : : void *data,
2056 : : void *userdata) {
2057 : :
2058 : 0 : char ***users = data;
2059 : 0 : Unit *u = userdata;
2060 : 0 : const char *p = rvalue;
2061 : : int r;
2062 : :
2063 [ # # ]: 0 : assert(filename);
2064 [ # # ]: 0 : assert(lvalue);
2065 [ # # ]: 0 : assert(rvalue);
2066 [ # # ]: 0 : assert(u);
2067 : :
2068 [ # # ]: 0 : if (isempty(rvalue)) {
2069 : 0 : *users = strv_free(*users);
2070 : 0 : return 0;
2071 : : }
2072 : :
2073 : 0 : for (;;) {
2074 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *k = NULL;
# # ]
2075 : :
2076 : 0 : r = extract_first_word(&p, &word, NULL, 0);
2077 [ # # ]: 0 : if (r == 0)
2078 : 0 : break;
2079 [ # # ]: 0 : if (r == -ENOMEM)
2080 : 0 : return log_oom();
2081 [ # # ]: 0 : if (r < 0) {
2082 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax: %s", rvalue);
2083 : 0 : return -ENOEXEC;
2084 : : }
2085 : :
2086 : 0 : r = unit_full_printf(u, word, &k);
2087 [ # # ]: 0 : if (r < 0) {
2088 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", word);
2089 : 0 : return -ENOEXEC;
2090 : : }
2091 : :
2092 [ # # ]: 0 : if (!valid_user_group_name_or_id(k)) {
2093 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
2094 : 0 : return -ENOEXEC;
2095 : : }
2096 : :
2097 : 0 : r = strv_push(users, k);
2098 [ # # ]: 0 : if (r < 0)
2099 : 0 : return log_oom();
2100 : :
2101 : 0 : k = NULL;
2102 : : }
2103 : :
2104 : 0 : return 0;
2105 : : }
2106 : :
2107 : 0 : int config_parse_working_directory(
2108 : : const char *unit,
2109 : : const char *filename,
2110 : : unsigned line,
2111 : : const char *section,
2112 : : unsigned section_line,
2113 : : const char *lvalue,
2114 : : int ltype,
2115 : : const char *rvalue,
2116 : : void *data,
2117 : : void *userdata) {
2118 : :
2119 : 0 : ExecContext *c = data;
2120 : 0 : Unit *u = userdata;
2121 : : bool missing_ok;
2122 : : int r;
2123 : :
2124 [ # # ]: 0 : assert(filename);
2125 [ # # ]: 0 : assert(lvalue);
2126 [ # # ]: 0 : assert(rvalue);
2127 [ # # ]: 0 : assert(c);
2128 [ # # ]: 0 : assert(u);
2129 : :
2130 [ # # ]: 0 : if (isempty(rvalue)) {
2131 : 0 : c->working_directory_home = false;
2132 : 0 : c->working_directory = mfree(c->working_directory);
2133 : 0 : return 0;
2134 : : }
2135 : :
2136 [ # # ]: 0 : if (rvalue[0] == '-') {
2137 : 0 : missing_ok = true;
2138 : 0 : rvalue++;
2139 : : } else
2140 : 0 : missing_ok = false;
2141 : :
2142 [ # # ]: 0 : if (streq(rvalue, "~")) {
2143 : 0 : c->working_directory_home = true;
2144 : 0 : c->working_directory = mfree(c->working_directory);
2145 : : } else {
2146 [ # # ]: 0 : _cleanup_free_ char *k = NULL;
2147 : :
2148 : 0 : r = unit_full_printf(u, rvalue, &k);
2149 [ # # ]: 0 : if (r < 0) {
2150 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
2151 : : "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2152 : : rvalue, missing_ok ? ", ignoring" : "");
2153 [ # # ]: 0 : return missing_ok ? 0 : -ENOEXEC;
2154 : : }
2155 : :
2156 [ # # ]: 0 : r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE | (missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
2157 [ # # ]: 0 : if (r < 0)
2158 [ # # ]: 0 : return missing_ok ? 0 : -ENOEXEC;
2159 : :
2160 : 0 : c->working_directory_home = false;
2161 : 0 : free_and_replace(c->working_directory, k);
2162 : : }
2163 : :
2164 : 0 : c->working_directory_missing_ok = missing_ok;
2165 : 0 : return 0;
2166 : : }
2167 : :
2168 : 0 : int config_parse_unit_env_file(const char *unit,
2169 : : const char *filename,
2170 : : unsigned line,
2171 : : const char *section,
2172 : : unsigned section_line,
2173 : : const char *lvalue,
2174 : : int ltype,
2175 : : const char *rvalue,
2176 : : void *data,
2177 : : void *userdata) {
2178 : :
2179 : 0 : char ***env = data;
2180 : 0 : Unit *u = userdata;
2181 : 0 : _cleanup_free_ char *n = NULL;
2182 : : int r;
2183 : :
2184 [ # # ]: 0 : assert(filename);
2185 [ # # ]: 0 : assert(lvalue);
2186 [ # # ]: 0 : assert(rvalue);
2187 [ # # ]: 0 : assert(data);
2188 : :
2189 [ # # ]: 0 : if (isempty(rvalue)) {
2190 : : /* Empty assignment frees the list */
2191 : 0 : *env = strv_free(*env);
2192 : 0 : return 0;
2193 : : }
2194 : :
2195 : 0 : r = unit_full_printf(u, rvalue, &n);
2196 [ # # ]: 0 : if (r < 0) {
2197 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
2198 : 0 : return 0;
2199 : : }
2200 : :
2201 [ # # ]: 0 : r = path_simplify_and_warn(n[0] == '-' ? n + 1 : n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
2202 [ # # ]: 0 : if (r < 0)
2203 : 0 : return 0;
2204 : :
2205 : 0 : r = strv_push(env, n);
2206 [ # # ]: 0 : if (r < 0)
2207 : 0 : return log_oom();
2208 : :
2209 : 0 : n = NULL;
2210 : :
2211 : 0 : return 0;
2212 : : }
2213 : :
2214 : 0 : int config_parse_environ(
2215 : : const char *unit,
2216 : : const char *filename,
2217 : : unsigned line,
2218 : : const char *section,
2219 : : unsigned section_line,
2220 : : const char *lvalue,
2221 : : int ltype,
2222 : : const char *rvalue,
2223 : : void *data,
2224 : : void *userdata) {
2225 : :
2226 : 0 : Unit *u = userdata;
2227 : 0 : char ***env = data;
2228 : : const char *p;
2229 : : int r;
2230 : :
2231 [ # # ]: 0 : assert(filename);
2232 [ # # ]: 0 : assert(lvalue);
2233 [ # # ]: 0 : assert(rvalue);
2234 [ # # ]: 0 : assert(data);
2235 : :
2236 [ # # ]: 0 : if (isempty(rvalue)) {
2237 : : /* Empty assignment resets the list */
2238 : 0 : *env = strv_free(*env);
2239 : 0 : return 0;
2240 : : }
2241 : :
2242 : 0 : for (p = rvalue;; ) {
2243 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *k = NULL;
# # ]
2244 : :
2245 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
2246 [ # # ]: 0 : if (r == 0)
2247 : 0 : return 0;
2248 [ # # ]: 0 : if (r == -ENOMEM)
2249 : 0 : return log_oom();
2250 [ # # ]: 0 : if (r < 0) {
2251 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
2252 : : "Invalid syntax, ignoring: %s", rvalue);
2253 : 0 : return 0;
2254 : : }
2255 : :
2256 [ # # ]: 0 : if (u) {
2257 : 0 : r = unit_full_printf(u, word, &k);
2258 [ # # ]: 0 : if (r < 0) {
2259 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
2260 : : "Failed to resolve unit specifiers in %s, ignoring: %m", word);
2261 : 0 : continue;
2262 : : }
2263 : : } else
2264 : 0 : k = TAKE_PTR(word);
2265 : :
2266 [ # # ]: 0 : if (!env_assignment_is_valid(k)) {
2267 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
2268 : : "Invalid environment assignment, ignoring: %s", k);
2269 : 0 : continue;
2270 : : }
2271 : :
2272 : 0 : r = strv_env_replace(env, k);
2273 [ # # ]: 0 : if (r < 0)
2274 : 0 : return log_oom();
2275 : :
2276 : 0 : k = NULL;
2277 : : }
2278 : : }
2279 : :
2280 : 12 : int config_parse_pass_environ(
2281 : : const char *unit,
2282 : : const char *filename,
2283 : : unsigned line,
2284 : : const char *section,
2285 : : unsigned section_line,
2286 : : const char *lvalue,
2287 : : int ltype,
2288 : : const char *rvalue,
2289 : : void *data,
2290 : : void *userdata) {
2291 : :
2292 : 12 : _cleanup_strv_free_ char **n = NULL;
2293 : 12 : size_t nlen = 0, nbufsize = 0;
2294 : 12 : char*** passenv = data;
2295 : 12 : const char *p = rvalue;
2296 : 12 : Unit *u = userdata;
2297 : : int r;
2298 : :
2299 [ - + ]: 12 : assert(filename);
2300 [ - + ]: 12 : assert(lvalue);
2301 [ - + ]: 12 : assert(rvalue);
2302 [ - + ]: 12 : assert(data);
2303 : :
2304 [ + + ]: 12 : if (isempty(rvalue)) {
2305 : : /* Empty assignment resets the list */
2306 : 4 : *passenv = strv_free(*passenv);
2307 : 4 : return 0;
2308 : : }
2309 : :
2310 : 20 : for (;;) {
2311 [ + + - + : 44 : _cleanup_free_ char *word = NULL, *k = NULL;
+ + - + ]
2312 : :
2313 : 28 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2314 [ + + ]: 28 : if (r == 0)
2315 : 4 : break;
2316 [ - + ]: 24 : if (r == -ENOMEM)
2317 : 0 : return log_oom();
2318 [ + + ]: 24 : if (r < 0) {
2319 [ + - ]: 4 : log_syntax(unit, LOG_ERR, filename, line, r,
2320 : : "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
2321 : 4 : break;
2322 : : }
2323 : :
2324 [ - + ]: 20 : if (u) {
2325 : 0 : r = unit_full_printf(u, word, &k);
2326 [ # # ]: 0 : if (r < 0) {
2327 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
2328 : : "Failed to resolve specifiers in %s, ignoring: %m", word);
2329 : 0 : continue;
2330 : : }
2331 : : } else
2332 : 20 : k = TAKE_PTR(word);
2333 : :
2334 [ + + ]: 20 : if (!env_name_is_valid(k)) {
2335 [ + - ]: 8 : log_syntax(unit, LOG_ERR, filename, line, 0,
2336 : : "Invalid environment name for %s, ignoring: %s", lvalue, k);
2337 : 8 : continue;
2338 : : }
2339 : :
2340 [ - + ]: 12 : if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2341 : 0 : return log_oom();
2342 : :
2343 : 12 : n[nlen++] = TAKE_PTR(k);
2344 : 12 : n[nlen] = NULL;
2345 : : }
2346 : :
2347 [ + - ]: 8 : if (n) {
2348 : 8 : r = strv_extend_strv(passenv, n, true);
2349 [ - + ]: 8 : if (r < 0)
2350 : 0 : return r;
2351 : : }
2352 : :
2353 : 8 : return 0;
2354 : : }
2355 : :
2356 : 0 : int config_parse_unset_environ(
2357 : : const char *unit,
2358 : : const char *filename,
2359 : : unsigned line,
2360 : : const char *section,
2361 : : unsigned section_line,
2362 : : const char *lvalue,
2363 : : int ltype,
2364 : : const char *rvalue,
2365 : : void *data,
2366 : : void *userdata) {
2367 : :
2368 : 0 : _cleanup_strv_free_ char **n = NULL;
2369 : 0 : size_t nlen = 0, nbufsize = 0;
2370 : 0 : char*** unsetenv = data;
2371 : 0 : const char *p = rvalue;
2372 : 0 : Unit *u = userdata;
2373 : : int r;
2374 : :
2375 [ # # ]: 0 : assert(filename);
2376 [ # # ]: 0 : assert(lvalue);
2377 [ # # ]: 0 : assert(rvalue);
2378 [ # # ]: 0 : assert(data);
2379 : :
2380 [ # # ]: 0 : if (isempty(rvalue)) {
2381 : : /* Empty assignment resets the list */
2382 : 0 : *unsetenv = strv_free(*unsetenv);
2383 : 0 : return 0;
2384 : : }
2385 : :
2386 : 0 : for (;;) {
2387 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *k = NULL;
# # # # ]
2388 : :
2389 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
2390 [ # # ]: 0 : if (r == 0)
2391 : 0 : break;
2392 [ # # ]: 0 : if (r == -ENOMEM)
2393 : 0 : return log_oom();
2394 [ # # ]: 0 : if (r < 0) {
2395 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
2396 : : "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
2397 : 0 : break;
2398 : : }
2399 : :
2400 [ # # ]: 0 : if (u) {
2401 : 0 : r = unit_full_printf(u, word, &k);
2402 [ # # ]: 0 : if (r < 0) {
2403 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
2404 : : "Failed to resolve unit specifiers in %s, ignoring: %m", word);
2405 : 0 : continue;
2406 : : }
2407 : : } else
2408 : 0 : k = TAKE_PTR(word);
2409 : :
2410 [ # # # # ]: 0 : if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
2411 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
2412 : : "Invalid environment name or assignment %s, ignoring: %s", lvalue, k);
2413 : 0 : continue;
2414 : : }
2415 : :
2416 [ # # ]: 0 : if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2417 : 0 : return log_oom();
2418 : :
2419 : 0 : n[nlen++] = TAKE_PTR(k);
2420 : 0 : n[nlen] = NULL;
2421 : : }
2422 : :
2423 [ # # ]: 0 : if (n) {
2424 : 0 : r = strv_extend_strv(unsetenv, n, true);
2425 [ # # ]: 0 : if (r < 0)
2426 : 0 : return r;
2427 : : }
2428 : :
2429 : 0 : return 0;
2430 : : }
2431 : :
2432 : 12 : int config_parse_log_extra_fields(
2433 : : const char *unit,
2434 : : const char *filename,
2435 : : unsigned line,
2436 : : const char *section,
2437 : : unsigned section_line,
2438 : : const char *lvalue,
2439 : : int ltype,
2440 : : const char *rvalue,
2441 : : void *data,
2442 : : void *userdata) {
2443 : :
2444 : 12 : ExecContext *c = data;
2445 : 12 : Unit *u = userdata;
2446 : 12 : const char *p = rvalue;
2447 : : int r;
2448 : :
2449 [ - + ]: 12 : assert(filename);
2450 [ - + ]: 12 : assert(lvalue);
2451 [ - + ]: 12 : assert(rvalue);
2452 [ - + ]: 12 : assert(c);
2453 : :
2454 [ + + ]: 12 : if (isempty(rvalue)) {
2455 : 4 : exec_context_free_log_extra_fields(c);
2456 : 4 : return 0;
2457 : : }
2458 : :
2459 : 20 : for (;;) {
2460 [ + + + + : 40 : _cleanup_free_ char *word = NULL, *k = NULL;
+ + ]
2461 : : struct iovec *t;
2462 : : const char *eq;
2463 : :
2464 : 28 : r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
2465 [ + + ]: 28 : if (r == 0)
2466 : 8 : return 0;
2467 [ - + ]: 20 : if (r == -ENOMEM)
2468 : 0 : return log_oom();
2469 [ - + ]: 20 : if (r < 0) {
2470 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
2471 : 0 : return 0;
2472 : : }
2473 : :
2474 : 20 : r = unit_full_printf(u, word, &k);
2475 [ - + ]: 20 : if (r < 0) {
2476 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
2477 : 0 : continue;
2478 : : }
2479 : :
2480 : 20 : eq = strchr(k, '=');
2481 [ + + ]: 20 : if (!eq) {
2482 [ + - ]: 4 : log_syntax(unit, LOG_ERR, filename, line, 0, "Log field lacks '=' character, ignoring: %s", k);
2483 : 4 : continue;
2484 : : }
2485 : :
2486 [ - + ]: 16 : if (!journal_field_valid(k, eq-k, false)) {
2487 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Log field name is invalid, ignoring: %s", k);
2488 : 0 : continue;
2489 : : }
2490 : :
2491 : 16 : t = reallocarray(c->log_extra_fields, c->n_log_extra_fields+1, sizeof(struct iovec));
2492 [ - + ]: 16 : if (!t)
2493 : 0 : return log_oom();
2494 : :
2495 : 16 : c->log_extra_fields = t;
2496 : 16 : c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE_STRING(k);
2497 : :
2498 : 16 : k = NULL;
2499 : : }
2500 : : }
2501 : :
2502 : 0 : int config_parse_unit_condition_path(
2503 : : const char *unit,
2504 : : const char *filename,
2505 : : unsigned line,
2506 : : const char *section,
2507 : : unsigned section_line,
2508 : : const char *lvalue,
2509 : : int ltype,
2510 : : const char *rvalue,
2511 : : void *data,
2512 : : void *userdata) {
2513 : :
2514 : 0 : _cleanup_free_ char *p = NULL;
2515 : 0 : Condition **list = data, *c;
2516 : 0 : ConditionType t = ltype;
2517 : : bool trigger, negate;
2518 : 0 : Unit *u = userdata;
2519 : : int r;
2520 : :
2521 [ # # ]: 0 : assert(filename);
2522 [ # # ]: 0 : assert(lvalue);
2523 [ # # ]: 0 : assert(rvalue);
2524 [ # # ]: 0 : assert(data);
2525 : :
2526 [ # # ]: 0 : if (isempty(rvalue)) {
2527 : : /* Empty assignment resets the list */
2528 : 0 : *list = condition_free_list(*list);
2529 : 0 : return 0;
2530 : : }
2531 : :
2532 : 0 : trigger = rvalue[0] == '|';
2533 [ # # ]: 0 : if (trigger)
2534 : 0 : rvalue++;
2535 : :
2536 : 0 : negate = rvalue[0] == '!';
2537 [ # # ]: 0 : if (negate)
2538 : 0 : rvalue++;
2539 : :
2540 : 0 : r = unit_full_printf(u, rvalue, &p);
2541 [ # # ]: 0 : if (r < 0) {
2542 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
2543 : 0 : return 0;
2544 : : }
2545 : :
2546 : 0 : r = path_simplify_and_warn(p, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
2547 [ # # ]: 0 : if (r < 0)
2548 : 0 : return 0;
2549 : :
2550 : 0 : c = condition_new(t, p, trigger, negate);
2551 [ # # ]: 0 : if (!c)
2552 : 0 : return log_oom();
2553 : :
2554 [ # # # # ]: 0 : LIST_PREPEND(conditions, *list, c);
2555 : 0 : return 0;
2556 : : }
2557 : :
2558 : 0 : int config_parse_unit_condition_string(
2559 : : const char *unit,
2560 : : const char *filename,
2561 : : unsigned line,
2562 : : const char *section,
2563 : : unsigned section_line,
2564 : : const char *lvalue,
2565 : : int ltype,
2566 : : const char *rvalue,
2567 : : void *data,
2568 : : void *userdata) {
2569 : :
2570 : 0 : _cleanup_free_ char *s = NULL;
2571 : 0 : Condition **list = data, *c;
2572 : 0 : ConditionType t = ltype;
2573 : : bool trigger, negate;
2574 : 0 : Unit *u = userdata;
2575 : : int r;
2576 : :
2577 [ # # ]: 0 : assert(filename);
2578 [ # # ]: 0 : assert(lvalue);
2579 [ # # ]: 0 : assert(rvalue);
2580 [ # # ]: 0 : assert(data);
2581 : :
2582 [ # # ]: 0 : if (isempty(rvalue)) {
2583 : : /* Empty assignment resets the list */
2584 : 0 : *list = condition_free_list(*list);
2585 : 0 : return 0;
2586 : : }
2587 : :
2588 : 0 : trigger = *rvalue == '|';
2589 [ # # ]: 0 : if (trigger)
2590 : 0 : rvalue += 1 + strspn(rvalue + 1, WHITESPACE);
2591 : :
2592 : 0 : negate = *rvalue == '!';
2593 [ # # ]: 0 : if (negate)
2594 : 0 : rvalue += 1 + strspn(rvalue + 1, WHITESPACE);
2595 : :
2596 : 0 : r = unit_full_printf(u, rvalue, &s);
2597 [ # # ]: 0 : if (r < 0) {
2598 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
2599 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
2600 : 0 : return 0;
2601 : : }
2602 : :
2603 : 0 : c = condition_new(t, s, trigger, negate);
2604 [ # # ]: 0 : if (!c)
2605 : 0 : return log_oom();
2606 : :
2607 [ # # # # ]: 0 : LIST_PREPEND(conditions, *list, c);
2608 : 0 : return 0;
2609 : : }
2610 : :
2611 : 0 : int config_parse_unit_condition_null(
2612 : : const char *unit,
2613 : : const char *filename,
2614 : : unsigned line,
2615 : : const char *section,
2616 : : unsigned section_line,
2617 : : const char *lvalue,
2618 : : int ltype,
2619 : : const char *rvalue,
2620 : : void *data,
2621 : : void *userdata) {
2622 : :
2623 : 0 : Condition **list = data, *c;
2624 : : bool trigger, negate;
2625 : : int b;
2626 : :
2627 [ # # ]: 0 : assert(filename);
2628 [ # # ]: 0 : assert(lvalue);
2629 [ # # ]: 0 : assert(rvalue);
2630 [ # # ]: 0 : assert(data);
2631 : :
2632 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is deprecated, please do not use.", lvalue);
2633 : :
2634 [ # # ]: 0 : if (isempty(rvalue)) {
2635 : : /* Empty assignment resets the list */
2636 : 0 : *list = condition_free_list(*list);
2637 : 0 : return 0;
2638 : : }
2639 : :
2640 : 0 : trigger = rvalue[0] == '|';
2641 [ # # ]: 0 : if (trigger)
2642 : 0 : rvalue++;
2643 : :
2644 : 0 : negate = rvalue[0] == '!';
2645 [ # # ]: 0 : if (negate)
2646 : 0 : rvalue++;
2647 : :
2648 : 0 : b = parse_boolean(rvalue);
2649 [ # # ]: 0 : if (b < 0) {
2650 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2651 : 0 : return 0;
2652 : : }
2653 : :
2654 [ # # ]: 0 : if (!b)
2655 : 0 : negate = !negate;
2656 : :
2657 : 0 : c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2658 [ # # ]: 0 : if (!c)
2659 : 0 : return log_oom();
2660 : :
2661 [ # # # # ]: 0 : LIST_PREPEND(conditions, *list, c);
2662 : 0 : return 0;
2663 : : }
2664 : :
2665 : 44 : int config_parse_unit_requires_mounts_for(
2666 : : const char *unit,
2667 : : const char *filename,
2668 : : unsigned line,
2669 : : const char *section,
2670 : : unsigned section_line,
2671 : : const char *lvalue,
2672 : : int ltype,
2673 : : const char *rvalue,
2674 : : void *data,
2675 : : void *userdata) {
2676 : :
2677 : 44 : const char *p = rvalue;
2678 : 44 : Unit *u = userdata;
2679 : : int r;
2680 : :
2681 [ - + ]: 44 : assert(filename);
2682 [ - + ]: 44 : assert(lvalue);
2683 [ - + ]: 44 : assert(rvalue);
2684 [ - + ]: 44 : assert(data);
2685 : :
2686 : 88 : for (;;) {
2687 [ + + - + : 176 : _cleanup_free_ char *word = NULL, *resolved = NULL;
+ - ]
2688 : :
2689 : 132 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2690 [ + + ]: 132 : if (r == 0)
2691 : 44 : return 0;
2692 [ - + ]: 88 : if (r == -ENOMEM)
2693 : 0 : return log_oom();
2694 [ - + ]: 88 : if (r < 0) {
2695 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
2696 : : "Invalid syntax, ignoring: %s", rvalue);
2697 : 0 : return 0;
2698 : : }
2699 : :
2700 : 88 : r = unit_full_printf(u, word, &resolved);
2701 [ - + ]: 88 : if (r < 0) {
2702 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
2703 : 0 : continue;
2704 : : }
2705 : :
2706 : 88 : r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
2707 [ - + ]: 88 : if (r < 0)
2708 : 0 : continue;
2709 : :
2710 : 88 : r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
2711 [ - + ]: 88 : if (r < 0) {
2712 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount '%s', ignoring: %m", resolved);
2713 : 0 : continue;
2714 : : }
2715 : : }
2716 : : }
2717 : :
2718 : 176 : int config_parse_documentation(const char *unit,
2719 : : const char *filename,
2720 : : unsigned line,
2721 : : const char *section,
2722 : : unsigned section_line,
2723 : : const char *lvalue,
2724 : : int ltype,
2725 : : const char *rvalue,
2726 : : void *data,
2727 : : void *userdata) {
2728 : :
2729 : 176 : Unit *u = userdata;
2730 : : int r;
2731 : : char **a, **b;
2732 : :
2733 [ - + ]: 176 : assert(filename);
2734 [ - + ]: 176 : assert(lvalue);
2735 [ - + ]: 176 : assert(rvalue);
2736 [ - + ]: 176 : assert(u);
2737 : :
2738 [ - + ]: 176 : if (isempty(rvalue)) {
2739 : : /* Empty assignment resets the list */
2740 : 0 : u->documentation = strv_free(u->documentation);
2741 : 0 : return 0;
2742 : : }
2743 : :
2744 : 176 : r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2745 : : rvalue, data, userdata);
2746 [ - + ]: 176 : if (r < 0)
2747 : 0 : return r;
2748 : :
2749 [ + - + + ]: 364 : for (a = b = u->documentation; a && *a; a++) {
2750 : :
2751 [ + - ]: 188 : if (documentation_url_is_valid(*a))
2752 : 188 : *(b++) = *a;
2753 : : else {
2754 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
2755 : 0 : free(*a);
2756 : : }
2757 : : }
2758 [ + - ]: 176 : if (b)
2759 : 176 : *b = NULL;
2760 : :
2761 : 176 : return r;
2762 : : }
2763 : :
2764 : : #if HAVE_SECCOMP
2765 : 0 : int config_parse_syscall_filter(
2766 : : const char *unit,
2767 : : const char *filename,
2768 : : unsigned line,
2769 : : const char *section,
2770 : : unsigned section_line,
2771 : : const char *lvalue,
2772 : : int ltype,
2773 : : const char *rvalue,
2774 : : void *data,
2775 : : void *userdata) {
2776 : :
2777 : 0 : ExecContext *c = data;
2778 : 0 : Unit *u = userdata;
2779 : 0 : bool invert = false;
2780 : : const char *p;
2781 : : int r;
2782 : :
2783 [ # # ]: 0 : assert(filename);
2784 [ # # ]: 0 : assert(lvalue);
2785 [ # # ]: 0 : assert(rvalue);
2786 [ # # ]: 0 : assert(u);
2787 : :
2788 [ # # ]: 0 : if (isempty(rvalue)) {
2789 : : /* Empty assignment resets the list */
2790 : 0 : c->syscall_filter = hashmap_free(c->syscall_filter);
2791 : 0 : c->syscall_whitelist = false;
2792 : 0 : return 0;
2793 : : }
2794 : :
2795 [ # # ]: 0 : if (rvalue[0] == '~') {
2796 : 0 : invert = true;
2797 : 0 : rvalue++;
2798 : : }
2799 : :
2800 [ # # ]: 0 : if (!c->syscall_filter) {
2801 : 0 : c->syscall_filter = hashmap_new(NULL);
2802 [ # # ]: 0 : if (!c->syscall_filter)
2803 : 0 : return log_oom();
2804 : :
2805 [ # # ]: 0 : if (invert)
2806 : : /* Allow everything but the ones listed */
2807 : 0 : c->syscall_whitelist = false;
2808 : : else {
2809 : : /* Allow nothing but the ones listed */
2810 : 0 : c->syscall_whitelist = true;
2811 : :
2812 : : /* Accept default syscalls if we are on a whitelist */
2813 : 0 : r = seccomp_parse_syscall_filter(
2814 : : "@default", -1, c->syscall_filter,
2815 : : SECCOMP_PARSE_PERMISSIVE|SECCOMP_PARSE_WHITELIST,
2816 : : unit,
2817 : : NULL, 0);
2818 [ # # ]: 0 : if (r < 0)
2819 : 0 : return r;
2820 : : }
2821 : : }
2822 : :
2823 : 0 : p = rvalue;
2824 : 0 : for (;;) {
2825 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *name = NULL;
# # ]
2826 : : int num;
2827 : :
2828 : 0 : r = extract_first_word(&p, &word, NULL, 0);
2829 [ # # ]: 0 : if (r == 0)
2830 : 0 : return 0;
2831 [ # # ]: 0 : if (r == -ENOMEM)
2832 : 0 : return log_oom();
2833 [ # # ]: 0 : if (r < 0) {
2834 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
2835 : 0 : return 0;
2836 : : }
2837 : :
2838 : 0 : r = parse_syscall_and_errno(word, &name, &num);
2839 [ # # ]: 0 : if (r < 0) {
2840 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall:errno, ignoring: %s", word);
2841 : 0 : continue;
2842 : : }
2843 : :
2844 : 0 : r = seccomp_parse_syscall_filter(
2845 : : name, num, c->syscall_filter,
2846 [ # # ]: 0 : SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
2847 : 0 : (invert ? SECCOMP_PARSE_INVERT : 0)|
2848 : 0 : (c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0),
2849 : : unit, filename, line);
2850 [ # # ]: 0 : if (r < 0)
2851 : 0 : return r;
2852 : : }
2853 : : }
2854 : :
2855 : 0 : int config_parse_syscall_archs(
2856 : : const char *unit,
2857 : : const char *filename,
2858 : : unsigned line,
2859 : : const char *section,
2860 : : unsigned section_line,
2861 : : const char *lvalue,
2862 : : int ltype,
2863 : : const char *rvalue,
2864 : : void *data,
2865 : : void *userdata) {
2866 : :
2867 : 0 : const char *p = rvalue;
2868 : 0 : Set **archs = data;
2869 : : int r;
2870 : :
2871 [ # # ]: 0 : if (isempty(rvalue)) {
2872 : 0 : *archs = set_free(*archs);
2873 : 0 : return 0;
2874 : : }
2875 : :
2876 : 0 : r = set_ensure_allocated(archs, NULL);
2877 [ # # ]: 0 : if (r < 0)
2878 : 0 : return log_oom();
2879 : :
2880 : 0 : for (;;) {
2881 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
2882 : : uint32_t a;
2883 : :
2884 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2885 [ # # ]: 0 : if (r == 0)
2886 : 0 : return 0;
2887 [ # # ]: 0 : if (r == -ENOMEM)
2888 : 0 : return log_oom();
2889 [ # # ]: 0 : if (r < 0) {
2890 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
2891 : : "Invalid syntax, ignoring: %s", rvalue);
2892 : 0 : return 0;
2893 : : }
2894 : :
2895 : 0 : r = seccomp_arch_from_string(word, &a);
2896 [ # # ]: 0 : if (r < 0) {
2897 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
2898 : : "Failed to parse system call architecture \"%s\", ignoring: %m", word);
2899 : 0 : continue;
2900 : : }
2901 : :
2902 : 0 : r = set_put(*archs, UINT32_TO_PTR(a + 1));
2903 [ # # ]: 0 : if (r < 0)
2904 : 0 : return log_oom();
2905 : : }
2906 : : }
2907 : :
2908 : 0 : int config_parse_syscall_errno(
2909 : : const char *unit,
2910 : : const char *filename,
2911 : : unsigned line,
2912 : : const char *section,
2913 : : unsigned section_line,
2914 : : const char *lvalue,
2915 : : int ltype,
2916 : : const char *rvalue,
2917 : : void *data,
2918 : : void *userdata) {
2919 : :
2920 : 0 : ExecContext *c = data;
2921 : : int e;
2922 : :
2923 [ # # ]: 0 : assert(filename);
2924 [ # # ]: 0 : assert(lvalue);
2925 [ # # ]: 0 : assert(rvalue);
2926 : :
2927 [ # # ]: 0 : if (isempty(rvalue)) {
2928 : : /* Empty assignment resets to KILL */
2929 : 0 : c->syscall_errno = 0;
2930 : 0 : return 0;
2931 : : }
2932 : :
2933 : 0 : e = parse_errno(rvalue);
2934 [ # # ]: 0 : if (e <= 0) {
2935 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
2936 : 0 : return 0;
2937 : : }
2938 : :
2939 : 0 : c->syscall_errno = e;
2940 : 0 : return 0;
2941 : : }
2942 : :
2943 : 0 : int config_parse_address_families(
2944 : : const char *unit,
2945 : : const char *filename,
2946 : : unsigned line,
2947 : : const char *section,
2948 : : unsigned section_line,
2949 : : const char *lvalue,
2950 : : int ltype,
2951 : : const char *rvalue,
2952 : : void *data,
2953 : : void *userdata) {
2954 : :
2955 : 0 : ExecContext *c = data;
2956 : 0 : bool invert = false;
2957 : : const char *p;
2958 : : int r;
2959 : :
2960 [ # # ]: 0 : assert(filename);
2961 [ # # ]: 0 : assert(lvalue);
2962 [ # # ]: 0 : assert(rvalue);
2963 : :
2964 [ # # ]: 0 : if (isempty(rvalue)) {
2965 : : /* Empty assignment resets the list */
2966 : 0 : c->address_families = set_free(c->address_families);
2967 : 0 : c->address_families_whitelist = false;
2968 : 0 : return 0;
2969 : : }
2970 : :
2971 [ # # ]: 0 : if (rvalue[0] == '~') {
2972 : 0 : invert = true;
2973 : 0 : rvalue++;
2974 : : }
2975 : :
2976 [ # # ]: 0 : if (!c->address_families) {
2977 : 0 : c->address_families = set_new(NULL);
2978 [ # # ]: 0 : if (!c->address_families)
2979 : 0 : return log_oom();
2980 : :
2981 : 0 : c->address_families_whitelist = !invert;
2982 : : }
2983 : :
2984 : 0 : for (p = rvalue;;) {
2985 [ # # # ]: 0 : _cleanup_free_ char *word = NULL;
2986 : : int af;
2987 : :
2988 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
2989 [ # # ]: 0 : if (r == 0)
2990 : 0 : return 0;
2991 [ # # ]: 0 : if (r == -ENOMEM)
2992 : 0 : return log_oom();
2993 [ # # ]: 0 : if (r < 0) {
2994 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
2995 : : "Invalid syntax, ignoring: %s", rvalue);
2996 : 0 : return 0;
2997 : : }
2998 : :
2999 : 0 : af = af_from_name(word);
3000 [ # # ]: 0 : if (af < 0) {
3001 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, af,
3002 : : "Failed to parse address family, ignoring: %s", word);
3003 : 0 : continue;
3004 : : }
3005 : :
3006 : : /* If we previously wanted to forbid an address family and now
3007 : : * we want to allow it, then just remove it from the list.
3008 : : */
3009 [ # # ]: 0 : if (!invert == c->address_families_whitelist) {
3010 : 0 : r = set_put(c->address_families, INT_TO_PTR(af));
3011 [ # # ]: 0 : if (r < 0)
3012 : 0 : return log_oom();
3013 : : } else
3014 : 0 : set_remove(c->address_families, INT_TO_PTR(af));
3015 : : }
3016 : : }
3017 : :
3018 : 0 : int config_parse_restrict_namespaces(
3019 : : const char *unit,
3020 : : const char *filename,
3021 : : unsigned line,
3022 : : const char *section,
3023 : : unsigned section_line,
3024 : : const char *lvalue,
3025 : : int ltype,
3026 : : const char *rvalue,
3027 : : void *data,
3028 : : void *userdata) {
3029 : :
3030 : 0 : ExecContext *c = data;
3031 : : unsigned long flags;
3032 : 0 : bool invert = false;
3033 : : int r;
3034 : :
3035 [ # # ]: 0 : if (isempty(rvalue)) {
3036 : : /* Reset to the default. */
3037 : 0 : c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
3038 : 0 : return 0;
3039 : : }
3040 : :
3041 : : /* Boolean parameter ignores the previous settings */
3042 : 0 : r = parse_boolean(rvalue);
3043 [ # # ]: 0 : if (r > 0) {
3044 : 0 : c->restrict_namespaces = 0;
3045 : 0 : return 0;
3046 [ # # ]: 0 : } else if (r == 0) {
3047 : 0 : c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
3048 : 0 : return 0;
3049 : : }
3050 : :
3051 [ # # ]: 0 : if (rvalue[0] == '~') {
3052 : 0 : invert = true;
3053 : 0 : rvalue++;
3054 : : }
3055 : :
3056 : : /* Not a boolean argument, in this case it's a list of namespace types. */
3057 : 0 : r = namespace_flags_from_string(rvalue, &flags);
3058 [ # # ]: 0 : if (r < 0) {
3059 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
3060 : 0 : return 0;
3061 : : }
3062 : :
3063 [ # # ]: 0 : if (c->restrict_namespaces == NAMESPACE_FLAGS_INITIAL)
3064 : : /* Initial assignment. Just set the value. */
3065 [ # # ]: 0 : c->restrict_namespaces = invert ? (~flags) & NAMESPACE_FLAGS_ALL : flags;
3066 : : else
3067 : : /* Merge the value with the previous one. */
3068 [ # # ]: 0 : SET_FLAG(c->restrict_namespaces, flags, !invert);
3069 : :
3070 : 0 : return 0;
3071 : : }
3072 : : #endif
3073 : :
3074 : 40 : int config_parse_unit_slice(
3075 : : const char *unit,
3076 : : const char *filename,
3077 : : unsigned line,
3078 : : const char *section,
3079 : : unsigned section_line,
3080 : : const char *lvalue,
3081 : : int ltype,
3082 : : const char *rvalue,
3083 : : void *data,
3084 : : void *userdata) {
3085 : :
3086 : 40 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3087 : 40 : _cleanup_free_ char *k = NULL;
3088 : 40 : Unit *u = userdata, *slice = NULL;
3089 : : int r;
3090 : :
3091 [ - + ]: 40 : assert(filename);
3092 [ - + ]: 40 : assert(lvalue);
3093 [ - + ]: 40 : assert(rvalue);
3094 [ - + ]: 40 : assert(u);
3095 : :
3096 : 40 : r = unit_name_printf(u, rvalue, &k);
3097 [ - + ]: 40 : if (r < 0) {
3098 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
3099 : 0 : return 0;
3100 : : }
3101 : :
3102 : 40 : r = manager_load_unit(u->manager, k, NULL, &error, &slice);
3103 [ - + ]: 40 : if (r < 0) {
3104 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s, ignoring: %s", k, bus_error_message(&error, r));
3105 : 0 : return 0;
3106 : : }
3107 : :
3108 : 40 : r = unit_set_slice(u, slice);
3109 [ - + ]: 40 : if (r < 0) {
3110 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s, ignoring: %m", slice->id, u->id);
3111 : 0 : return 0;
3112 : : }
3113 : :
3114 : 40 : return 0;
3115 : : }
3116 : :
3117 : 0 : int config_parse_cpu_quota(
3118 : : const char *unit,
3119 : : const char *filename,
3120 : : unsigned line,
3121 : : const char *section,
3122 : : unsigned section_line,
3123 : : const char *lvalue,
3124 : : int ltype,
3125 : : const char *rvalue,
3126 : : void *data,
3127 : : void *userdata) {
3128 : :
3129 : 0 : CGroupContext *c = data;
3130 : : int r;
3131 : :
3132 [ # # ]: 0 : assert(filename);
3133 [ # # ]: 0 : assert(lvalue);
3134 [ # # ]: 0 : assert(rvalue);
3135 : :
3136 [ # # ]: 0 : if (isempty(rvalue)) {
3137 : 0 : c->cpu_quota_per_sec_usec = USEC_INFINITY;
3138 : 0 : return 0;
3139 : : }
3140 : :
3141 : 0 : r = parse_permille_unbounded(rvalue);
3142 [ # # ]: 0 : if (r <= 0) {
3143 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
3144 : 0 : return 0;
3145 : : }
3146 : :
3147 : 0 : c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U;
3148 : 0 : return 0;
3149 : : }
3150 : :
3151 : 32 : int config_parse_memory_limit(
3152 : : const char *unit,
3153 : : const char *filename,
3154 : : unsigned line,
3155 : : const char *section,
3156 : : unsigned section_line,
3157 : : const char *lvalue,
3158 : : int ltype,
3159 : : const char *rvalue,
3160 : : void *data,
3161 : : void *userdata) {
3162 : :
3163 : 32 : CGroupContext *c = data;
3164 : 32 : uint64_t bytes = CGROUP_LIMIT_MAX;
3165 : : int r;
3166 : :
3167 [ + + + - ]: 32 : if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
3168 : :
3169 : 28 : r = parse_permille(rvalue);
3170 [ + - ]: 28 : if (r < 0) {
3171 : 28 : r = parse_size(rvalue, 1024, &bytes);
3172 [ - + ]: 28 : if (r < 0) {
3173 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid memory limit '%s', ignoring: %m", rvalue);
3174 : 0 : return 0;
3175 : : }
3176 : : } else
3177 : 0 : bytes = physical_memory_scale(r, 1000U);
3178 : :
3179 [ + - ]: 28 : if (bytes >= UINT64_MAX ||
3180 [ + + - + ]: 28 : (bytes <= 0 && !STR_IN_SET(lvalue, "MemorySwapMax", "MemoryLow", "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin"))) {
3181 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range, ignoring.", rvalue);
3182 : 0 : return 0;
3183 : : }
3184 : : }
3185 : :
3186 [ + + ]: 32 : if (streq(lvalue, "DefaultMemoryLow")) {
3187 : 16 : c->default_memory_low_set = true;
3188 [ + + ]: 16 : if (isempty(rvalue))
3189 : 4 : c->default_memory_low = CGROUP_LIMIT_MIN;
3190 : : else
3191 : 12 : c->default_memory_low = bytes;
3192 [ - + ]: 16 : } else if (streq(lvalue, "DefaultMemoryMin")) {
3193 : 0 : c->default_memory_min_set = true;
3194 [ # # ]: 0 : if (isempty(rvalue))
3195 : 0 : c->default_memory_min = CGROUP_LIMIT_MIN;
3196 : : else
3197 : 0 : c->default_memory_min = bytes;
3198 [ - + ]: 16 : } else if (streq(lvalue, "MemoryMin")) {
3199 : 0 : c->memory_min = bytes;
3200 : 0 : c->memory_min_set = true;
3201 [ + + ]: 16 : } else if (streq(lvalue, "MemoryLow")) {
3202 : 12 : c->memory_low = bytes;
3203 : 12 : c->memory_low_set = true;
3204 [ - + ]: 4 : } else if (streq(lvalue, "MemoryHigh"))
3205 : 0 : c->memory_high = bytes;
3206 [ - + ]: 4 : else if (streq(lvalue, "MemoryMax"))
3207 : 0 : c->memory_max = bytes;
3208 [ - + ]: 4 : else if (streq(lvalue, "MemorySwapMax"))
3209 : 0 : c->memory_swap_max = bytes;
3210 [ + - ]: 4 : else if (streq(lvalue, "MemoryLimit"))
3211 : 4 : c->memory_limit = bytes;
3212 : : else
3213 : 0 : return -EINVAL;
3214 : :
3215 : 32 : return 0;
3216 : : }
3217 : :
3218 : 0 : int config_parse_tasks_max(
3219 : : const char *unit,
3220 : : const char *filename,
3221 : : unsigned line,
3222 : : const char *section,
3223 : : unsigned section_line,
3224 : : const char *lvalue,
3225 : : int ltype,
3226 : : const char *rvalue,
3227 : : void *data,
3228 : : void *userdata) {
3229 : :
3230 : 0 : uint64_t *tasks_max = data, v;
3231 : 0 : Unit *u = userdata;
3232 : : int r;
3233 : :
3234 [ # # ]: 0 : if (isempty(rvalue)) {
3235 [ # # ]: 0 : *tasks_max = u ? u->manager->default_tasks_max : UINT64_MAX;
3236 : 0 : return 0;
3237 : : }
3238 : :
3239 [ # # ]: 0 : if (streq(rvalue, "infinity")) {
3240 : 0 : *tasks_max = CGROUP_LIMIT_MAX;
3241 : 0 : return 0;
3242 : : }
3243 : :
3244 : 0 : r = parse_permille(rvalue);
3245 [ # # ]: 0 : if (r < 0) {
3246 : 0 : r = safe_atou64(rvalue, &v);
3247 [ # # ]: 0 : if (r < 0) {
3248 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid maximum tasks value '%s', ignoring: %m", rvalue);
3249 : 0 : return 0;
3250 : : }
3251 : : } else
3252 : 0 : v = system_tasks_max_scale(r, 1000U);
3253 : :
3254 [ # # # # ]: 0 : if (v <= 0 || v >= UINT64_MAX) {
3255 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range, ignoring.", rvalue);
3256 : 0 : return 0;
3257 : : }
3258 : :
3259 : 0 : *tasks_max = v;
3260 : 0 : return 0;
3261 : : }
3262 : :
3263 : 0 : int config_parse_delegate(
3264 : : const char *unit,
3265 : : const char *filename,
3266 : : unsigned line,
3267 : : const char *section,
3268 : : unsigned section_line,
3269 : : const char *lvalue,
3270 : : int ltype,
3271 : : const char *rvalue,
3272 : : void *data,
3273 : : void *userdata) {
3274 : :
3275 : 0 : CGroupContext *c = data;
3276 : : UnitType t;
3277 : : int r;
3278 : :
3279 : 0 : t = unit_name_to_type(unit);
3280 [ # # ]: 0 : assert(t != _UNIT_TYPE_INVALID);
3281 : :
3282 [ # # ]: 0 : if (!unit_vtable[t]->can_delegate) {
3283 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Delegate= setting not supported for this unit type, ignoring.");
3284 : 0 : return 0;
3285 : : }
3286 : :
3287 : : /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
3288 : : * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
3289 : : * mask to delegate. */
3290 : :
3291 [ # # ]: 0 : if (isempty(rvalue)) {
3292 : : /* An empty string resets controllers and set Delegate=yes. */
3293 : 0 : c->delegate = true;
3294 : 0 : c->delegate_controllers = 0;
3295 : 0 : return 0;
3296 : : }
3297 : :
3298 : 0 : r = parse_boolean(rvalue);
3299 [ # # ]: 0 : if (r < 0) {
3300 : 0 : const char *p = rvalue;
3301 : 0 : CGroupMask mask = 0;
3302 : :
3303 : 0 : for (;;) {
3304 [ # # # # ]: 0 : _cleanup_free_ char *word = NULL;
3305 : : CGroupController cc;
3306 : :
3307 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3308 [ # # ]: 0 : if (r == 0)
3309 : 0 : break;
3310 [ # # ]: 0 : if (r == -ENOMEM)
3311 : 0 : return log_oom();
3312 [ # # ]: 0 : if (r < 0) {
3313 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
3314 : 0 : return 0;
3315 : : }
3316 : :
3317 : 0 : cc = cgroup_controller_from_string(word);
3318 [ # # ]: 0 : if (cc < 0) {
3319 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", word);
3320 : 0 : continue;
3321 : : }
3322 : :
3323 : 0 : mask |= CGROUP_CONTROLLER_TO_MASK(cc);
3324 : : }
3325 : :
3326 : 0 : c->delegate = true;
3327 : 0 : c->delegate_controllers |= mask;
3328 : :
3329 [ # # ]: 0 : } else if (r > 0) {
3330 : 0 : c->delegate = true;
3331 : 0 : c->delegate_controllers = _CGROUP_MASK_ALL;
3332 : : } else {
3333 : 0 : c->delegate = false;
3334 : 0 : c->delegate_controllers = 0;
3335 : : }
3336 : :
3337 : 0 : return 0;
3338 : : }
3339 : :
3340 : 0 : int config_parse_device_allow(
3341 : : const char *unit,
3342 : : const char *filename,
3343 : : unsigned line,
3344 : : const char *section,
3345 : : unsigned section_line,
3346 : : const char *lvalue,
3347 : : int ltype,
3348 : : const char *rvalue,
3349 : : void *data,
3350 : : void *userdata) {
3351 : :
3352 : 0 : _cleanup_free_ char *path = NULL, *resolved = NULL;
3353 : 0 : CGroupContext *c = data;
3354 : 0 : const char *p = rvalue;
3355 : : int r;
3356 : :
3357 [ # # ]: 0 : if (isempty(rvalue)) {
3358 [ # # ]: 0 : while (c->device_allow)
3359 : 0 : cgroup_context_free_device_allow(c, c->device_allow);
3360 : :
3361 : 0 : return 0;
3362 : : }
3363 : :
3364 : 0 : r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
3365 [ # # ]: 0 : if (r == -ENOMEM)
3366 : 0 : return log_oom();
3367 [ # # ]: 0 : if (r < 0) {
3368 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3369 : : "Invalid syntax, ignoring: %s", rvalue);
3370 : 0 : return 0;
3371 : : }
3372 [ # # ]: 0 : if (r == 0) {
3373 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
3374 : : "Failed to extract device path and rights from '%s', ignoring.", rvalue);
3375 : 0 : return 0;
3376 : : }
3377 : :
3378 : 0 : r = unit_full_printf(userdata, path, &resolved);
3379 [ # # ]: 0 : if (r < 0) {
3380 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3381 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
3382 : 0 : return 0;
3383 : : }
3384 : :
3385 [ # # # # : 0 : if (!STARTSWITH_SET(resolved, "block-", "char-")) {
# # # # ]
3386 : :
3387 : 0 : r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
3388 [ # # ]: 0 : if (r < 0)
3389 : 0 : return 0;
3390 : :
3391 [ # # ]: 0 : if (!valid_device_node_path(resolved)) {
3392 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
3393 : 0 : return 0;
3394 : : }
3395 : : }
3396 : :
3397 [ # # # # ]: 0 : if (!isempty(p) && !in_charset(p, "rwm")) {
3398 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s', ignoring.", p);
3399 : 0 : return 0;
3400 : : }
3401 : :
3402 : 0 : return cgroup_add_device_allow(c, resolved, p);
3403 : : }
3404 : :
3405 : 0 : int config_parse_io_device_weight(
3406 : : const char *unit,
3407 : : const char *filename,
3408 : : unsigned line,
3409 : : const char *section,
3410 : : unsigned section_line,
3411 : : const char *lvalue,
3412 : : int ltype,
3413 : : const char *rvalue,
3414 : : void *data,
3415 : : void *userdata) {
3416 : :
3417 : 0 : _cleanup_free_ char *path = NULL, *resolved = NULL;
3418 : : CGroupIODeviceWeight *w;
3419 : 0 : CGroupContext *c = data;
3420 : 0 : const char *p = rvalue;
3421 : : uint64_t u;
3422 : : int r;
3423 : :
3424 [ # # ]: 0 : assert(filename);
3425 [ # # ]: 0 : assert(lvalue);
3426 [ # # ]: 0 : assert(rvalue);
3427 : :
3428 [ # # ]: 0 : if (isempty(rvalue)) {
3429 [ # # ]: 0 : while (c->io_device_weights)
3430 : 0 : cgroup_context_free_io_device_weight(c, c->io_device_weights);
3431 : :
3432 : 0 : return 0;
3433 : : }
3434 : :
3435 : 0 : r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
3436 [ # # ]: 0 : if (r == -ENOMEM)
3437 : 0 : return log_oom();
3438 [ # # ]: 0 : if (r < 0) {
3439 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3440 : : "Invalid syntax, ignoring: %s", rvalue);
3441 : 0 : return 0;
3442 : : }
3443 [ # # # # ]: 0 : if (r == 0 || isempty(p)) {
3444 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
3445 : : "Failed to extract device path and weight from '%s', ignoring.", rvalue);
3446 : 0 : return 0;
3447 : : }
3448 : :
3449 : 0 : r = unit_full_printf(userdata, path, &resolved);
3450 [ # # ]: 0 : if (r < 0) {
3451 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3452 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
3453 : 0 : return 0;
3454 : : }
3455 : :
3456 : 0 : r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
3457 [ # # ]: 0 : if (r < 0)
3458 : 0 : return 0;
3459 : :
3460 : 0 : r = cg_weight_parse(p, &u);
3461 [ # # ]: 0 : if (r < 0) {
3462 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid, ignoring: %m", p);
3463 : 0 : return 0;
3464 : : }
3465 : :
3466 [ # # ]: 0 : assert(u != CGROUP_WEIGHT_INVALID);
3467 : :
3468 : 0 : w = new0(CGroupIODeviceWeight, 1);
3469 [ # # ]: 0 : if (!w)
3470 : 0 : return log_oom();
3471 : :
3472 : 0 : w->path = TAKE_PTR(resolved);
3473 : 0 : w->weight = u;
3474 : :
3475 [ # # # # ]: 0 : LIST_PREPEND(device_weights, c->io_device_weights, w);
3476 : 0 : return 0;
3477 : : }
3478 : :
3479 : 0 : int config_parse_io_device_latency(
3480 : : const char *unit,
3481 : : const char *filename,
3482 : : unsigned line,
3483 : : const char *section,
3484 : : unsigned section_line,
3485 : : const char *lvalue,
3486 : : int ltype,
3487 : : const char *rvalue,
3488 : : void *data,
3489 : : void *userdata) {
3490 : :
3491 : 0 : _cleanup_free_ char *path = NULL, *resolved = NULL;
3492 : : CGroupIODeviceLatency *l;
3493 : 0 : CGroupContext *c = data;
3494 : 0 : const char *p = rvalue;
3495 : : usec_t usec;
3496 : : int r;
3497 : :
3498 [ # # ]: 0 : assert(filename);
3499 [ # # ]: 0 : assert(lvalue);
3500 [ # # ]: 0 : assert(rvalue);
3501 : :
3502 [ # # ]: 0 : if (isempty(rvalue)) {
3503 [ # # ]: 0 : while (c->io_device_latencies)
3504 : 0 : cgroup_context_free_io_device_latency(c, c->io_device_latencies);
3505 : :
3506 : 0 : return 0;
3507 : : }
3508 : :
3509 : 0 : r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
3510 [ # # ]: 0 : if (r == -ENOMEM)
3511 : 0 : return log_oom();
3512 [ # # ]: 0 : if (r < 0) {
3513 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3514 : : "Invalid syntax, ignoring: %s", rvalue);
3515 : 0 : return 0;
3516 : : }
3517 [ # # # # ]: 0 : if (r == 0 || isempty(p)) {
3518 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
3519 : : "Failed to extract device path and latency from '%s', ignoring.", rvalue);
3520 : 0 : return 0;
3521 : : }
3522 : :
3523 : 0 : r = unit_full_printf(userdata, path, &resolved);
3524 [ # # ]: 0 : if (r < 0) {
3525 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3526 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
3527 : 0 : return 0;
3528 : : }
3529 : :
3530 : 0 : r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
3531 [ # # ]: 0 : if (r < 0)
3532 : 0 : return 0;
3533 : :
3534 [ # # ]: 0 : if (parse_sec(p, &usec) < 0) {
3535 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", p);
3536 : 0 : return 0;
3537 : : }
3538 : :
3539 : 0 : l = new0(CGroupIODeviceLatency, 1);
3540 [ # # ]: 0 : if (!l)
3541 : 0 : return log_oom();
3542 : :
3543 : 0 : l->path = TAKE_PTR(resolved);
3544 : 0 : l->target_usec = usec;
3545 : :
3546 [ # # # # ]: 0 : LIST_PREPEND(device_latencies, c->io_device_latencies, l);
3547 : 0 : return 0;
3548 : : }
3549 : :
3550 : 0 : int config_parse_io_limit(
3551 : : const char *unit,
3552 : : const char *filename,
3553 : : unsigned line,
3554 : : const char *section,
3555 : : unsigned section_line,
3556 : : const char *lvalue,
3557 : : int ltype,
3558 : : const char *rvalue,
3559 : : void *data,
3560 : : void *userdata) {
3561 : :
3562 : 0 : _cleanup_free_ char *path = NULL, *resolved = NULL;
3563 : 0 : CGroupIODeviceLimit *l = NULL, *t;
3564 : 0 : CGroupContext *c = data;
3565 : : CGroupIOLimitType type;
3566 : 0 : const char *p = rvalue;
3567 : : uint64_t num;
3568 : : int r;
3569 : :
3570 [ # # ]: 0 : assert(filename);
3571 [ # # ]: 0 : assert(lvalue);
3572 [ # # ]: 0 : assert(rvalue);
3573 : :
3574 : 0 : type = cgroup_io_limit_type_from_string(lvalue);
3575 [ # # ]: 0 : assert(type >= 0);
3576 : :
3577 [ # # ]: 0 : if (isempty(rvalue)) {
3578 [ # # ]: 0 : LIST_FOREACH(device_limits, l, c->io_device_limits)
3579 : 0 : l->limits[type] = cgroup_io_limit_defaults[type];
3580 : 0 : return 0;
3581 : : }
3582 : :
3583 : 0 : r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
3584 [ # # ]: 0 : if (r == -ENOMEM)
3585 : 0 : return log_oom();
3586 [ # # ]: 0 : if (r < 0) {
3587 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3588 : : "Invalid syntax, ignoring: %s", rvalue);
3589 : 0 : return 0;
3590 : : }
3591 [ # # # # ]: 0 : if (r == 0 || isempty(p)) {
3592 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
3593 : : "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue);
3594 : 0 : return 0;
3595 : : }
3596 : :
3597 : 0 : r = unit_full_printf(userdata, path, &resolved);
3598 [ # # ]: 0 : if (r < 0) {
3599 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3600 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
3601 : 0 : return 0;
3602 : : }
3603 : :
3604 : 0 : r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
3605 [ # # ]: 0 : if (r < 0)
3606 : 0 : return 0;
3607 : :
3608 [ # # ]: 0 : if (streq("infinity", p))
3609 : 0 : num = CGROUP_LIMIT_MAX;
3610 : : else {
3611 : 0 : r = parse_size(p, 1000, &num);
3612 [ # # # # ]: 0 : if (r < 0 || num <= 0) {
3613 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid IO limit '%s', ignoring.", p);
3614 : 0 : return 0;
3615 : : }
3616 : : }
3617 : :
3618 [ # # ]: 0 : LIST_FOREACH(device_limits, t, c->io_device_limits) {
3619 [ # # ]: 0 : if (path_equal(resolved, t->path)) {
3620 : 0 : l = t;
3621 : 0 : break;
3622 : : }
3623 : : }
3624 : :
3625 [ # # ]: 0 : if (!l) {
3626 : : CGroupIOLimitType ttype;
3627 : :
3628 : 0 : l = new0(CGroupIODeviceLimit, 1);
3629 [ # # ]: 0 : if (!l)
3630 : 0 : return log_oom();
3631 : :
3632 : 0 : l->path = TAKE_PTR(resolved);
3633 [ # # ]: 0 : for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
3634 : 0 : l->limits[ttype] = cgroup_io_limit_defaults[ttype];
3635 : :
3636 [ # # # # ]: 0 : LIST_PREPEND(device_limits, c->io_device_limits, l);
3637 : : }
3638 : :
3639 : 0 : l->limits[type] = num;
3640 : :
3641 : 0 : return 0;
3642 : : }
3643 : :
3644 : 0 : int config_parse_blockio_device_weight(
3645 : : const char *unit,
3646 : : const char *filename,
3647 : : unsigned line,
3648 : : const char *section,
3649 : : unsigned section_line,
3650 : : const char *lvalue,
3651 : : int ltype,
3652 : : const char *rvalue,
3653 : : void *data,
3654 : : void *userdata) {
3655 : :
3656 : 0 : _cleanup_free_ char *path = NULL, *resolved = NULL;
3657 : : CGroupBlockIODeviceWeight *w;
3658 : 0 : CGroupContext *c = data;
3659 : 0 : const char *p = rvalue;
3660 : : uint64_t u;
3661 : : int r;
3662 : :
3663 [ # # ]: 0 : assert(filename);
3664 [ # # ]: 0 : assert(lvalue);
3665 [ # # ]: 0 : assert(rvalue);
3666 : :
3667 [ # # ]: 0 : if (isempty(rvalue)) {
3668 [ # # ]: 0 : while (c->blockio_device_weights)
3669 : 0 : cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3670 : :
3671 : 0 : return 0;
3672 : : }
3673 : :
3674 : 0 : r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
3675 [ # # ]: 0 : if (r == -ENOMEM)
3676 : 0 : return log_oom();
3677 [ # # ]: 0 : if (r < 0) {
3678 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3679 : : "Invalid syntax, ignoring: %s", rvalue);
3680 : 0 : return 0;
3681 : : }
3682 [ # # # # ]: 0 : if (r == 0 || isempty(p)) {
3683 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
3684 : : "Failed to extract device node and weight from '%s', ignoring.", rvalue);
3685 : 0 : return 0;
3686 : : }
3687 : :
3688 : 0 : r = unit_full_printf(userdata, path, &resolved);
3689 [ # # ]: 0 : if (r < 0) {
3690 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3691 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
3692 : 0 : return 0;
3693 : : }
3694 : :
3695 : 0 : r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
3696 [ # # ]: 0 : if (r < 0)
3697 : 0 : return 0;
3698 : :
3699 : 0 : r = cg_blkio_weight_parse(p, &u);
3700 [ # # ]: 0 : if (r < 0) {
3701 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid block IO weight '%s', ignoring: %m", p);
3702 : 0 : return 0;
3703 : : }
3704 : :
3705 [ # # ]: 0 : assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3706 : :
3707 : 0 : w = new0(CGroupBlockIODeviceWeight, 1);
3708 [ # # ]: 0 : if (!w)
3709 : 0 : return log_oom();
3710 : :
3711 : 0 : w->path = TAKE_PTR(resolved);
3712 : 0 : w->weight = u;
3713 : :
3714 [ # # # # ]: 0 : LIST_PREPEND(device_weights, c->blockio_device_weights, w);
3715 : 0 : return 0;
3716 : : }
3717 : :
3718 : 0 : int config_parse_blockio_bandwidth(
3719 : : const char *unit,
3720 : : const char *filename,
3721 : : unsigned line,
3722 : : const char *section,
3723 : : unsigned section_line,
3724 : : const char *lvalue,
3725 : : int ltype,
3726 : : const char *rvalue,
3727 : : void *data,
3728 : : void *userdata) {
3729 : :
3730 : 0 : _cleanup_free_ char *path = NULL, *resolved = NULL;
3731 : 0 : CGroupBlockIODeviceBandwidth *b = NULL, *t;
3732 : 0 : CGroupContext *c = data;
3733 : 0 : const char *p = rvalue;
3734 : : uint64_t bytes;
3735 : : bool read;
3736 : : int r;
3737 : :
3738 [ # # ]: 0 : assert(filename);
3739 [ # # ]: 0 : assert(lvalue);
3740 [ # # ]: 0 : assert(rvalue);
3741 : :
3742 : 0 : read = streq("BlockIOReadBandwidth", lvalue);
3743 : :
3744 [ # # ]: 0 : if (isempty(rvalue)) {
3745 [ # # ]: 0 : LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
3746 : 0 : b->rbps = CGROUP_LIMIT_MAX;
3747 : 0 : b->wbps = CGROUP_LIMIT_MAX;
3748 : : }
3749 : 0 : return 0;
3750 : : }
3751 : :
3752 : 0 : r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
3753 [ # # ]: 0 : if (r == -ENOMEM)
3754 : 0 : return log_oom();
3755 [ # # ]: 0 : if (r < 0) {
3756 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3757 : : "Invalid syntax, ignoring: %s", rvalue);
3758 : 0 : return 0;
3759 : : }
3760 [ # # # # ]: 0 : if (r == 0 || isempty(p)) {
3761 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
3762 : : "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue);
3763 : 0 : return 0;
3764 : : }
3765 : :
3766 : 0 : r = unit_full_printf(userdata, path, &resolved);
3767 [ # # ]: 0 : if (r < 0) {
3768 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3769 : : "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
3770 : 0 : return 0;
3771 : : }
3772 : :
3773 : 0 : r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
3774 [ # # ]: 0 : if (r < 0)
3775 : 0 : return 0;
3776 : :
3777 : 0 : r = parse_size(p, 1000, &bytes);
3778 [ # # # # ]: 0 : if (r < 0 || bytes <= 0) {
3779 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid Block IO Bandwidth '%s', ignoring.", p);
3780 : 0 : return 0;
3781 : : }
3782 : :
3783 [ # # ]: 0 : LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
3784 [ # # ]: 0 : if (path_equal(resolved, t->path)) {
3785 : 0 : b = t;
3786 : 0 : break;
3787 : : }
3788 : : }
3789 : :
3790 [ # # ]: 0 : if (!t) {
3791 : 0 : b = new0(CGroupBlockIODeviceBandwidth, 1);
3792 [ # # ]: 0 : if (!b)
3793 : 0 : return log_oom();
3794 : :
3795 : 0 : b->path = TAKE_PTR(resolved);
3796 : 0 : b->rbps = CGROUP_LIMIT_MAX;
3797 : 0 : b->wbps = CGROUP_LIMIT_MAX;
3798 : :
3799 [ # # # # ]: 0 : LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3800 : : }
3801 : :
3802 [ # # ]: 0 : if (read)
3803 : 0 : b->rbps = bytes;
3804 : : else
3805 : 0 : b->wbps = bytes;
3806 : :
3807 : 0 : return 0;
3808 : : }
3809 : :
3810 : 0 : int config_parse_job_mode_isolate(
3811 : : const char *unit,
3812 : : const char *filename,
3813 : : unsigned line,
3814 : : const char *section,
3815 : : unsigned section_line,
3816 : : const char *lvalue,
3817 : : int ltype,
3818 : : const char *rvalue,
3819 : : void *data,
3820 : : void *userdata) {
3821 : :
3822 : 0 : JobMode *m = data;
3823 : : int r;
3824 : :
3825 [ # # ]: 0 : assert(filename);
3826 [ # # ]: 0 : assert(lvalue);
3827 [ # # ]: 0 : assert(rvalue);
3828 : :
3829 : 0 : r = parse_boolean(rvalue);
3830 [ # # ]: 0 : if (r < 0) {
3831 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
3832 : 0 : return 0;
3833 : : }
3834 : :
3835 [ # # ]: 0 : log_notice("%s is deprecated. Please use OnFailureJobMode= instead", lvalue);
3836 : :
3837 [ # # ]: 0 : *m = r ? JOB_ISOLATE : JOB_REPLACE;
3838 : 0 : return 0;
3839 : : }
3840 : :
3841 : 0 : int config_parse_exec_directories(
3842 : : const char *unit,
3843 : : const char *filename,
3844 : : unsigned line,
3845 : : const char *section,
3846 : : unsigned section_line,
3847 : : const char *lvalue,
3848 : : int ltype,
3849 : : const char *rvalue,
3850 : : void *data,
3851 : : void *userdata) {
3852 : :
3853 : 0 : char***rt = data;
3854 : 0 : Unit *u = userdata;
3855 : : const char *p;
3856 : : int r;
3857 : :
3858 [ # # ]: 0 : assert(filename);
3859 [ # # ]: 0 : assert(lvalue);
3860 [ # # ]: 0 : assert(rvalue);
3861 [ # # ]: 0 : assert(data);
3862 : :
3863 [ # # ]: 0 : if (isempty(rvalue)) {
3864 : : /* Empty assignment resets the list */
3865 : 0 : *rt = strv_free(*rt);
3866 : 0 : return 0;
3867 : : }
3868 : :
3869 : 0 : for (p = rvalue;;) {
3870 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *k = NULL;
# # ]
3871 : :
3872 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3873 [ # # ]: 0 : if (r == -ENOMEM)
3874 : 0 : return log_oom();
3875 [ # # ]: 0 : if (r < 0) {
3876 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, r,
3877 : : "Invalid syntax, ignoring: %s", rvalue);
3878 : 0 : return 0;
3879 : : }
3880 [ # # ]: 0 : if (r == 0)
3881 : 0 : return 0;
3882 : :
3883 : 0 : r = unit_full_printf(u, word, &k);
3884 [ # # ]: 0 : if (r < 0) {
3885 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
3886 : : "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
3887 : 0 : continue;
3888 : : }
3889 : :
3890 : 0 : r = path_simplify_and_warn(k, PATH_CHECK_RELATIVE, unit, filename, line, lvalue);
3891 [ # # ]: 0 : if (r < 0)
3892 : 0 : continue;
3893 : :
3894 [ # # ]: 0 : if (path_startswith(k, "private")) {
3895 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
3896 : : "%s= path can't be 'private', ignoring assignment: %s", lvalue, word);
3897 : 0 : continue;
3898 : : }
3899 : :
3900 : 0 : r = strv_push(rt, k);
3901 [ # # ]: 0 : if (r < 0)
3902 : 0 : return log_oom();
3903 : 0 : k = NULL;
3904 : : }
3905 : : }
3906 : :
3907 : 0 : int config_parse_set_status(
3908 : : const char *unit,
3909 : : const char *filename,
3910 : : unsigned line,
3911 : : const char *section,
3912 : : unsigned section_line,
3913 : : const char *lvalue,
3914 : : int ltype,
3915 : : const char *rvalue,
3916 : : void *data,
3917 : : void *userdata) {
3918 : :
3919 : : size_t l;
3920 : : const char *word, *state;
3921 : : int r;
3922 : 0 : ExitStatusSet *status_set = data;
3923 : :
3924 [ # # ]: 0 : assert(filename);
3925 [ # # ]: 0 : assert(lvalue);
3926 [ # # ]: 0 : assert(rvalue);
3927 [ # # ]: 0 : assert(data);
3928 : :
3929 : : /* Empty assignment resets the list */
3930 [ # # ]: 0 : if (isempty(rvalue)) {
3931 : 0 : exit_status_set_free(status_set);
3932 : 0 : return 0;
3933 : : }
3934 : :
3935 [ # # ]: 0 : FOREACH_WORD(word, l, rvalue, state) {
3936 [ # # # ]: 0 : _cleanup_free_ char *temp;
3937 : : Bitmap *bitmap;
3938 : :
3939 : 0 : temp = strndup(word, l);
3940 [ # # ]: 0 : if (!temp)
3941 : 0 : return log_oom();
3942 : :
3943 : : /* We need to call exit_status_from_string() first, because we want
3944 : : * to parse numbers as exit statuses, not signals. */
3945 : :
3946 : 0 : r = exit_status_from_string(temp);
3947 [ # # ]: 0 : if (r >= 0) {
3948 [ # # # # ]: 0 : assert(r >= 0 && r < 256);
3949 : 0 : bitmap = &status_set->status;
3950 : : } else {
3951 : 0 : r = signal_from_string(temp);
3952 : :
3953 [ # # ]: 0 : if (r <= 0) {
3954 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
3955 : : "Failed to parse value, ignoring: %s", word);
3956 : 0 : continue;
3957 : : }
3958 : 0 : bitmap = &status_set->signal;
3959 : : }
3960 : :
3961 : 0 : r = bitmap_set(bitmap, r);
3962 [ # # ]: 0 : if (r < 0)
3963 [ # # ]: 0 : return log_error_errno(r, "Failed to set signal or status %s: %m", word);
3964 : : }
3965 [ # # ]: 0 : if (!isempty(state))
3966 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3967 : :
3968 : 0 : return 0;
3969 : : }
3970 : :
3971 : 0 : int config_parse_namespace_path_strv(
3972 : : const char *unit,
3973 : : const char *filename,
3974 : : unsigned line,
3975 : : const char *section,
3976 : : unsigned section_line,
3977 : : const char *lvalue,
3978 : : int ltype,
3979 : : const char *rvalue,
3980 : : void *data,
3981 : : void *userdata) {
3982 : :
3983 : 0 : Unit *u = userdata;
3984 : 0 : char*** sv = data;
3985 : 0 : const char *p = rvalue;
3986 : : int r;
3987 : :
3988 [ # # ]: 0 : assert(filename);
3989 [ # # ]: 0 : assert(lvalue);
3990 [ # # ]: 0 : assert(rvalue);
3991 [ # # ]: 0 : assert(data);
3992 : :
3993 [ # # ]: 0 : if (isempty(rvalue)) {
3994 : : /* Empty assignment resets the list */
3995 : 0 : *sv = strv_free(*sv);
3996 : 0 : return 0;
3997 : : }
3998 : :
3999 : 0 : for (;;) {
4000 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
# # # # #
# # # ]
4001 : : const char *w;
4002 : 0 : bool ignore_enoent = false, shall_prefix = false;
4003 : :
4004 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
4005 [ # # ]: 0 : if (r == 0)
4006 : 0 : break;
4007 [ # # ]: 0 : if (r == -ENOMEM)
4008 : 0 : return log_oom();
4009 [ # # ]: 0 : if (r < 0) {
4010 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
4011 : 0 : return 0;
4012 : : }
4013 : :
4014 : 0 : w = word;
4015 [ # # ]: 0 : if (startswith(w, "-")) {
4016 : 0 : ignore_enoent = true;
4017 : 0 : w++;
4018 : : }
4019 [ # # ]: 0 : if (startswith(w, "+")) {
4020 : 0 : shall_prefix = true;
4021 : 0 : w++;
4022 : : }
4023 : :
4024 : 0 : r = unit_full_printf(u, w, &resolved);
4025 [ # # ]: 0 : if (r < 0) {
4026 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", w);
4027 : 0 : continue;
4028 : : }
4029 : :
4030 : 0 : r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
4031 [ # # ]: 0 : if (r < 0)
4032 : 0 : continue;
4033 : :
4034 [ # # # # ]: 0 : joined = strjoin(ignore_enoent ? "-" : "",
4035 : : shall_prefix ? "+" : "",
4036 : : resolved);
4037 : :
4038 : 0 : r = strv_push(sv, joined);
4039 [ # # ]: 0 : if (r < 0)
4040 : 0 : return log_oom();
4041 : :
4042 : 0 : joined = NULL;
4043 : : }
4044 : :
4045 : 0 : return 0;
4046 : : }
4047 : :
4048 : 0 : int config_parse_temporary_filesystems(
4049 : : const char *unit,
4050 : : const char *filename,
4051 : : unsigned line,
4052 : : const char *section,
4053 : : unsigned section_line,
4054 : : const char *lvalue,
4055 : : int ltype,
4056 : : const char *rvalue,
4057 : : void *data,
4058 : : void *userdata) {
4059 : :
4060 : 0 : Unit *u = userdata;
4061 : 0 : ExecContext *c = data;
4062 : 0 : const char *p = rvalue;
4063 : : int r;
4064 : :
4065 [ # # ]: 0 : assert(filename);
4066 [ # # ]: 0 : assert(lvalue);
4067 [ # # ]: 0 : assert(rvalue);
4068 [ # # ]: 0 : assert(data);
4069 : :
4070 [ # # ]: 0 : if (isempty(rvalue)) {
4071 : : /* Empty assignment resets the list */
4072 : 0 : temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
4073 : 0 : c->temporary_filesystems = NULL;
4074 : 0 : c->n_temporary_filesystems = 0;
4075 : 0 : return 0;
4076 : : }
4077 : :
4078 : 0 : for (;;) {
4079 [ # # # # : 0 : _cleanup_free_ char *word = NULL, *path = NULL, *resolved = NULL;
# # # #
# ]
4080 : : const char *w;
4081 : :
4082 : 0 : r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
4083 [ # # ]: 0 : if (r == 0)
4084 : 0 : return 0;
4085 [ # # ]: 0 : if (r == -ENOMEM)
4086 : 0 : return log_oom();
4087 [ # # ]: 0 : if (r < 0) {
4088 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
4089 : 0 : return 0;
4090 : : }
4091 : :
4092 : 0 : w = word;
4093 : 0 : r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
4094 [ # # ]: 0 : if (r == -ENOMEM)
4095 : 0 : return log_oom();
4096 [ # # ]: 0 : if (r < 0) {
4097 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", word);
4098 : 0 : continue;
4099 : : }
4100 [ # # ]: 0 : if (r == 0) {
4101 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", word);
4102 : 0 : continue;
4103 : : }
4104 : :
4105 : 0 : r = unit_full_printf(u, path, &resolved);
4106 [ # # ]: 0 : if (r < 0) {
4107 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", path);
4108 : 0 : continue;
4109 : : }
4110 : :
4111 : 0 : r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
4112 [ # # ]: 0 : if (r < 0)
4113 : 0 : continue;
4114 : :
4115 : 0 : r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, resolved, w);
4116 [ # # ]: 0 : if (r < 0)
4117 : 0 : return log_oom();
4118 : : }
4119 : : }
4120 : :
4121 : 0 : int config_parse_bind_paths(
4122 : : const char *unit,
4123 : : const char *filename,
4124 : : unsigned line,
4125 : : const char *section,
4126 : : unsigned section_line,
4127 : : const char *lvalue,
4128 : : int ltype,
4129 : : const char *rvalue,
4130 : : void *data,
4131 : : void *userdata) {
4132 : :
4133 : 0 : ExecContext *c = data;
4134 : 0 : Unit *u = userdata;
4135 : : const char *p;
4136 : : int r;
4137 : :
4138 [ # # ]: 0 : assert(filename);
4139 [ # # ]: 0 : assert(lvalue);
4140 [ # # ]: 0 : assert(rvalue);
4141 [ # # ]: 0 : assert(data);
4142 : :
4143 [ # # ]: 0 : if (isempty(rvalue)) {
4144 : : /* Empty assignment resets the list */
4145 : 0 : bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
4146 : 0 : c->bind_mounts = NULL;
4147 : 0 : c->n_bind_mounts = 0;
4148 : 0 : return 0;
4149 : : }
4150 : :
4151 : 0 : p = rvalue;
4152 : 0 : for (;;) {
4153 [ # # # # : 0 : _cleanup_free_ char *source = NULL, *destination = NULL;
# # # # ]
4154 [ # # # # : 0 : _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
# # # # ]
4155 : 0 : char *s = NULL, *d = NULL;
4156 : 0 : bool rbind = true, ignore_enoent = false;
4157 : :
4158 : 0 : r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
4159 [ # # ]: 0 : if (r == 0)
4160 : 0 : break;
4161 [ # # ]: 0 : if (r == -ENOMEM)
4162 : 0 : return log_oom();
4163 [ # # ]: 0 : if (r < 0) {
4164 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
4165 : 0 : return 0;
4166 : : }
4167 : :
4168 : 0 : r = unit_full_printf(u, source, &sresolved);
4169 [ # # ]: 0 : if (r < 0) {
4170 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
4171 : : "Failed to resolved unit specifiers in \"%s\", ignoring: %m", source);
4172 : 0 : continue;
4173 : : }
4174 : :
4175 : 0 : s = sresolved;
4176 [ # # ]: 0 : if (s[0] == '-') {
4177 : 0 : ignore_enoent = true;
4178 : 0 : s++;
4179 : : }
4180 : :
4181 : 0 : r = path_simplify_and_warn(s, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
4182 [ # # ]: 0 : if (r < 0)
4183 : 0 : continue;
4184 : :
4185 : : /* Optionally, the destination is specified. */
4186 [ # # # # ]: 0 : if (p && p[-1] == ':') {
4187 : 0 : r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
4188 [ # # ]: 0 : if (r == -ENOMEM)
4189 : 0 : return log_oom();
4190 [ # # ]: 0 : if (r < 0) {
4191 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
4192 : 0 : return 0;
4193 : : }
4194 [ # # ]: 0 : if (r == 0) {
4195 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':', ignoring: %s", s);
4196 : 0 : continue;
4197 : : }
4198 : :
4199 : 0 : r = unit_full_printf(u, destination, &dresolved);
4200 [ # # ]: 0 : if (r < 0) {
4201 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
4202 : : "Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
4203 : 0 : continue;
4204 : : }
4205 : :
4206 : 0 : r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
4207 [ # # ]: 0 : if (r < 0)
4208 : 0 : continue;
4209 : :
4210 : 0 : d = dresolved;
4211 : :
4212 : : /* Optionally, there's also a short option string specified */
4213 [ # # # # ]: 0 : if (p && p[-1] == ':') {
4214 [ # # # ]: 0 : _cleanup_free_ char *options = NULL;
4215 : :
4216 : 0 : r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
4217 [ # # ]: 0 : if (r == -ENOMEM)
4218 : 0 : return log_oom();
4219 [ # # ]: 0 : if (r < 0) {
4220 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4221 : 0 : return 0;
4222 : : }
4223 : :
4224 [ # # # # ]: 0 : if (isempty(options) || streq(options, "rbind"))
4225 : 0 : rbind = true;
4226 [ # # ]: 0 : else if (streq(options, "norbind"))
4227 : 0 : rbind = false;
4228 : : else {
4229 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
4230 : 0 : continue;
4231 : : }
4232 : : }
4233 : : } else
4234 : 0 : d = s;
4235 : :
4236 : 0 : r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
4237 : 0 : &(BindMount) {
4238 : : .source = s,
4239 : : .destination = d,
4240 : 0 : .read_only = !!strstr(lvalue, "ReadOnly"),
4241 : : .recursive = rbind,
4242 : : .ignore_enoent = ignore_enoent,
4243 : : });
4244 [ # # ]: 0 : if (r < 0)
4245 : 0 : return log_oom();
4246 : : }
4247 : :
4248 : 0 : return 0;
4249 : : }
4250 : :
4251 : 0 : int config_parse_job_timeout_sec(
4252 : : const char* unit,
4253 : : const char *filename,
4254 : : unsigned line,
4255 : : const char *section,
4256 : : unsigned section_line,
4257 : : const char *lvalue,
4258 : : int ltype,
4259 : : const char *rvalue,
4260 : : void *data,
4261 : : void *userdata) {
4262 : :
4263 : 0 : Unit *u = data;
4264 : : usec_t usec;
4265 : : int r;
4266 : :
4267 [ # # ]: 0 : assert(filename);
4268 [ # # ]: 0 : assert(lvalue);
4269 [ # # ]: 0 : assert(rvalue);
4270 [ # # ]: 0 : assert(u);
4271 : :
4272 : 0 : r = parse_sec_fix_0(rvalue, &usec);
4273 [ # # ]: 0 : if (r < 0) {
4274 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
4275 : 0 : return 0;
4276 : : }
4277 : :
4278 : : /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4279 : : * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4280 : : * count. */
4281 : :
4282 [ # # ]: 0 : if (!u->job_running_timeout_set)
4283 : 0 : u->job_running_timeout = usec;
4284 : :
4285 : 0 : u->job_timeout = usec;
4286 : :
4287 : 0 : return 0;
4288 : : }
4289 : :
4290 : 0 : int config_parse_job_running_timeout_sec(
4291 : : const char* unit,
4292 : : const char *filename,
4293 : : unsigned line,
4294 : : const char *section,
4295 : : unsigned section_line,
4296 : : const char *lvalue,
4297 : : int ltype,
4298 : : const char *rvalue,
4299 : : void *data,
4300 : : void *userdata) {
4301 : :
4302 : 0 : Unit *u = data;
4303 : : usec_t usec;
4304 : : int r;
4305 : :
4306 [ # # ]: 0 : assert(filename);
4307 [ # # ]: 0 : assert(lvalue);
4308 [ # # ]: 0 : assert(rvalue);
4309 [ # # ]: 0 : assert(u);
4310 : :
4311 : 0 : r = parse_sec_fix_0(rvalue, &usec);
4312 [ # # ]: 0 : if (r < 0) {
4313 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
4314 : 0 : return 0;
4315 : : }
4316 : :
4317 : 0 : u->job_running_timeout = usec;
4318 : 0 : u->job_running_timeout_set = true;
4319 : :
4320 : 0 : return 0;
4321 : : }
4322 : :
4323 : 0 : int config_parse_emergency_action(
4324 : : const char* unit,
4325 : : const char *filename,
4326 : : unsigned line,
4327 : : const char *section,
4328 : : unsigned section_line,
4329 : : const char *lvalue,
4330 : : int ltype,
4331 : : const char *rvalue,
4332 : : void *data,
4333 : : void *userdata) {
4334 : :
4335 : 0 : Manager *m = NULL;
4336 : 0 : EmergencyAction *x = data;
4337 : : int r;
4338 : :
4339 [ # # ]: 0 : assert(filename);
4340 [ # # ]: 0 : assert(lvalue);
4341 [ # # ]: 0 : assert(rvalue);
4342 [ # # ]: 0 : assert(data);
4343 : :
4344 [ # # ]: 0 : if (unit)
4345 : 0 : m = ((Unit*) userdata)->manager;
4346 : : else
4347 : 0 : m = data;
4348 : :
4349 : 0 : r = parse_emergency_action(rvalue, MANAGER_IS_SYSTEM(m), x);
4350 [ # # ]: 0 : if (r < 0) {
4351 [ # # # # ]: 0 : if (r == -EOPNOTSUPP && MANAGER_IS_USER(m)) {
4352 : : /* Compat mode: remove for systemd 241. */
4353 : :
4354 [ # # ]: 0 : log_syntax(unit, LOG_INFO, filename, line, r,
4355 : : "%s= in user mode specified as \"%s\", using \"exit-force\" instead.",
4356 : : lvalue, rvalue);
4357 : 0 : *x = EMERGENCY_ACTION_EXIT_FORCE;
4358 : 0 : return 0;
4359 : : }
4360 : :
4361 [ # # ]: 0 : if (r == -EOPNOTSUPP)
4362 [ # # # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
4363 : : "%s= specified as %s mode action, ignoring: %s",
4364 : : lvalue, MANAGER_IS_SYSTEM(m) ? "user" : "system", rvalue);
4365 : : else
4366 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
4367 : : "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
4368 : 0 : return 0;
4369 : : }
4370 : :
4371 : 0 : return 0;
4372 : : }
4373 : :
4374 : 0 : int config_parse_pid_file(
4375 : : const char *unit,
4376 : : const char *filename,
4377 : : unsigned line,
4378 : : const char *section,
4379 : : unsigned section_line,
4380 : : const char *lvalue,
4381 : : int ltype,
4382 : : const char *rvalue,
4383 : : void *data,
4384 : : void *userdata) {
4385 : :
4386 : 0 : _cleanup_free_ char *k = NULL, *n = NULL;
4387 : 0 : Unit *u = userdata;
4388 : 0 : char **s = data;
4389 : : int r;
4390 : :
4391 [ # # ]: 0 : assert(filename);
4392 [ # # ]: 0 : assert(lvalue);
4393 [ # # ]: 0 : assert(rvalue);
4394 [ # # ]: 0 : assert(u);
4395 : :
4396 [ # # ]: 0 : if (isempty(rvalue)) {
4397 : : /* An empty assignment removes already set value. */
4398 : 0 : *s = mfree(*s);
4399 : 0 : return 0;
4400 : : }
4401 : :
4402 : 0 : r = unit_full_printf(u, rvalue, &k);
4403 [ # # ]: 0 : if (r < 0) {
4404 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
4405 : 0 : return 0;
4406 : : }
4407 : :
4408 : : /* If this is a relative path make it absolute by prefixing the /run */
4409 : 0 : n = path_make_absolute(k, u->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
4410 [ # # ]: 0 : if (!n)
4411 : 0 : return log_oom();
4412 : :
4413 : : /* Check that the result is a sensible path */
4414 : 0 : r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
4415 [ # # ]: 0 : if (r < 0)
4416 : 0 : return r;
4417 : :
4418 : 0 : r = patch_var_run(unit, filename, line, lvalue, &n);
4419 [ # # ]: 0 : if (r < 0)
4420 : 0 : return r;
4421 : :
4422 : 0 : free_and_replace(*s, n);
4423 : 0 : return 0;
4424 : : }
4425 : :
4426 : 0 : int config_parse_exit_status(
4427 : : const char *unit,
4428 : : const char *filename,
4429 : : unsigned line,
4430 : : const char *section,
4431 : : unsigned section_line,
4432 : : const char *lvalue,
4433 : : int ltype,
4434 : : const char *rvalue,
4435 : : void *data,
4436 : : void *userdata) {
4437 : :
4438 : 0 : int *exit_status = data, r;
4439 : : uint8_t u;
4440 : :
4441 [ # # ]: 0 : assert(filename);
4442 [ # # ]: 0 : assert(lvalue);
4443 [ # # ]: 0 : assert(rvalue);
4444 [ # # ]: 0 : assert(exit_status);
4445 : :
4446 [ # # ]: 0 : if (isempty(rvalue)) {
4447 : 0 : *exit_status = -1;
4448 : 0 : return 0;
4449 : : }
4450 : :
4451 : 0 : r = safe_atou8(rvalue, &u);
4452 [ # # ]: 0 : if (r < 0) {
4453 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse exit status '%s', ignoring: %m", rvalue);
4454 : 0 : return 0;
4455 : : }
4456 : :
4457 : 0 : *exit_status = u;
4458 : 0 : return 0;
4459 : : }
4460 : :
4461 : 4 : int config_parse_disable_controllers(
4462 : : const char *unit,
4463 : : const char *filename,
4464 : : unsigned line,
4465 : : const char *section,
4466 : : unsigned section_line,
4467 : : const char *lvalue,
4468 : : int ltype,
4469 : : const char *rvalue,
4470 : : void *data,
4471 : : void *userdata) {
4472 : :
4473 : : int r;
4474 : 4 : CGroupContext *c = data;
4475 : : CGroupMask disabled_mask;
4476 : :
4477 : : /* 1. If empty, make all controllers eligible for use again.
4478 : : * 2. If non-empty, merge all listed controllers, space separated. */
4479 : :
4480 [ - + ]: 4 : if (isempty(rvalue)) {
4481 : 0 : c->disable_controllers = 0;
4482 : 0 : return 0;
4483 : : }
4484 : :
4485 : 4 : r = cg_mask_from_string(rvalue, &disabled_mask);
4486 [ + - - + ]: 4 : if (r < 0 || disabled_mask <= 0) {
4487 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Invalid cgroup string: %s, ignoring", rvalue);
4488 : 0 : return 0;
4489 : : }
4490 : :
4491 : 4 : c->disable_controllers |= disabled_mask;
4492 : :
4493 : 4 : return 0;
4494 : : }
4495 : :
4496 : 0 : int config_parse_ip_filter_bpf_progs(
4497 : : const char *unit,
4498 : : const char *filename,
4499 : : unsigned line,
4500 : : const char *section,
4501 : : unsigned section_line,
4502 : : const char *lvalue,
4503 : : int ltype,
4504 : : const char *rvalue,
4505 : : void *data,
4506 : : void *userdata) {
4507 : :
4508 : 0 : _cleanup_free_ char *resolved = NULL;
4509 : 0 : Unit *u = userdata;
4510 : 0 : char ***paths = data;
4511 : : int r;
4512 : :
4513 [ # # ]: 0 : assert(filename);
4514 [ # # ]: 0 : assert(lvalue);
4515 [ # # ]: 0 : assert(rvalue);
4516 [ # # ]: 0 : assert(paths);
4517 : :
4518 [ # # ]: 0 : if (isempty(rvalue)) {
4519 : 0 : *paths = strv_free(*paths);
4520 : 0 : return 0;
4521 : : }
4522 : :
4523 : 0 : r = unit_full_printf(u, rvalue, &resolved);
4524 [ # # ]: 0 : if (r < 0) {
4525 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
4526 : 0 : return 0;
4527 : : }
4528 : :
4529 : 0 : r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
4530 [ # # ]: 0 : if (r < 0)
4531 : 0 : return 0;
4532 : :
4533 [ # # ]: 0 : if (strv_contains(*paths, resolved))
4534 : 0 : return 0;
4535 : :
4536 : 0 : r = strv_extend(paths, resolved);
4537 [ # # ]: 0 : if (r < 0)
4538 : 0 : return log_oom();
4539 : :
4540 : 0 : r = bpf_firewall_supported();
4541 [ # # ]: 0 : if (r < 0)
4542 : 0 : return r;
4543 [ # # ]: 0 : if (r != BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
4544 : : static bool warned = false;
4545 : :
4546 [ # # # # ]: 0 : log_full(warned ? LOG_DEBUG : LOG_WARNING,
4547 : : "File %s:%u configures an IP firewall with BPF programs (%s=%s), but the local system does not support BPF/cgroup based firewalling with multiple filters.\n"
4548 : : "Starting this unit will fail! (This warning is only shown for the first loaded unit using IP firewalling.)", filename, line, lvalue, rvalue);
4549 : :
4550 : 0 : warned = true;
4551 : : }
4552 : :
4553 : 0 : return 0;
4554 : : }
4555 : :
4556 : 8664 : static int merge_by_names(Unit **u, Set *names, const char *id) {
4557 : : char *k;
4558 : : int r;
4559 : :
4560 [ - + ]: 8664 : assert(u);
4561 [ - + ]: 8664 : assert(*u);
4562 : :
4563 : : /* Let's try to add in all names that are aliases of this unit */
4564 [ + + ]: 17472 : while ((k = set_steal_first(names))) {
4565 [ + - ]: 8808 : _cleanup_free_ _unused_ char *free_k = k;
4566 : :
4567 : : /* First try to merge in the other name into our unit */
4568 : 8808 : r = unit_merge_by_name(*u, k);
4569 [ - + ]: 8808 : if (r < 0) {
4570 : : Unit *other;
4571 : :
4572 : : /* Hmm, we couldn't merge the other unit into ours? Then let's try it the other way
4573 : : * round. */
4574 : :
4575 : 0 : other = manager_get_unit((*u)->manager, k);
4576 [ # # ]: 0 : if (!other)
4577 : 0 : return r; /* return previous failure */
4578 : :
4579 : 0 : r = unit_merge(other, *u);
4580 [ # # ]: 0 : if (r < 0)
4581 : 0 : return r;
4582 : :
4583 : 0 : *u = other;
4584 : 0 : return merge_by_names(u, names, NULL);
4585 : : }
4586 : :
4587 [ + + ]: 8808 : if (streq_ptr(id, k))
4588 : 8664 : unit_choose_id(*u, id);
4589 : : }
4590 : :
4591 : 8664 : return 0;
4592 : : }
4593 : :
4594 : 8708 : int unit_load_fragment(Unit *u) {
4595 : : const char *fragment;
4596 : 8708 : _cleanup_set_free_free_ Set *names = NULL;
4597 : : int r;
4598 : :
4599 [ - + ]: 8708 : assert(u);
4600 [ - + ]: 8708 : assert(u->load_state == UNIT_STUB);
4601 [ - + ]: 8708 : assert(u->id);
4602 : :
4603 [ + + ]: 8708 : if (u->transient) {
4604 : 44 : u->load_state = UNIT_LOADED;
4605 : 44 : return 0;
4606 : : }
4607 : :
4608 : : /* Possibly rebuild the fragment map to catch new units */
4609 : 34656 : r = unit_file_build_name_map(&u->manager->lookup_paths,
4610 : 8664 : &u->manager->unit_cache_mtime,
4611 : 8664 : &u->manager->unit_id_map,
4612 : 8664 : &u->manager->unit_name_map,
4613 : 8664 : &u->manager->unit_path_cache);
4614 [ - + ]: 8664 : if (r < 0)
4615 [ # # ]: 0 : log_error_errno(r, "Failed to rebuild name map: %m");
4616 : :
4617 : 8664 : r = unit_file_find_fragment(u->manager->unit_id_map,
4618 : 8664 : u->manager->unit_name_map,
4619 : 8664 : u->id,
4620 : : &fragment,
4621 : : &names);
4622 [ - + # # ]: 8664 : if (r < 0 && r != -ENOENT)
4623 : 0 : return r;
4624 : :
4625 [ + + ]: 8664 : if (fragment) {
4626 : : /* Open the file, check if this is a mask, otherwise read. */
4627 [ + - ]: 352 : _cleanup_fclose_ FILE *f = NULL;
4628 : : struct stat st;
4629 : :
4630 : : /* Try to open the file name. A symlink is OK, for example for linked files or masks. We
4631 : : * expect that all symlinks within the lookup paths have been already resolved, but we don't
4632 : : * verify this here. */
4633 : 352 : f = fopen(fragment, "re");
4634 [ - + ]: 352 : if (!f)
4635 [ # # ]: 0 : return log_unit_notice_errno(u, errno, "Failed to open %s: %m", fragment);
4636 : :
4637 [ - + ]: 352 : if (fstat(fileno(f), &st) < 0)
4638 : 0 : return -errno;
4639 : :
4640 : 352 : r = free_and_strdup(&u->fragment_path, fragment);
4641 [ - + ]: 352 : if (r < 0)
4642 : 0 : return r;
4643 : :
4644 [ - + ]: 352 : if (null_or_empty(&st)) {
4645 : 0 : u->load_state = UNIT_MASKED;
4646 : 0 : u->fragment_mtime = 0;
4647 : : } else {
4648 : 352 : u->load_state = UNIT_LOADED;
4649 : 352 : u->fragment_mtime = timespec_load(&st.st_mtim);
4650 : :
4651 : : /* Now, parse the file contents */
4652 : 352 : r = config_parse(u->id, fragment, f,
4653 : 352 : UNIT_VTABLE(u)->sections,
4654 : : config_item_perf_lookup, load_fragment_gperf_lookup,
4655 : : CONFIG_PARSE_ALLOW_INCLUDE, u);
4656 [ - + ]: 352 : if (r == -ENOEXEC)
4657 [ # # ]: 0 : log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started.");
4658 [ - + ]: 352 : if (r < 0)
4659 : 0 : return r;
4660 : : }
4661 : : }
4662 : :
4663 : : /* We do the merge dance here because for some unit types, the unit might have aliases which are not
4664 : : * declared in the file system. In particular, this is true (and frequent) for device and swap units.
4665 : : */
4666 : : Unit *merged;
4667 : 8664 : const char *id = u->id;
4668 : 8664 : _cleanup_free_ char *free_id = NULL;
4669 : :
4670 [ + + ]: 8664 : if (fragment) {
4671 : 352 : id = basename(fragment);
4672 [ - + ]: 352 : if (unit_name_is_valid(id, UNIT_NAME_TEMPLATE)) {
4673 [ # # ]: 0 : assert(u->instance); /* If we're not trying to use a template for non-instanced unit,
4674 : : * this must be set. */
4675 : :
4676 : 0 : r = unit_name_replace_instance(id, u->instance, &free_id);
4677 [ # # ]: 0 : if (r < 0)
4678 [ # # ]: 0 : return log_debug_errno(r, "Failed to build id (%s + %s): %m", id, u->instance);
4679 : 0 : id = free_id;
4680 : : }
4681 : : }
4682 : :
4683 : 8664 : merged = u;
4684 : 8664 : r = merge_by_names(&merged, names, id);
4685 [ - + ]: 8664 : if (r < 0)
4686 : 0 : return r;
4687 : :
4688 [ - + ]: 8664 : if (merged != u)
4689 : 0 : u->load_state = UNIT_MERGED;
4690 : :
4691 : 8664 : return 0;
4692 : : }
4693 : :
4694 : 4 : void unit_dump_config_items(FILE *f) {
4695 : : static const struct {
4696 : : const ConfigParserCallback callback;
4697 : : const char *rvalue;
4698 : : } table[] = {
4699 : : { config_parse_warn_compat, "NOTSUPPORTED" },
4700 : : { config_parse_int, "INTEGER" },
4701 : : { config_parse_unsigned, "UNSIGNED" },
4702 : : { config_parse_iec_size, "SIZE" },
4703 : : { config_parse_iec_uint64, "SIZE" },
4704 : : { config_parse_si_size, "SIZE" },
4705 : : { config_parse_bool, "BOOLEAN" },
4706 : : { config_parse_string, "STRING" },
4707 : : { config_parse_path, "PATH" },
4708 : : { config_parse_unit_path_printf, "PATH" },
4709 : : { config_parse_strv, "STRING [...]" },
4710 : : { config_parse_exec_nice, "NICE" },
4711 : : { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4712 : : { config_parse_exec_io_class, "IOCLASS" },
4713 : : { config_parse_exec_io_priority, "IOPRIORITY" },
4714 : : { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4715 : : { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4716 : : { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4717 : : { config_parse_mode, "MODE" },
4718 : : { config_parse_unit_env_file, "FILE" },
4719 : : { config_parse_exec_output, "OUTPUT" },
4720 : : { config_parse_exec_input, "INPUT" },
4721 : : { config_parse_log_facility, "FACILITY" },
4722 : : { config_parse_log_level, "LEVEL" },
4723 : : { config_parse_exec_secure_bits, "SECUREBITS" },
4724 : : { config_parse_capability_set, "BOUNDINGSET" },
4725 : : { config_parse_rlimit, "LIMIT" },
4726 : : { config_parse_unit_deps, "UNIT [...]" },
4727 : : { config_parse_exec, "PATH [ARGUMENT [...]]" },
4728 : : { config_parse_service_type, "SERVICETYPE" },
4729 : : { config_parse_service_restart, "SERVICERESTART" },
4730 : : { config_parse_kill_mode, "KILLMODE" },
4731 : : { config_parse_signal, "SIGNAL" },
4732 : : { config_parse_socket_listen, "SOCKET [...]" },
4733 : : { config_parse_socket_bind, "SOCKETBIND" },
4734 : : { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
4735 : : { config_parse_sec, "SECONDS" },
4736 : : { config_parse_nsec, "NANOSECONDS" },
4737 : : { config_parse_namespace_path_strv, "PATH [...]" },
4738 : : { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
4739 : : { config_parse_unit_requires_mounts_for, "PATH [...]" },
4740 : : { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4741 : : { config_parse_unit_string_printf, "STRING" },
4742 : : { config_parse_trigger_unit, "UNIT" },
4743 : : { config_parse_timer, "TIMER" },
4744 : : { config_parse_path_spec, "PATH" },
4745 : : { config_parse_notify_access, "ACCESS" },
4746 : : { config_parse_ip_tos, "TOS" },
4747 : : { config_parse_unit_condition_path, "CONDITION" },
4748 : : { config_parse_unit_condition_string, "CONDITION" },
4749 : : { config_parse_unit_condition_null, "CONDITION" },
4750 : : { config_parse_unit_slice, "SLICE" },
4751 : : { config_parse_documentation, "URL" },
4752 : : { config_parse_service_timeout, "SECONDS" },
4753 : : { config_parse_emergency_action, "ACTION" },
4754 : : { config_parse_set_status, "STATUS" },
4755 : : { config_parse_service_sockets, "SOCKETS" },
4756 : : { config_parse_environ, "ENVIRON" },
4757 : : #if HAVE_SECCOMP
4758 : : { config_parse_syscall_filter, "SYSCALLS" },
4759 : : { config_parse_syscall_archs, "ARCHS" },
4760 : : { config_parse_syscall_errno, "ERRNO" },
4761 : : { config_parse_address_families, "FAMILIES" },
4762 : : { config_parse_restrict_namespaces, "NAMESPACES" },
4763 : : #endif
4764 : : { config_parse_cpu_shares, "SHARES" },
4765 : : { config_parse_cg_weight, "WEIGHT" },
4766 : : { config_parse_memory_limit, "LIMIT" },
4767 : : { config_parse_device_allow, "DEVICE" },
4768 : : { config_parse_device_policy, "POLICY" },
4769 : : { config_parse_io_limit, "LIMIT" },
4770 : : { config_parse_io_device_weight, "DEVICEWEIGHT" },
4771 : : { config_parse_io_device_latency, "DEVICELATENCY" },
4772 : : { config_parse_blockio_bandwidth, "BANDWIDTH" },
4773 : : { config_parse_blockio_weight, "WEIGHT" },
4774 : : { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4775 : : { config_parse_long, "LONG" },
4776 : : { config_parse_socket_service, "SERVICE" },
4777 : : #if HAVE_SELINUX
4778 : : { config_parse_exec_selinux_context, "LABEL" },
4779 : : #endif
4780 : : { config_parse_job_mode, "MODE" },
4781 : : { config_parse_job_mode_isolate, "BOOLEAN" },
4782 : : { config_parse_personality, "PERSONALITY" },
4783 : : };
4784 : :
4785 : 4 : const char *prev = NULL;
4786 : : const char *i;
4787 : :
4788 [ - + ]: 4 : assert(f);
4789 : :
4790 [ + - + + ]: 3928 : NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4791 : 3924 : const char *rvalue = "OTHER", *lvalue;
4792 : : const ConfigPerfItem *p;
4793 : : size_t prefix_len;
4794 : : const char *dot;
4795 : : unsigned j;
4796 : :
4797 [ - + ]: 3924 : assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4798 : :
4799 : : /* Hide legacy settings */
4800 [ + + ]: 3924 : if (p->parse == config_parse_warn_compat &&
4801 [ + + ]: 68 : p->ltype == DISABLED_LEGACY)
4802 : 52 : continue;
4803 : :
4804 [ + + ]: 166220 : for (j = 0; j < ELEMENTSOF(table); j++)
4805 [ + + ]: 165532 : if (p->parse == table[j].callback) {
4806 : 3184 : rvalue = table[j].rvalue;
4807 : 3184 : break;
4808 : : }
4809 : :
4810 : 3872 : dot = strchr(i, '.');
4811 [ + - ]: 3872 : lvalue = dot ? dot + 1 : i;
4812 : 3872 : prefix_len = dot-i;
4813 : :
4814 [ + - ]: 3872 : if (dot)
4815 [ + + + + ]: 3872 : if (!prev || !strneq(prev, i, prefix_len+1)) {
4816 [ + + ]: 44 : if (prev)
4817 : 40 : fputc('\n', f);
4818 : :
4819 : 44 : fprintf(f, "[%.*s]\n", (int) prefix_len, i);
4820 : : }
4821 : :
4822 : 3872 : fprintf(f, "%s=%s\n", lvalue, rvalue);
4823 : 3872 : prev = i;
4824 : : }
4825 : 4 : }
4826 : :
4827 : 0 : int config_parse_cpu_affinity2(
4828 : : const char *unit,
4829 : : const char *filename,
4830 : : unsigned line,
4831 : : const char *section,
4832 : : unsigned section_line,
4833 : : const char *lvalue,
4834 : : int ltype,
4835 : : const char *rvalue,
4836 : : void *data,
4837 : : void *userdata) {
4838 : :
4839 : 0 : CPUSet *affinity = data;
4840 : :
4841 [ # # ]: 0 : assert(affinity);
4842 : :
4843 : 0 : (void) parse_cpu_set_extend(rvalue, affinity, true, unit, filename, line, lvalue);
4844 : :
4845 : 0 : return 0;
4846 : : }
4847 : :
4848 : 0 : int config_parse_show_status(
4849 : : const char* unit,
4850 : : const char *filename,
4851 : : unsigned line,
4852 : : const char *section,
4853 : : unsigned section_line,
4854 : : const char *lvalue,
4855 : : int ltype,
4856 : : const char *rvalue,
4857 : : void *data,
4858 : : void *userdata) {
4859 : :
4860 : : int k;
4861 : 0 : ShowStatus *b = data;
4862 : :
4863 [ # # ]: 0 : assert(filename);
4864 [ # # ]: 0 : assert(lvalue);
4865 [ # # ]: 0 : assert(rvalue);
4866 [ # # ]: 0 : assert(data);
4867 : :
4868 : 0 : k = parse_show_status(rvalue, b);
4869 [ # # ]: 0 : if (k < 0) {
4870 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue);
4871 : 0 : return 0;
4872 : : }
4873 : :
4874 : 0 : return 0;
4875 : : }
4876 : :
4877 : 0 : int config_parse_output_restricted(
4878 : : const char* unit,
4879 : : const char *filename,
4880 : : unsigned line,
4881 : : const char *section,
4882 : : unsigned section_line,
4883 : : const char *lvalue,
4884 : : int ltype,
4885 : : const char *rvalue,
4886 : : void *data,
4887 : : void *userdata) {
4888 : :
4889 : 0 : ExecOutput t, *eo = data;
4890 : :
4891 [ # # ]: 0 : assert(filename);
4892 [ # # ]: 0 : assert(lvalue);
4893 [ # # ]: 0 : assert(rvalue);
4894 [ # # ]: 0 : assert(data);
4895 : :
4896 : 0 : t = exec_output_from_string(rvalue);
4897 [ # # ]: 0 : if (t < 0) {
4898 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output type, ignoring: %s", rvalue);
4899 : 0 : return 0;
4900 : : }
4901 : :
4902 [ # # # # ]: 0 : if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
4903 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
4904 : 0 : return 0;
4905 : : }
4906 : :
4907 : 0 : *eo = t;
4908 : 0 : return 0;
4909 : : }
4910 : :
4911 : 0 : int config_parse_crash_chvt(
4912 : : const char* unit,
4913 : : const char *filename,
4914 : : unsigned line,
4915 : : const char *section,
4916 : : unsigned section_line,
4917 : : const char *lvalue,
4918 : : int ltype,
4919 : : const char *rvalue,
4920 : : void *data,
4921 : : void *userdata) {
4922 : :
4923 : : int r;
4924 : :
4925 [ # # ]: 0 : assert(filename);
4926 [ # # ]: 0 : assert(lvalue);
4927 [ # # ]: 0 : assert(rvalue);
4928 [ # # ]: 0 : assert(data);
4929 : :
4930 : 0 : r = parse_crash_chvt(rvalue, data);
4931 [ # # ]: 0 : if (r < 0) {
4932 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue);
4933 : 0 : return 0;
4934 : : }
4935 : :
4936 : 0 : return 0;
4937 : : }
4938 : :
4939 : 0 : int config_parse_timeout_abort(
4940 : : const char* unit,
4941 : : const char *filename,
4942 : : unsigned line,
4943 : : const char *section,
4944 : : unsigned section_line,
4945 : : const char *lvalue,
4946 : : int ltype,
4947 : : const char *rvalue,
4948 : : void *data,
4949 : : void *userdata) {
4950 : :
4951 : 0 : usec_t *timeout_usec = data;
4952 : : int r;
4953 : :
4954 [ # # ]: 0 : assert(filename);
4955 [ # # ]: 0 : assert(lvalue);
4956 [ # # ]: 0 : assert(rvalue);
4957 [ # # ]: 0 : assert(timeout_usec);
4958 : :
4959 : 0 : rvalue += strspn(rvalue, WHITESPACE);
4960 [ # # ]: 0 : if (isempty(rvalue)) {
4961 : 0 : *timeout_usec = false;
4962 : 0 : return 0;
4963 : : }
4964 : :
4965 : 0 : r = parse_sec(rvalue, timeout_usec);
4966 [ # # ]: 0 : if (r < 0) {
4967 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DefaultTimeoutAbortSec= setting, ignoring: %s", rvalue);
4968 : 0 : return 0;
4969 : : }
4970 : :
4971 : 0 : *timeout_usec = true;
4972 : 0 : return 0;
4973 : : }
|