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