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