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