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