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