]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
core: add specifier expansion to RequiresMountsFor=
[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"
6bedfcbb 52#include "parse-util.h"
9eb977db 53#include "path-util.h"
7b3e062c 54#include "process-util.h"
d0a7c5f6 55#include "rlimit-util.h"
57183d11
LP
56#ifdef HAVE_SECCOMP
57#include "seccomp-util.h"
58#endif
5f5d8eab
LP
59#include "securebits.h"
60#include "signal-util.h"
8fcde012 61#include "stat-util.h"
07630cea 62#include "string-util.h"
5f5d8eab
LP
63#include "strv.h"
64#include "unit-name.h"
65#include "unit-printf.h"
66#include "unit.h"
66dccd8d 67#include "user-util.h"
5f5d8eab 68#include "utf8.h"
49cf4170 69#include "web-util.h"
57183d11 70
17df7223
LP
71int config_parse_warn_compat(
72 const char *unit,
73 const char *filename,
74 unsigned line,
75 const char *section,
76 unsigned section_line,
77 const char *lvalue,
78 int ltype,
79 const char *rvalue,
80 void *data,
81 void *userdata) {
a2c0e528
ZJS
82 Disabled reason = ltype;
83
84 switch(reason) {
85 case DISABLED_CONFIGURATION:
12ca818f 86 log_syntax(unit, LOG_DEBUG, filename, line, 0,
a2c0e528
ZJS
87 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
88 break;
9e37c954 89 case DISABLED_LEGACY:
12ca818f 90 log_syntax(unit, LOG_INFO, filename, line, 0,
9e37c954
ZJS
91 "Support for option %s= has been removed and it is ignored", lvalue);
92 break;
a2c0e528 93 case DISABLED_EXPERIMENTAL:
12ca818f 94 log_syntax(unit, LOG_INFO, filename, line, 0,
a2c0e528
ZJS
95 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
96 break;
97 };
e8e581bf 98
07459bb6
FF
99 return 0;
100}
07459bb6 101
f32b43bd
LP
102int config_parse_unit_deps(
103 const char *unit,
104 const char *filename,
105 unsigned line,
106 const char *section,
107 unsigned section_line,
108 const char *lvalue,
109 int ltype,
110 const char *rvalue,
111 void *data,
112 void *userdata) {
3efd4195 113
f975e971 114 UnitDependency d = ltype;
87f0e418 115 Unit *u = userdata;
3d793d29 116 const char *p;
3efd4195
LP
117
118 assert(filename);
119 assert(lvalue);
120 assert(rvalue);
3efd4195 121
3d793d29 122 p = rvalue;
9ed794a3 123 for (;;) {
3d793d29 124 _cleanup_free_ char *word = NULL, *k = NULL;
3efd4195 125 int r;
3efd4195 126
c89f52ac 127 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
3d793d29
SS
128 if (r == 0)
129 break;
130 if (r == -ENOMEM)
74051b9b 131 return log_oom();
3d793d29
SS
132 if (r < 0) {
133 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
134 break;
135 }
3efd4195 136
3d793d29 137 r = unit_name_printf(u, word, &k);
19f6d710 138 if (r < 0) {
12ca818f 139 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
19f6d710
LP
140 continue;
141 }
9e2f7c11 142
701cc384 143 r = unit_add_dependency_by_name(u, d, k, NULL, true);
57020a3a 144 if (r < 0)
12ca818f 145 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
3efd4195
LP
146 }
147
148 return 0;
149}
150
f32b43bd
LP
151int config_parse_obsolete_unit_deps(
152 const char *unit,
153 const char *filename,
154 unsigned line,
155 const char *section,
156 unsigned section_line,
157 const char *lvalue,
158 int ltype,
159 const char *rvalue,
160 void *data,
161 void *userdata) {
162
163 log_syntax(unit, LOG_WARNING, filename, line, 0,
164 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
165
166 return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
167}
168
b02cb41c
LP
169int config_parse_unit_string_printf(
170 const char *unit,
171 const char *filename,
172 unsigned line,
173 const char *section,
174 unsigned section_line,
175 const char *lvalue,
176 int ltype,
177 const char *rvalue,
178 void *data,
179 void *userdata) {
932921b5 180
74051b9b 181 _cleanup_free_ char *k = NULL;
b02cb41c 182 Unit *u = userdata;
19f6d710 183 int r;
932921b5
LP
184
185 assert(filename);
186 assert(lvalue);
187 assert(rvalue);
f2d3769a 188 assert(u);
932921b5 189
19f6d710 190 r = unit_full_printf(u, rvalue, &k);
b02cb41c
LP
191 if (r < 0) {
192 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
193 return 0;
194 }
932921b5 195
b02cb41c 196 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
932921b5
LP
197}
198
12ca818f
LP
199int config_parse_unit_strv_printf(
200 const char *unit,
201 const char *filename,
202 unsigned line,
203 const char *section,
204 unsigned section_line,
205 const char *lvalue,
206 int ltype,
207 const char *rvalue,
208 void *data,
209 void *userdata) {
8fef7659
LP
210
211 Unit *u = userdata;
74051b9b 212 _cleanup_free_ char *k = NULL;
19f6d710 213 int r;
8fef7659
LP
214
215 assert(filename);
216 assert(lvalue);
217 assert(rvalue);
218 assert(u);
219
19f6d710 220 r = unit_full_printf(u, rvalue, &k);
12ca818f
LP
221 if (r < 0) {
222 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
223 return 0;
224 }
8fef7659 225
12ca818f 226 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
8fef7659
LP
227}
228
5f5d8eab
LP
229int config_parse_unit_path_printf(
230 const char *unit,
231 const char *filename,
232 unsigned line,
233 const char *section,
234 unsigned section_line,
235 const char *lvalue,
236 int ltype,
237 const char *rvalue,
238 void *data,
239 void *userdata) {
6ea832a2 240
74051b9b 241 _cleanup_free_ char *k = NULL;
811ba7a0 242 Unit *u = userdata;
19f6d710 243 int r;
6ea832a2
LP
244
245 assert(filename);
246 assert(lvalue);
247 assert(rvalue);
6ea832a2
LP
248 assert(u);
249
19f6d710 250 r = unit_full_printf(u, rvalue, &k);
811ba7a0 251 if (r < 0) {
12ca818f 252 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
811ba7a0
LP
253 return 0;
254 }
6ea832a2 255
811ba7a0
LP
256 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
257}
258
259int config_parse_unit_path_strv_printf(
260 const char *unit,
261 const char *filename,
262 unsigned line,
263 const char *section,
264 unsigned section_line,
265 const char *lvalue,
266 int ltype,
267 const char *rvalue,
268 void *data,
269 void *userdata) {
270
a2a5291b 271 char ***x = data;
811ba7a0 272 Unit *u = userdata;
811ba7a0 273 int r;
035fe294 274 const char *p;
811ba7a0
LP
275
276 assert(filename);
277 assert(lvalue);
278 assert(rvalue);
279 assert(u);
280
035fe294
ZJS
281 for (p = rvalue;;) {
282 _cleanup_free_ char *word = NULL, *k = NULL;
811ba7a0 283
035fe294
ZJS
284 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
285 if (r == 0)
286 return 0;
287 if (r == -ENOMEM)
288 return log_oom();
289 if (r < 0) {
290 log_syntax(unit, LOG_WARNING, filename, line, r,
291 "Invalid syntax, ignoring: %s", rvalue);
292 return 0;
293 }
811ba7a0 294
035fe294 295 r = unit_full_printf(u, word, &k);
811ba7a0 296 if (r < 0) {
035fe294
ZJS
297 log_syntax(unit, LOG_ERR, filename, line, r,
298 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word);
811ba7a0
LP
299 return 0;
300 }
301
302 if (!utf8_is_valid(k)) {
0e05ee04 303 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
811ba7a0
LP
304 return 0;
305 }
306
307 if (!path_is_absolute(k)) {
035fe294
ZJS
308 log_syntax(unit, LOG_ERR, filename, line, 0,
309 "Symlink path is not absolute: %s", k);
811ba7a0
LP
310 return 0;
311 }
312
313 path_kill_slashes(k);
314
315 r = strv_push(x, k);
316 if (r < 0)
317 return log_oom();
811ba7a0
LP
318 k = NULL;
319 }
6ea832a2
LP
320}
321
e8e581bf
ZJS
322int config_parse_socket_listen(const char *unit,
323 const char *filename,
324 unsigned line,
325 const char *section,
71a61510 326 unsigned section_line,
e8e581bf
ZJS
327 const char *lvalue,
328 int ltype,
329 const char *rvalue,
330 void *data,
331 void *userdata) {
42f4e3c4 332
b1389b0d
ZJS
333 _cleanup_free_ SocketPort *p = NULL;
334 SocketPort *tail;
542563ba 335 Socket *s;
19f6d710 336 int r;
16354eff 337
42f4e3c4
LP
338 assert(filename);
339 assert(lvalue);
340 assert(rvalue);
341 assert(data);
342
595ed347 343 s = SOCKET(data);
542563ba 344
74051b9b
LP
345 if (isempty(rvalue)) {
346 /* An empty assignment removes all ports */
347 socket_free_ports(s);
348 return 0;
349 }
350
7f110ff9
LP
351 p = new0(SocketPort, 1);
352 if (!p)
74051b9b 353 return log_oom();
916abb21 354
74051b9b 355 if (ltype != SOCKET_SOCKET) {
916abb21 356
74051b9b 357 p->type = ltype;
19f6d710
LP
358 r = unit_full_printf(UNIT(s), rvalue, &p->path);
359 if (r < 0) {
12ca818f
LP
360 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
361 return 0;
916abb21
LP
362 }
363
364 path_kill_slashes(p->path);
365
7a22745a 366 } else if (streq(lvalue, "ListenNetlink")) {
74051b9b 367 _cleanup_free_ char *k = NULL;
1fd45a90 368
7a22745a 369 p->type = SOCKET_SOCKET;
19f6d710 370 r = unit_full_printf(UNIT(s), rvalue, &k);
12ca818f
LP
371 if (r < 0) {
372 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
373 return 0;
374 }
7a22745a 375
12ca818f 376 r = socket_address_parse_netlink(&p->address, k);
1fd45a90 377 if (r < 0) {
12ca818f 378 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
7a22745a
LP
379 return 0;
380 }
381
542563ba 382 } else {
74051b9b 383 _cleanup_free_ char *k = NULL;
1fd45a90 384
542563ba 385 p->type = SOCKET_SOCKET;
19f6d710 386 r = unit_full_printf(UNIT(s), rvalue, &k);
12ca818f
LP
387 if (r < 0) {
388 log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
389 return 0;
390 }
542563ba 391
12ca818f 392 r = socket_address_parse_and_warn(&p->address, k);
1fd45a90 393 if (r < 0) {
12ca818f 394 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
c0b34696 395 return 0;
542563ba
LP
396 }
397
398 if (streq(lvalue, "ListenStream"))
399 p->address.type = SOCK_STREAM;
400 else if (streq(lvalue, "ListenDatagram"))
401 p->address.type = SOCK_DGRAM;
402 else {
403 assert(streq(lvalue, "ListenSequentialPacket"));
404 p->address.type = SOCK_SEQPACKET;
405 }
406
407 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
12ca818f 408 log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
c0b34696 409 return 0;
542563ba 410 }
16354eff
LP
411 }
412
542563ba 413 p->fd = -1;
15087cdb
PS
414 p->auxiliary_fds = NULL;
415 p->n_auxiliary_fds = 0;
2e41a51e 416 p->socket = s;
49f91047
LP
417
418 if (s->ports) {
71fda00f
LP
419 LIST_FIND_TAIL(port, s->ports, tail);
420 LIST_INSERT_AFTER(port, s->ports, tail, p);
49f91047 421 } else
71fda00f 422 LIST_PREPEND(port, s->ports, p);
b1389b0d 423 p = NULL;
542563ba 424
16354eff 425 return 0;
42f4e3c4
LP
426}
427
74bb646e
SS
428int config_parse_socket_protocol(const char *unit,
429 const char *filename,
430 unsigned line,
431 const char *section,
432 unsigned section_line,
433 const char *lvalue,
434 int ltype,
435 const char *rvalue,
436 void *data,
437 void *userdata) {
438 Socket *s;
439
440 assert(filename);
441 assert(lvalue);
442 assert(rvalue);
443 assert(data);
444
445 s = SOCKET(data);
446
447 if (streq(rvalue, "udplite"))
448 s->socket_protocol = IPPROTO_UDPLITE;
449 else if (streq(rvalue, "sctp"))
450 s->socket_protocol = IPPROTO_SCTP;
451 else {
452 log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
453 return 0;
454 }
455
456 return 0;
457}
458
e8e581bf
ZJS
459int config_parse_socket_bind(const char *unit,
460 const char *filename,
461 unsigned line,
462 const char *section,
71a61510 463 unsigned section_line,
e8e581bf
ZJS
464 const char *lvalue,
465 int ltype,
466 const char *rvalue,
467 void *data,
468 void *userdata) {
42f4e3c4 469
542563ba 470 Socket *s;
c0120d99 471 SocketAddressBindIPv6Only b;
42f4e3c4
LP
472
473 assert(filename);
474 assert(lvalue);
475 assert(rvalue);
476 assert(data);
477
595ed347 478 s = SOCKET(data);
542563ba 479
5198dabc
LP
480 b = socket_address_bind_ipv6_only_from_string(rvalue);
481 if (b < 0) {
c0120d99
LP
482 int r;
483
5198dabc
LP
484 r = parse_boolean(rvalue);
485 if (r < 0) {
12ca818f 486 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
c0b34696 487 return 0;
c0120d99 488 }
42f4e3c4 489
c0120d99
LP
490 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
491 } else
492 s->bind_ipv6_only = b;
542563ba 493
42f4e3c4
LP
494 return 0;
495}
496
41bf0590
LP
497int config_parse_exec_nice(
498 const char *unit,
499 const char *filename,
500 unsigned line,
501 const char *section,
502 unsigned section_line,
503 const char *lvalue,
504 int ltype,
505 const char *rvalue,
506 void *data,
507 void *userdata) {
034c6ed7 508
fb33a393 509 ExecContext *c = data;
e8e581bf 510 int priority, r;
034c6ed7
LP
511
512 assert(filename);
513 assert(lvalue);
514 assert(rvalue);
515 assert(data);
516
41bf0590 517 r = parse_nice(rvalue, &priority);
e8e581bf 518 if (r < 0) {
41bf0590
LP
519 if (r == -ERANGE)
520 log_syntax(unit, LOG_ERR, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
521 else
522 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
034c6ed7 523
c0b34696 524 return 0;
034c6ed7
LP
525 }
526
fb33a393 527 c->nice = priority;
71155933 528 c->nice_set = true;
fb33a393 529
034c6ed7
LP
530 return 0;
531}
532
e8e581bf
ZJS
533int config_parse_exec_oom_score_adjust(const char* unit,
534 const char *filename,
535 unsigned line,
536 const char *section,
71a61510 537 unsigned section_line,
e8e581bf
ZJS
538 const char *lvalue,
539 int ltype,
540 const char *rvalue,
541 void *data,
542 void *userdata) {
034c6ed7 543
fb33a393 544 ExecContext *c = data;
e8e581bf 545 int oa, r;
034c6ed7
LP
546
547 assert(filename);
548 assert(lvalue);
549 assert(rvalue);
550 assert(data);
551
e8e581bf
ZJS
552 r = safe_atoi(rvalue, &oa);
553 if (r < 0) {
12ca818f 554 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
c0b34696 555 return 0;
034c6ed7
LP
556 }
557
dd6c17b1 558 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
12ca818f 559 log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
c0b34696 560 return 0;
034c6ed7
LP
561 }
562
dd6c17b1
LP
563 c->oom_score_adjust = oa;
564 c->oom_score_adjust_set = true;
fb33a393 565
034c6ed7
LP
566 return 0;
567}
568
527b7a42
LP
569int config_parse_exec(
570 const char *unit,
571 const char *filename,
572 unsigned line,
573 const char *section,
574 unsigned section_line,
575 const char *lvalue,
576 int ltype,
577 const char *rvalue,
578 void *data,
579 void *userdata) {
034c6ed7 580
46a0d98a 581 ExecCommand **e = data;
5125e762 582 Unit *u = userdata;
46a0d98a
FB
583 const char *p;
584 bool semicolon;
7f110ff9 585 int r;
034c6ed7
LP
586
587 assert(filename);
588 assert(lvalue);
589 assert(rvalue);
61e5d8ed 590 assert(e);
034c6ed7 591
74051b9b 592 e += ltype;
c83f1f30 593 rvalue += strspn(rvalue, WHITESPACE);
c83f1f30 594
74051b9b
LP
595 if (isempty(rvalue)) {
596 /* An empty assignment resets the list */
f1acf85a 597 *e = exec_command_free_list(*e);
74051b9b
LP
598 return 0;
599 }
600
bd1b973f 601 p = rvalue;
46a0d98a 602 do {
dea7b6b0 603 _cleanup_free_ char *path = NULL, *firstword = NULL;
cf677fe6 604 bool separate_argv0 = false, ignore = false, privileged = false;
dea7b6b0 605 _cleanup_free_ ExecCommand *nce = NULL;
46a0d98a
FB
606 _cleanup_strv_free_ char **n = NULL;
607 size_t nlen = 0, nbufsize = 0;
5125e762 608 const char *f;
dea7b6b0 609 int i;
6c666e26 610
46a0d98a
FB
611 semicolon = false;
612
9a82ab95 613 r = extract_first_word_and_warn(&p, &firstword, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
614 if (r <= 0)
615 return 0;
6c666e26 616
46a0d98a 617 f = firstword;
cf677fe6
AP
618 for (i = 0; i < 3; i++) {
619 /* We accept an absolute path as first argument.
620 * If it's prefixed with - and the path doesn't exist,
621 * we ignore it instead of erroring out;
622 * if it's prefixed with @, we allow overriding of argv[0];
623 * and if it's prefixed with !, it will be run with full privileges */
46a0d98a
FB
624 if (*f == '-' && !ignore)
625 ignore = true;
626 else if (*f == '@' && !separate_argv0)
627 separate_argv0 = true;
43eb109a 628 else if (*f == '+' && !privileged)
cf677fe6 629 privileged = true;
46a0d98a
FB
630 else
631 break;
313cefa1 632 f++;
61e5d8ed 633 }
46a0d98a 634
5125e762
LP
635 r = unit_full_printf(u, f, &path);
636 if (r < 0) {
637 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", f);
638 return 0;
639 }
640
641 if (isempty(path)) {
46a0d98a 642 /* First word is either "-" or "@" with no command. */
12ca818f 643 log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
b2fadec6
ZJS
644 return 0;
645 }
5125e762 646 if (!string_is_safe(path)) {
12ca818f 647 log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
46a0d98a
FB
648 return 0;
649 }
5125e762 650 if (!path_is_absolute(path)) {
12ca818f 651 log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
46a0d98a
FB
652 return 0;
653 }
5125e762 654 if (endswith(path, "/")) {
12ca818f 655 log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
46a0d98a
FB
656 return 0;
657 }
61e5d8ed 658
46a0d98a 659 if (!separate_argv0) {
5125e762
LP
660 char *w = NULL;
661
46a0d98a
FB
662 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
663 return log_oom();
5125e762
LP
664
665 w = strdup(path);
666 if (!w)
46a0d98a 667 return log_oom();
5125e762 668 n[nlen++] = w;
46a0d98a
FB
669 n[nlen] = NULL;
670 }
7f110ff9 671
46a0d98a
FB
672 path_kill_slashes(path);
673
4b1c1753 674 while (!isempty(p)) {
5125e762 675 _cleanup_free_ char *word = NULL, *resolved = NULL;
46a0d98a
FB
676
677 /* Check explicitly for an unquoted semicolon as
678 * command separator token. */
679 if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
313cefa1 680 p++;
46a0d98a
FB
681 p += strspn(p, WHITESPACE);
682 semicolon = true;
683 break;
c8539536 684 }
7f110ff9 685
5125e762
LP
686 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
687 * extract_first_word() would return the same for all of those. */
46a0d98a 688 if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
5125e762
LP
689 char *w;
690
46a0d98a
FB
691 p += 2;
692 p += strspn(p, WHITESPACE);
5125e762 693
46a0d98a
FB
694 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
695 return log_oom();
5125e762
LP
696
697 w = strdup(";");
698 if (!w)
46a0d98a 699 return log_oom();
5125e762 700 n[nlen++] = w;
46a0d98a
FB
701 n[nlen] = NULL;
702 continue;
61e5d8ed 703 }
c8539536 704
9a82ab95 705 r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
706 if (r == 0)
707 break;
5125e762
LP
708 if (r < 0)
709 return 0;
710
711 r = unit_full_printf(u, word, &resolved);
712 if (r < 0) {
713 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to resolve unit specifiers on %s, ignoring: %m", word);
46a0d98a 714 return 0;
5125e762 715 }
46a0d98a
FB
716
717 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
718 return log_oom();
5125e762 719 n[nlen++] = resolved;
46a0d98a 720 n[nlen] = NULL;
5125e762 721 resolved = NULL;
61e5d8ed
LP
722 }
723
46a0d98a 724 if (!n || !n[0]) {
12ca818f 725 log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
46a0d98a 726 return 0;
7f110ff9 727 }
6c666e26 728
7f110ff9 729 nce = new0(ExecCommand, 1);
46a0d98a
FB
730 if (!nce)
731 return log_oom();
61e5d8ed
LP
732
733 nce->argv = n;
734 nce->path = path;
b708e7ce 735 nce->ignore = ignore;
cf677fe6 736 nce->privileged = privileged;
034c6ed7 737
61e5d8ed 738 exec_command_append_list(e, nce);
01f78473 739
46a0d98a
FB
740 /* Do not _cleanup_free_ these. */
741 n = NULL;
742 path = NULL;
743 nce = NULL;
034c6ed7 744
46a0d98a
FB
745 rvalue = p;
746 } while (semicolon);
034c6ed7 747
46a0d98a 748 return 0;
034c6ed7
LP
749}
750
f975e971
LP
751DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
752DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
034c6ed7 753
d31645ad
LP
754int config_parse_socket_bindtodevice(
755 const char* unit,
756 const char *filename,
757 unsigned line,
758 const char *section,
759 unsigned section_line,
760 const char *lvalue,
761 int ltype,
762 const char *rvalue,
763 void *data,
764 void *userdata) {
acbb0225
LP
765
766 Socket *s = data;
767 char *n;
768
769 assert(filename);
770 assert(lvalue);
771 assert(rvalue);
772 assert(data);
773
774 if (rvalue[0] && !streq(rvalue, "*")) {
d31645ad
LP
775 if (!ifname_valid(rvalue)) {
776 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue);
777 return 0;
778 }
779
74051b9b
LP
780 n = strdup(rvalue);
781 if (!n)
782 return log_oom();
acbb0225
LP
783 } else
784 n = NULL;
785
786 free(s->bind_to_device);
787 s->bind_to_device = n;
788
789 return 0;
790}
791
52c239d7
LB
792DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input literal specifier");
793DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output literal specifier");
794
795int config_parse_exec_input(const char *unit,
796 const char *filename,
797 unsigned line,
798 const char *section,
799 unsigned section_line,
800 const char *lvalue,
801 int ltype,
802 const char *rvalue,
803 void *data,
804 void *userdata) {
805 ExecContext *c = data;
806 const char *name;
807 int r;
808
809 assert(data);
810 assert(filename);
811 assert(line);
812 assert(rvalue);
813
814 name = startswith(rvalue, "fd:");
815 if (name) {
816 /* Strip prefix and validate fd name */
817 if (!fdname_is_valid(name)) {
818 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
819 return 0;
820 }
821 c->std_input = EXEC_INPUT_NAMED_FD;
822 r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], name);
823 if (r < 0)
824 log_oom();
825 return r;
826 } else {
827 ExecInput ei = exec_input_from_string(rvalue);
828 if (ei == _EXEC_INPUT_INVALID)
829 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue);
830 else
831 c->std_input = ei;
832 return 0;
833 }
834}
835
836int config_parse_exec_output(const char *unit,
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
846 ExecContext *c = data;
847 ExecOutput eo;
848 const char *name;
849 int r;
850
851 assert(data);
852 assert(filename);
853 assert(line);
854 assert(lvalue);
855 assert(rvalue);
856
857 name = startswith(rvalue, "fd:");
858 if (name) {
859 /* Strip prefix and validate fd name */
860 if (!fdname_is_valid(name)) {
861 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
862 return 0;
863 }
864 eo = EXEC_OUTPUT_NAMED_FD;
865 } else {
866 eo = exec_output_from_string(rvalue);
867 if (eo == _EXEC_OUTPUT_INVALID) {
868 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue);
869 return 0;
870 }
871 }
872
873 if (streq(lvalue, "StandardOutput")) {
874 c->std_output = eo;
875 r = free_and_strdup(&c->stdio_fdname[STDOUT_FILENO], name);
876 if (r < 0)
877 log_oom();
878 return r;
879 } else if (streq(lvalue, "StandardError")) {
880 c->std_error = eo;
881 r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], name);
882 if (r < 0)
883 log_oom();
884 return r;
885 } else {
886 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output property, ignoring: %s", lvalue);
887 return 0;
888 }
889}
87f0e418 890
e8e581bf
ZJS
891int config_parse_exec_io_class(const char *unit,
892 const char *filename,
893 unsigned line,
894 const char *section,
71a61510 895 unsigned section_line,
e8e581bf
ZJS
896 const char *lvalue,
897 int ltype,
898 const char *rvalue,
899 void *data,
900 void *userdata) {
94f04347
LP
901
902 ExecContext *c = data;
903 int x;
904
905 assert(filename);
906 assert(lvalue);
907 assert(rvalue);
908 assert(data);
909
f8b69d1d
MS
910 x = ioprio_class_from_string(rvalue);
911 if (x < 0) {
12ca818f 912 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
c0b34696 913 return 0;
0d87eb42 914 }
94f04347
LP
915
916 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
917 c->ioprio_set = true;
918
919 return 0;
920}
921
e8e581bf
ZJS
922int config_parse_exec_io_priority(const char *unit,
923 const char *filename,
924 unsigned line,
925 const char *section,
71a61510 926 unsigned section_line,
e8e581bf
ZJS
927 const char *lvalue,
928 int ltype,
929 const char *rvalue,
930 void *data,
931 void *userdata) {
94f04347
LP
932
933 ExecContext *c = data;
e8e581bf 934 int i, r;
94f04347
LP
935
936 assert(filename);
937 assert(lvalue);
938 assert(rvalue);
939 assert(data);
940
e8e581bf
ZJS
941 r = safe_atoi(rvalue, &i);
942 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
12ca818f 943 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
c0b34696 944 return 0;
071830ff
LP
945 }
946
94f04347
LP
947 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
948 c->ioprio_set = true;
949
071830ff
LP
950 return 0;
951}
952
e8e581bf
ZJS
953int config_parse_exec_cpu_sched_policy(const char *unit,
954 const char *filename,
955 unsigned line,
956 const char *section,
71a61510 957 unsigned section_line,
e8e581bf
ZJS
958 const char *lvalue,
959 int ltype,
960 const char *rvalue,
961 void *data,
962 void *userdata) {
9eba9da4 963
94f04347
LP
964
965 ExecContext *c = data;
966 int x;
967
968 assert(filename);
969 assert(lvalue);
970 assert(rvalue);
971 assert(data);
972
f8b69d1d
MS
973 x = sched_policy_from_string(rvalue);
974 if (x < 0) {
12ca818f 975 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 976 return 0;
0d87eb42 977 }
94f04347
LP
978
979 c->cpu_sched_policy = x;
bb112710
HHPF
980 /* Moving to or from real-time policy? We need to adjust the priority */
981 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
94f04347
LP
982 c->cpu_sched_set = true;
983
984 return 0;
985}
986
e8e581bf
ZJS
987int config_parse_exec_cpu_sched_prio(const char *unit,
988 const char *filename,
989 unsigned line,
990 const char *section,
71a61510 991 unsigned section_line,
e8e581bf
ZJS
992 const char *lvalue,
993 int ltype,
994 const char *rvalue,
995 void *data,
996 void *userdata) {
9eba9da4
LP
997
998 ExecContext *c = data;
e8e581bf 999 int i, min, max, r;
9eba9da4
LP
1000
1001 assert(filename);
1002 assert(lvalue);
1003 assert(rvalue);
1004 assert(data);
1005
e8e581bf
ZJS
1006 r = safe_atoi(rvalue, &i);
1007 if (r < 0) {
12ca818f 1008 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 1009 return 0;
94f04347 1010 }
9eba9da4 1011
bb112710
HHPF
1012 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1013 min = sched_get_priority_min(c->cpu_sched_policy);
1014 max = sched_get_priority_max(c->cpu_sched_policy);
1015
1016 if (i < min || i > max) {
12ca818f 1017 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
bb112710
HHPF
1018 return 0;
1019 }
1020
94f04347
LP
1021 c->cpu_sched_priority = i;
1022 c->cpu_sched_set = true;
1023
1024 return 0;
1025}
1026
e8e581bf
ZJS
1027int config_parse_exec_cpu_affinity(const char *unit,
1028 const char *filename,
1029 unsigned line,
1030 const char *section,
71a61510 1031 unsigned section_line,
e8e581bf
ZJS
1032 const char *lvalue,
1033 int ltype,
1034 const char *rvalue,
1035 void *data,
1036 void *userdata) {
94f04347
LP
1037
1038 ExecContext *c = data;
9d5ca7f8
FB
1039 _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
1040 int ncpus;
94f04347
LP
1041
1042 assert(filename);
1043 assert(lvalue);
1044 assert(rvalue);
1045 assert(data);
1046
765d143b 1047 ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
9d5ca7f8
FB
1048 if (ncpus < 0)
1049 return ncpus;
487393e9 1050
9d5ca7f8
FB
1051 if (c->cpuset)
1052 CPU_FREE(c->cpuset);
82c121a4 1053
9d5ca7f8
FB
1054 if (ncpus == 0)
1055 /* An empty assignment resets the CPU list */
1056 c->cpuset = NULL;
1057 else {
1058 c->cpuset = cpuset;
1059 cpuset = NULL;
9eba9da4 1060 }
9d5ca7f8 1061 c->cpuset_ncpus = ncpus;
9eba9da4 1062
94f04347
LP
1063 return 0;
1064}
1065
e8e581bf
ZJS
1066int config_parse_exec_secure_bits(const char *unit,
1067 const char *filename,
1068 unsigned line,
1069 const char *section,
71a61510 1070 unsigned section_line,
e8e581bf
ZJS
1071 const char *lvalue,
1072 int ltype,
1073 const char *rvalue,
1074 void *data,
1075 void *userdata) {
94f04347
LP
1076
1077 ExecContext *c = data;
035fe294
ZJS
1078 const char *p;
1079 int r;
94f04347
LP
1080
1081 assert(filename);
1082 assert(lvalue);
1083 assert(rvalue);
1084 assert(data);
1085
74051b9b
LP
1086 if (isempty(rvalue)) {
1087 /* An empty assignment resets the field */
1088 c->secure_bits = 0;
1089 return 0;
1090 }
1091
035fe294
ZJS
1092 for (p = rvalue;;) {
1093 _cleanup_free_ char *word = NULL;
1094
1095 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1096 if (r == 0)
1097 return 0;
1098 if (r == -ENOMEM)
1099 return log_oom();
1100 if (r < 0) {
1101 log_syntax(unit, LOG_WARNING, filename, line, r,
1102 "Invalid syntax, ignoring: %s", rvalue);
1103 return 0;
1104 }
1105
1106 if (streq(word, "keep-caps"))
cbb21cca 1107 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
035fe294 1108 else if (streq(word, "keep-caps-locked"))
cbb21cca 1109 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
035fe294 1110 else if (streq(word, "no-setuid-fixup"))
cbb21cca 1111 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
035fe294 1112 else if (streq(word, "no-setuid-fixup-locked"))
cbb21cca 1113 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
035fe294 1114 else if (streq(word, "noroot"))
cbb21cca 1115 c->secure_bits |= 1<<SECURE_NOROOT;
035fe294 1116 else if (streq(word, "noroot-locked"))
cbb21cca 1117 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
9eba9da4 1118 else {
035fe294
ZJS
1119 log_syntax(unit, LOG_ERR, filename, line, 0,
1120 "Failed to parse secure bit \"%s\", ignoring.", word);
c0b34696 1121 return 0;
9eba9da4
LP
1122 }
1123 }
94f04347
LP
1124}
1125
a103496c 1126int config_parse_capability_set(
65dce264
LP
1127 const char *unit,
1128 const char *filename,
1129 unsigned line,
1130 const char *section,
1131 unsigned section_line,
1132 const char *lvalue,
1133 int ltype,
1134 const char *rvalue,
1135 void *data,
1136 void *userdata) {
94f04347 1137
a103496c
IP
1138 uint64_t *capability_set = data;
1139 uint64_t sum = 0, initial = 0;
260abb78 1140 bool invert = false;
65dce264 1141 const char *p;
94f04347
LP
1142
1143 assert(filename);
1144 assert(lvalue);
1145 assert(rvalue);
1146 assert(data);
1147
260abb78
LP
1148 if (rvalue[0] == '~') {
1149 invert = true;
1150 rvalue++;
1151 }
1152
a103496c
IP
1153 if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
1154 initial = CAP_ALL; /* initialized to all bits on */
755d4b67 1155 /* else "AmbientCapabilities" initialized to all bits off */
260abb78 1156
65dce264 1157 p = rvalue;
9ef57298
EV
1158 for (;;) {
1159 _cleanup_free_ char *word = NULL;
65dce264 1160 int cap, r;
94f04347 1161
65dce264 1162 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
9ef57298
EV
1163 if (r == 0)
1164 break;
1165 if (r == -ENOMEM)
74051b9b 1166 return log_oom();
9ef57298 1167 if (r < 0) {
65dce264 1168 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
9ef57298
EV
1169 break;
1170 }
94f04347 1171
9ef57298 1172 cap = capability_from_name(word);
2822da4f 1173 if (cap < 0) {
755d4b67 1174 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
8351ceae 1175 continue;
94f04347
LP
1176 }
1177
65dce264 1178 sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
94f04347 1179 }
9eba9da4 1180
a103496c
IP
1181 sum = invert ? ~sum : sum;
1182
1183 if (sum == 0 || *capability_set == initial)
1184 /* "" or uninitialized data -> replace */
1185 *capability_set = sum;
260abb78 1186 else
a103496c
IP
1187 /* previous data -> merge */
1188 *capability_set |= sum;
260abb78 1189
9eba9da4
LP
1190 return 0;
1191}
1192
91518d20 1193int config_parse_limit(
d580265e
LP
1194 const char *unit,
1195 const char *filename,
1196 unsigned line,
1197 const char *section,
1198 unsigned section_line,
1199 const char *lvalue,
1200 int ltype,
1201 const char *rvalue,
1202 void *data,
1203 void *userdata) {
412ea7a9 1204
d0a7c5f6
LP
1205 struct rlimit **rl = data, d = {};
1206 int r;
a4c18002
LP
1207
1208 assert(filename);
1209 assert(lvalue);
1210 assert(rvalue);
1211 assert(data);
1212
d0a7c5f6
LP
1213 r = rlimit_parse(ltype, rvalue, &d);
1214 if (r == -EILSEQ) {
1215 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1216 return 0;
1217 }
1218 if (r < 0) {
1219 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1220 return 0;
1221 }
a4c18002 1222
d0a7c5f6
LP
1223 if (rl[ltype])
1224 *rl[ltype] = d;
1225 else {
1226 rl[ltype] = newdup(struct rlimit, &d, 1);
1227 if (!rl[ltype])
1228 return log_oom();
1229 }
a4c18002 1230
d0a7c5f6 1231 return 0;
91518d20 1232}
a4c18002 1233
07459bb6 1234#ifdef HAVE_SYSV_COMPAT
e8e581bf
ZJS
1235int config_parse_sysv_priority(const char *unit,
1236 const char *filename,
1237 unsigned line,
1238 const char *section,
71a61510 1239 unsigned section_line,
e8e581bf
ZJS
1240 const char *lvalue,
1241 int ltype,
1242 const char *rvalue,
1243 void *data,
1244 void *userdata) {
a9a1e00a
LP
1245
1246 int *priority = data;
e8e581bf 1247 int i, r;
a9a1e00a
LP
1248
1249 assert(filename);
1250 assert(lvalue);
1251 assert(rvalue);
1252 assert(data);
1253
e8e581bf
ZJS
1254 r = safe_atoi(rvalue, &i);
1255 if (r < 0 || i < 0) {
12ca818f 1256 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
c0b34696 1257 return 0;
a9a1e00a
LP
1258 }
1259
1260 *priority = (int) i;
1261 return 0;
1262}
07459bb6 1263#endif
a9a1e00a 1264
023a4f67 1265DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
f975e971 1266DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
50159e6a 1267
e8e581bf
ZJS
1268int config_parse_exec_mount_flags(const char *unit,
1269 const char *filename,
1270 unsigned line,
1271 const char *section,
71a61510 1272 unsigned section_line,
e8e581bf
ZJS
1273 const char *lvalue,
1274 int ltype,
1275 const char *rvalue,
1276 void *data,
1277 void *userdata) {
15ae422b 1278
e28bb14a 1279
15ae422b 1280 unsigned long flags = 0;
e28bb14a 1281 ExecContext *c = data;
15ae422b
LP
1282
1283 assert(filename);
1284 assert(lvalue);
1285 assert(rvalue);
1286 assert(data);
1287
e28bb14a
SS
1288 if (streq(rvalue, "shared"))
1289 flags = MS_SHARED;
1290 else if (streq(rvalue, "slave"))
1291 flags = MS_SLAVE;
1292 else if (streq(rvalue, "private"))
1293 flags = MS_PRIVATE;
1294 else {
1295 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
1296 return 0;
15ae422b
LP
1297 }
1298
1299 c->mount_flags = flags;
e28bb14a 1300
15ae422b
LP
1301 return 0;
1302}
1303
5f8640fb
LP
1304int config_parse_exec_selinux_context(
1305 const char *unit,
1306 const char *filename,
1307 unsigned line,
1308 const char *section,
1309 unsigned section_line,
1310 const char *lvalue,
1311 int ltype,
1312 const char *rvalue,
1313 void *data,
1314 void *userdata) {
1315
1316 ExecContext *c = data;
1317 Unit *u = userdata;
1318 bool ignore;
1319 char *k;
1320 int r;
1321
1322 assert(filename);
1323 assert(lvalue);
1324 assert(rvalue);
1325 assert(data);
1326
1327 if (isempty(rvalue)) {
a1e58e8e 1328 c->selinux_context = mfree(c->selinux_context);
5f8640fb
LP
1329 c->selinux_context_ignore = false;
1330 return 0;
1331 }
1332
1333 if (rvalue[0] == '-') {
1334 ignore = true;
1335 rvalue++;
1336 } else
1337 ignore = false;
1338
18913df9 1339 r = unit_full_printf(u, rvalue, &k);
5f8640fb 1340 if (r < 0) {
12ca818f 1341 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
5f8640fb
LP
1342 return 0;
1343 }
1344
1345 free(c->selinux_context);
1346 c->selinux_context = k;
1347 c->selinux_context_ignore = ignore;
1348
1349 return 0;
1350}
1351
eef65bf3
MS
1352int config_parse_exec_apparmor_profile(
1353 const char *unit,
1354 const char *filename,
1355 unsigned line,
1356 const char *section,
1357 unsigned section_line,
1358 const char *lvalue,
1359 int ltype,
1360 const char *rvalue,
1361 void *data,
1362 void *userdata) {
1363
1364 ExecContext *c = data;
1365 Unit *u = userdata;
1366 bool ignore;
1367 char *k;
1368 int r;
1369
1370 assert(filename);
1371 assert(lvalue);
1372 assert(rvalue);
1373 assert(data);
1374
1375 if (isempty(rvalue)) {
a1e58e8e 1376 c->apparmor_profile = mfree(c->apparmor_profile);
eef65bf3
MS
1377 c->apparmor_profile_ignore = false;
1378 return 0;
1379 }
1380
1381 if (rvalue[0] == '-') {
1382 ignore = true;
1383 rvalue++;
1384 } else
1385 ignore = false;
1386
18913df9 1387 r = unit_full_printf(u, rvalue, &k);
eef65bf3 1388 if (r < 0) {
12ca818f 1389 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
eef65bf3
MS
1390 return 0;
1391 }
1392
1393 free(c->apparmor_profile);
1394 c->apparmor_profile = k;
1395 c->apparmor_profile_ignore = ignore;
1396
1397 return 0;
1398}
1399
2ca620c4
WC
1400int config_parse_exec_smack_process_label(
1401 const char *unit,
1402 const char *filename,
1403 unsigned line,
1404 const char *section,
1405 unsigned section_line,
1406 const char *lvalue,
1407 int ltype,
1408 const char *rvalue,
1409 void *data,
1410 void *userdata) {
1411
1412 ExecContext *c = data;
1413 Unit *u = userdata;
1414 bool ignore;
1415 char *k;
1416 int r;
1417
1418 assert(filename);
1419 assert(lvalue);
1420 assert(rvalue);
1421 assert(data);
1422
1423 if (isempty(rvalue)) {
a1e58e8e 1424 c->smack_process_label = mfree(c->smack_process_label);
2ca620c4
WC
1425 c->smack_process_label_ignore = false;
1426 return 0;
1427 }
1428
1429 if (rvalue[0] == '-') {
1430 ignore = true;
1431 rvalue++;
1432 } else
1433 ignore = false;
1434
18913df9 1435 r = unit_full_printf(u, rvalue, &k);
2ca620c4 1436 if (r < 0) {
12ca818f 1437 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
2ca620c4
WC
1438 return 0;
1439 }
1440
1441 free(c->smack_process_label);
1442 c->smack_process_label = k;
1443 c->smack_process_label_ignore = ignore;
1444
1445 return 0;
1446}
1447
e8e581bf
ZJS
1448int config_parse_timer(const char *unit,
1449 const char *filename,
1450 unsigned line,
1451 const char *section,
71a61510 1452 unsigned section_line,
e8e581bf
ZJS
1453 const char *lvalue,
1454 int ltype,
1455 const char *rvalue,
1456 void *data,
1457 void *userdata) {
871d7de4
LP
1458
1459 Timer *t = data;
2507992f 1460 usec_t usec = 0;
871d7de4
LP
1461 TimerValue *v;
1462 TimerBase b;
36697dc0 1463 CalendarSpec *c = NULL;
2507992f
DC
1464 Unit *u = userdata;
1465 _cleanup_free_ char *k = NULL;
1466 int r;
871d7de4
LP
1467
1468 assert(filename);
1469 assert(lvalue);
1470 assert(rvalue);
1471 assert(data);
1472
74051b9b
LP
1473 if (isempty(rvalue)) {
1474 /* Empty assignment resets list */
1475 timer_free_values(t);
1476 return 0;
1477 }
1478
36697dc0
LP
1479 b = timer_base_from_string(lvalue);
1480 if (b < 0) {
12ca818f 1481 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
c0b34696 1482 return 0;
871d7de4
LP
1483 }
1484
2507992f
DC
1485 r = unit_full_printf(u, rvalue, &k);
1486 if (r < 0) {
1487 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1488 return 0;
1489 }
1490
36697dc0 1491 if (b == TIMER_CALENDAR) {
2507992f
DC
1492 if (calendar_spec_from_string(k, &c) < 0) {
1493 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k);
36697dc0
LP
1494 return 0;
1495 }
36697dc0 1496 } else {
2507992f
DC
1497 if (parse_sec(k, &usec) < 0) {
1498 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k);
36697dc0
LP
1499 return 0;
1500 }
871d7de4
LP
1501 }
1502
36697dc0 1503 v = new0(TimerValue, 1);
4d5e13a1 1504 if (!v) {
0b76b4d8 1505 calendar_spec_free(c);
74051b9b 1506 return log_oom();
4d5e13a1 1507 }
871d7de4
LP
1508
1509 v->base = b;
2507992f 1510 v->value = usec;
36697dc0 1511 v->calendar_spec = c;
871d7de4 1512
71fda00f 1513 LIST_PREPEND(value, t->values, v);
871d7de4
LP
1514
1515 return 0;
1516}
1517
3ecaa09b
LP
1518int config_parse_trigger_unit(
1519 const char *unit,
1520 const char *filename,
1521 unsigned line,
1522 const char *section,
71a61510 1523 unsigned section_line,
3ecaa09b
LP
1524 const char *lvalue,
1525 int ltype,
1526 const char *rvalue,
1527 void *data,
1528 void *userdata) {
871d7de4 1529
74051b9b 1530 _cleanup_free_ char *p = NULL;
3ecaa09b
LP
1531 Unit *u = data;
1532 UnitType type;
1533 int r;
398ef8ba
LP
1534
1535 assert(filename);
1536 assert(lvalue);
1537 assert(rvalue);
1538 assert(data);
1539
3ecaa09b 1540 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
12ca818f 1541 log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
3ecaa09b
LP
1542 return 0;
1543 }
871d7de4 1544
19f6d710 1545 r = unit_name_printf(u, rvalue, &p);
12ca818f
LP
1546 if (r < 0) {
1547 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1548 return 0;
1549 }
74051b9b 1550
12ca818f 1551 type = unit_name_to_type(p);
3ecaa09b 1552 if (type < 0) {
12ca818f 1553 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
c0b34696 1554 return 0;
871d7de4
LP
1555 }
1556
3ecaa09b 1557 if (type == u->type) {
12ca818f 1558 log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
3ecaa09b
LP
1559 return 0;
1560 }
1561
12ca818f 1562 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
57020a3a 1563 if (r < 0) {
12ca818f 1564 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
c0b34696 1565 return 0;
871d7de4
LP
1566 }
1567
1568 return 0;
1569}
1570
e8e581bf
ZJS
1571int config_parse_path_spec(const char *unit,
1572 const char *filename,
1573 unsigned line,
1574 const char *section,
71a61510 1575 unsigned section_line,
e8e581bf
ZJS
1576 const char *lvalue,
1577 int ltype,
1578 const char *rvalue,
1579 void *data,
1580 void *userdata) {
01f78473
LP
1581
1582 Path *p = data;
1583 PathSpec *s;
1584 PathType b;
7fd1b19b 1585 _cleanup_free_ char *k = NULL;
19f6d710 1586 int r;
01f78473
LP
1587
1588 assert(filename);
1589 assert(lvalue);
1590 assert(rvalue);
1591 assert(data);
1592
74051b9b
LP
1593 if (isempty(rvalue)) {
1594 /* Empty assignment clears list */
1595 path_free_specs(p);
1596 return 0;
1597 }
1598
93e4c84b
LP
1599 b = path_type_from_string(lvalue);
1600 if (b < 0) {
12ca818f 1601 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 1602 return 0;
01f78473
LP
1603 }
1604
19f6d710
LP
1605 r = unit_full_printf(UNIT(p), rvalue, &k);
1606 if (r < 0) {
12ca818f
LP
1607 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1608 return 0;
487060c2 1609 }
93e4c84b
LP
1610
1611 if (!path_is_absolute(k)) {
12ca818f 1612 log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
c0b34696 1613 return 0;
01f78473
LP
1614 }
1615
93e4c84b 1616 s = new0(PathSpec, 1);
543295ad 1617 if (!s)
93e4c84b 1618 return log_oom();
01f78473 1619
718db961 1620 s->unit = UNIT(p);
93e4c84b 1621 s->path = path_kill_slashes(k);
543295ad 1622 k = NULL;
01f78473
LP
1623 s->type = b;
1624 s->inotify_fd = -1;
1625
71fda00f 1626 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
1627
1628 return 0;
1629}
1630
b02cb41c
LP
1631int config_parse_socket_service(
1632 const char *unit,
1633 const char *filename,
1634 unsigned line,
1635 const char *section,
1636 unsigned section_line,
1637 const char *lvalue,
1638 int ltype,
1639 const char *rvalue,
1640 void *data,
1641 void *userdata) {
d9ff321a 1642
4afd3348 1643 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8dd4c05b 1644 _cleanup_free_ char *p = NULL;
d9ff321a 1645 Socket *s = data;
4ff77f66 1646 Unit *x;
8dd4c05b 1647 int r;
d9ff321a
LP
1648
1649 assert(filename);
1650 assert(lvalue);
1651 assert(rvalue);
1652 assert(data);
1653
19f6d710 1654 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 1655 if (r < 0) {
b02cb41c 1656 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
613b411c
LP
1657 return 0;
1658 }
74051b9b 1659
613b411c 1660 if (!endswith(p, ".service")) {
12ca818f 1661 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
d9ff321a
LP
1662 return 0;
1663 }
1664
613b411c 1665 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 1666 if (r < 0) {
12ca818f 1667 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
d9ff321a
LP
1668 return 0;
1669 }
1670
4ff77f66
LP
1671 unit_ref_set(&s->service, x);
1672
d9ff321a
LP
1673 return 0;
1674}
1675
8dd4c05b
LP
1676int config_parse_fdname(
1677 const char *unit,
1678 const char *filename,
1679 unsigned line,
1680 const char *section,
1681 unsigned section_line,
1682 const char *lvalue,
1683 int ltype,
1684 const char *rvalue,
1685 void *data,
1686 void *userdata) {
1687
1688 _cleanup_free_ char *p = NULL;
1689 Socket *s = data;
1690 int r;
1691
1692 assert(filename);
1693 assert(lvalue);
1694 assert(rvalue);
1695 assert(data);
1696
1697 if (isempty(rvalue)) {
1698 s->fdname = mfree(s->fdname);
1699 return 0;
1700 }
1701
18913df9 1702 r = unit_full_printf(UNIT(s), rvalue, &p);
8dd4c05b
LP
1703 if (r < 0) {
1704 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1705 return 0;
1706 }
1707
1708 if (!fdname_is_valid(p)) {
1709 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
1710 return 0;
1711 }
1712
3b319885 1713 return free_and_replace(s->fdname, p);
8dd4c05b
LP
1714}
1715
b02cb41c
LP
1716int config_parse_service_sockets(
1717 const char *unit,
1718 const char *filename,
1719 unsigned line,
1720 const char *section,
1721 unsigned section_line,
1722 const char *lvalue,
1723 int ltype,
1724 const char *rvalue,
1725 void *data,
1726 void *userdata) {
f976f3f6
LP
1727
1728 Service *s = data;
7b2313f5 1729 const char *p;
b02cb41c 1730 int r;
f976f3f6
LP
1731
1732 assert(filename);
1733 assert(lvalue);
1734 assert(rvalue);
1735 assert(data);
1736
7b2313f5 1737 p = rvalue;
9ed794a3 1738 for (;;) {
6a0f3175 1739 _cleanup_free_ char *word = NULL, *k = NULL;
f976f3f6 1740
7b2313f5
SS
1741 r = extract_first_word(&p, &word, NULL, 0);
1742 if (r == 0)
1743 break;
1744 if (r == -ENOMEM)
74051b9b 1745 return log_oom();
7b2313f5
SS
1746 if (r < 0) {
1747 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
1748 break;
1749 }
f976f3f6 1750
7b2313f5 1751 r = unit_name_printf(UNIT(s), word, &k);
b02cb41c
LP
1752 if (r < 0) {
1753 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1754 continue;
1755 }
57020a3a 1756
b02cb41c 1757 if (!endswith(k, ".socket")) {
12ca818f 1758 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
f976f3f6
LP
1759 continue;
1760 }
1761
b02cb41c 1762 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
57020a3a 1763 if (r < 0)
b02cb41c 1764 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 1765
b02cb41c 1766 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
57020a3a 1767 if (r < 0)
b02cb41c 1768 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6
LP
1769 }
1770
1771 return 0;
1772}
1773
b02cb41c
LP
1774int config_parse_bus_name(
1775 const char *unit,
1776 const char *filename,
1777 unsigned line,
1778 const char *section,
1779 unsigned section_line,
1780 const char *lvalue,
1781 int ltype,
1782 const char *rvalue,
1783 void *data,
1784 void *userdata) {
1785
1786 _cleanup_free_ char *k = NULL;
1787 Unit *u = userdata;
1788 int r;
1789
1790 assert(filename);
1791 assert(lvalue);
1792 assert(rvalue);
1793 assert(u);
1794
1795 r = unit_full_printf(u, rvalue, &k);
1796 if (r < 0) {
1797 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1798 return 0;
1799 }
1800
1801 if (!service_name_is_valid(k)) {
12ca818f 1802 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
b02cb41c
LP
1803 return 0;
1804 }
1805
1806 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1807}
1808
aad41f08
LP
1809int config_parse_service_timeout(
1810 const char *unit,
1811 const char *filename,
1812 unsigned line,
1813 const char *section,
1814 unsigned section_line,
1815 const char *lvalue,
1816 int ltype,
1817 const char *rvalue,
1818 void *data,
1819 void *userdata) {
98709151
LN
1820
1821 Service *s = userdata;
aad41f08 1822 usec_t usec;
98709151
LN
1823 int r;
1824
1825 assert(filename);
1826 assert(lvalue);
1827 assert(rvalue);
1828 assert(s);
1829
aad41f08 1830 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
98709151 1831
aad41f08
LP
1832 r = parse_sec(rvalue, &usec);
1833 if (r < 0) {
1834 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1835 return 0;
1836 }
d568a335 1837
36c16a7c
LP
1838 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1839 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1840 * all other timeouts. */
aad41f08
LP
1841 if (usec <= 0)
1842 usec = USEC_INFINITY;
1843
1844 if (!streq(lvalue, "TimeoutStopSec")) {
1845 s->start_timeout_defined = true;
1846 s->timeout_start_usec = usec;
1847 }
36c16a7c 1848
aad41f08
LP
1849 if (!streq(lvalue, "TimeoutStartSec"))
1850 s->timeout_stop_usec = usec;
36c16a7c 1851
d568a335 1852 return 0;
98709151
LN
1853}
1854
89beff89
LP
1855int config_parse_sec_fix_0(
1856 const char *unit,
1857 const char *filename,
1858 unsigned line,
1859 const char *section,
1860 unsigned section_line,
1861 const char *lvalue,
1862 int ltype,
1863 const char *rvalue,
1864 void *data,
1865 void *userdata) {
1866
1867 usec_t *usec = data;
1868 int r;
1869
1870 assert(filename);
1871 assert(lvalue);
1872 assert(rvalue);
1873 assert(usec);
1874
1875 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1876 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1877 * timeout. */
1878
1879 r = parse_sec(rvalue, usec);
1880 if (r < 0) {
1881 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1882 return 0;
1883 }
1884
1885 if (*usec <= 0)
1886 *usec = USEC_INFINITY;
1887
1888 return 0;
1889}
1890
66dccd8d
LP
1891int config_parse_user_group(
1892 const char *unit,
1893 const char *filename,
1894 unsigned line,
1895 const char *section,
1896 unsigned section_line,
1897 const char *lvalue,
1898 int ltype,
1899 const char *rvalue,
1900 void *data,
1901 void *userdata) {
1902
1903 char **user = data, *n;
1904 Unit *u = userdata;
1905 int r;
1906
1907 assert(filename);
1908 assert(lvalue);
1909 assert(rvalue);
1910 assert(u);
1911
1912 if (isempty(rvalue))
1913 n = NULL;
1914 else {
1915 _cleanup_free_ char *k = NULL;
1916
1917 r = unit_full_printf(u, rvalue, &k);
1918 if (r < 0) {
1919 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1920 return 0;
1921 }
1922
1923 if (!valid_user_group_name_or_id(k)) {
1924 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
1925 return 0;
1926 }
1927
1928 n = k;
1929 k = NULL;
1930 }
1931
1932 free(*user);
1933 *user = n;
1934
1935 return 0;
1936}
1937
1938int config_parse_user_group_strv(
1939 const char *unit,
1940 const char *filename,
1941 unsigned line,
1942 const char *section,
1943 unsigned section_line,
1944 const char *lvalue,
1945 int ltype,
1946 const char *rvalue,
1947 void *data,
1948 void *userdata) {
1949
1950 char ***users = data;
1951 Unit *u = userdata;
1952 const char *p;
1953 int r;
1954
1955 assert(filename);
1956 assert(lvalue);
1957 assert(rvalue);
1958 assert(u);
1959
1960 if (isempty(rvalue)) {
1961 char **empty;
1962
1963 empty = new0(char*, 1);
1964 if (!empty)
1965 return log_oom();
1966
1967 strv_free(*users);
1968 *users = empty;
1969
1970 return 0;
1971 }
1972
1973 p = rvalue;
1974 for (;;) {
1975 _cleanup_free_ char *word = NULL, *k = NULL;
1976
9a82ab95 1977 r = extract_first_word(&p, &word, NULL, 0);
66dccd8d
LP
1978 if (r == 0)
1979 break;
1980 if (r == -ENOMEM)
1981 return log_oom();
1982 if (r < 0) {
1983 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1984 break;
1985 }
1986
1987 r = unit_full_printf(u, word, &k);
1988 if (r < 0) {
1989 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
1990 continue;
1991 }
1992
1993 if (!valid_user_group_name_or_id(k)) {
1994 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
1995 continue;
1996 }
1997
1998 r = strv_push(users, k);
1999 if (r < 0)
2000 return log_oom();
2001
2002 k = NULL;
2003 }
2004
2005 return 0;
2006}
2007
e821075a
LP
2008int config_parse_busname_service(
2009 const char *unit,
2010 const char *filename,
2011 unsigned line,
2012 const char *section,
2013 unsigned section_line,
2014 const char *lvalue,
2015 int ltype,
2016 const char *rvalue,
2017 void *data,
2018 void *userdata) {
2019
4afd3348 2020 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
e821075a
LP
2021 BusName *n = data;
2022 int r;
2023 Unit *x;
2024 _cleanup_free_ char *p = NULL;
2025
2026 assert(filename);
2027 assert(lvalue);
2028 assert(rvalue);
2029 assert(data);
2030
2031 r = unit_name_printf(UNIT(n), rvalue, &p);
2032 if (r < 0) {
12ca818f 2033 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
e821075a
LP
2034 return 0;
2035 }
2036
2037 if (!endswith(p, ".service")) {
12ca818f 2038 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
e821075a
LP
2039 return 0;
2040 }
2041
2042 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
2043 if (r < 0) {
12ca818f 2044 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
e821075a
LP
2045 return 0;
2046 }
2047
2048 unit_ref_set(&n->service, x);
2049
2050 return 0;
2051}
2052
5369c77d 2053DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
a4152e3f 2054
54d76c92
DM
2055int config_parse_bus_policy(
2056 const char *unit,
2057 const char *filename,
2058 unsigned line,
2059 const char *section,
2060 unsigned section_line,
2061 const char *lvalue,
2062 int ltype,
2063 const char *rvalue,
2064 void *data,
2065 void *userdata) {
2066
2067 _cleanup_free_ BusNamePolicy *p = NULL;
2068 _cleanup_free_ char *id_str = NULL;
2069 BusName *busname = data;
2070 char *access_str;
54d76c92
DM
2071
2072 assert(filename);
2073 assert(lvalue);
2074 assert(rvalue);
2075 assert(data);
2076
2077 p = new0(BusNamePolicy, 1);
2078 if (!p)
2079 return log_oom();
2080
2081 if (streq(lvalue, "AllowUser"))
2082 p->type = BUSNAME_POLICY_TYPE_USER;
2083 else if (streq(lvalue, "AllowGroup"))
2084 p->type = BUSNAME_POLICY_TYPE_GROUP;
54d76c92
DM
2085 else
2086 assert_not_reached("Unknown lvalue");
2087
2088 id_str = strdup(rvalue);
2089 if (!id_str)
2090 return log_oom();
2091
a4152e3f
LP
2092 access_str = strpbrk(id_str, WHITESPACE);
2093 if (!access_str) {
12ca818f 2094 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
a4152e3f 2095 return 0;
54d76c92
DM
2096 }
2097
a4152e3f
LP
2098 *access_str = '\0';
2099 access_str++;
2100 access_str += strspn(access_str, WHITESPACE);
2101
5369c77d 2102 p->access = bus_policy_access_from_string(access_str);
54d76c92 2103 if (p->access < 0) {
12ca818f 2104 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
54d76c92
DM
2105 return 0;
2106 }
2107
a4152e3f
LP
2108 p->name = id_str;
2109 id_str = NULL;
2110
54d76c92
DM
2111 LIST_PREPEND(policy, busname->policy, p);
2112 p = NULL;
2113
2114 return 0;
2115}
2116
5f5d8eab
LP
2117int config_parse_working_directory(
2118 const char *unit,
2119 const char *filename,
2120 unsigned line,
2121 const char *section,
2122 unsigned section_line,
2123 const char *lvalue,
2124 int ltype,
2125 const char *rvalue,
2126 void *data,
2127 void *userdata) {
2128
2129 ExecContext *c = data;
2130 Unit *u = userdata;
2131 bool missing_ok;
2132 int r;
2133
2134 assert(filename);
2135 assert(lvalue);
2136 assert(rvalue);
2137 assert(c);
2138 assert(u);
2139
2140 if (rvalue[0] == '-') {
2141 missing_ok = true;
2142 rvalue++;
2143 } else
2144 missing_ok = false;
2145
2146 if (streq(rvalue, "~")) {
2147 c->working_directory_home = true;
2148 c->working_directory = mfree(c->working_directory);
2149 } else {
2150 _cleanup_free_ char *k = NULL;
2151
2152 r = unit_full_printf(u, rvalue, &k);
2153 if (r < 0) {
2154 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
2155 return 0;
2156 }
2157
2158 path_kill_slashes(k);
2159
2160 if (!utf8_is_valid(k)) {
0e05ee04 2161 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
5f5d8eab
LP
2162 return 0;
2163 }
2164
2165 if (!path_is_absolute(k)) {
2166 log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
2167 return 0;
2168 }
2169
3b319885 2170 free_and_replace(c->working_directory, k);
5f5d8eab
LP
2171
2172 c->working_directory_home = false;
2173 }
2174
2175 c->working_directory_missing_ok = missing_ok;
2176 return 0;
2177}
2178
e8e581bf
ZJS
2179int config_parse_unit_env_file(const char *unit,
2180 const char *filename,
2181 unsigned line,
2182 const char *section,
71a61510 2183 unsigned section_line,
e8e581bf
ZJS
2184 const char *lvalue,
2185 int ltype,
2186 const char *rvalue,
2187 void *data,
2188 void *userdata) {
ddb26e18 2189
853b8397 2190 char ***env = data;
8fef7659 2191 Unit *u = userdata;
19f6d710 2192 _cleanup_free_ char *n = NULL;
853b8397 2193 int r;
ddb26e18
LP
2194
2195 assert(filename);
2196 assert(lvalue);
2197 assert(rvalue);
2198 assert(data);
2199
74051b9b
LP
2200 if (isempty(rvalue)) {
2201 /* Empty assignment frees the list */
6796073e 2202 *env = strv_free(*env);
74051b9b
LP
2203 return 0;
2204 }
2205
19f6d710 2206 r = unit_full_printf(u, rvalue, &n);
12ca818f
LP
2207 if (r < 0) {
2208 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2209 return 0;
2210 }
8fef7659 2211
12ca818f
LP
2212 if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
2213 log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
afe4bfe2
LP
2214 return 0;
2215 }
2216
12ca818f 2217 r = strv_extend(env, n);
853b8397
LP
2218 if (r < 0)
2219 return log_oom();
2220
2221 return 0;
2222}
2223
e8e581bf
ZJS
2224int config_parse_environ(const char *unit,
2225 const char *filename,
2226 unsigned line,
2227 const char *section,
71a61510 2228 unsigned section_line,
e8e581bf
ZJS
2229 const char *lvalue,
2230 int ltype,
2231 const char *rvalue,
2232 void *data,
2233 void *userdata) {
853b8397
LP
2234
2235 Unit *u = userdata;
035fe294
ZJS
2236 char ***env = data;
2237 const char *p;
19f6d710 2238 int r;
853b8397
LP
2239
2240 assert(filename);
2241 assert(lvalue);
2242 assert(rvalue);
97d0e5f8 2243 assert(data);
853b8397
LP
2244
2245 if (isempty(rvalue)) {
2246 /* Empty assignment resets the list */
6796073e 2247 *env = strv_free(*env);
853b8397
LP
2248 return 0;
2249 }
2250
035fe294
ZJS
2251 for (p = rvalue;; ) {
2252 _cleanup_free_ char *word = NULL, *k = NULL;
035fe294
ZJS
2253
2254 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
2255 if (r == 0)
2256 return 0;
2257 if (r == -ENOMEM)
2258 return log_oom();
12ca818f 2259 if (r < 0) {
035fe294
ZJS
2260 log_syntax(unit, LOG_WARNING, filename, line, r,
2261 "Invalid syntax, ignoring: %s", rvalue);
12ca818f
LP
2262 return 0;
2263 }
97d0e5f8 2264
035fe294
ZJS
2265 if (u) {
2266 r = unit_full_printf(u, word, &k);
2267 if (r < 0) {
2268 log_syntax(unit, LOG_ERR, filename, line, r,
2269 "Failed to resolve specifiers, ignoring: %s", k);
2270 continue;
2271 }
2272 } else {
2273 k = word;
2274 word = NULL;
527b7a42 2275 }
853b8397 2276
035fe294
ZJS
2277 if (!env_assignment_is_valid(k)) {
2278 log_syntax(unit, LOG_ERR, filename, line, 0,
2279 "Invalid environment assignment, ignoring: %s", k);
853b8397
LP
2280 continue;
2281 }
2282
54ac3494
ZJS
2283 r = strv_env_replace(env, k);
2284 if (r < 0)
853b8397 2285 return log_oom();
54ac3494 2286 k = NULL;
853b8397 2287 }
ddb26e18
LP
2288}
2289
b4c14404
FB
2290int config_parse_pass_environ(const char *unit,
2291 const char *filename,
2292 unsigned line,
2293 const char *section,
2294 unsigned section_line,
2295 const char *lvalue,
2296 int ltype,
2297 const char *rvalue,
2298 void *data,
2299 void *userdata) {
2300
2301 const char *whole_rvalue = rvalue;
2302 char*** passenv = data;
2303 _cleanup_strv_free_ char **n = NULL;
2304 size_t nlen = 0, nbufsize = 0;
2305 int r;
2306
2307 assert(filename);
2308 assert(lvalue);
2309 assert(rvalue);
2310 assert(data);
2311
2312 if (isempty(rvalue)) {
2313 /* Empty assignment resets the list */
2314 *passenv = strv_free(*passenv);
2315 return 0;
2316 }
2317
2318 for (;;) {
2319 _cleanup_free_ char *word = NULL;
2320
9a82ab95 2321 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
b4c14404
FB
2322 if (r == 0)
2323 break;
2324 if (r == -ENOMEM)
2325 return log_oom();
2326 if (r < 0) {
2327 log_syntax(unit, LOG_ERR, filename, line, r,
2328 "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
2329 break;
2330 }
2331
2332 if (!env_name_is_valid(word)) {
2333 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2334 "Invalid environment name for %s, ignoring: %s", lvalue, word);
2335 continue;
2336 }
2337
2338 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2339 return log_oom();
2340 n[nlen++] = word;
2341 n[nlen] = NULL;
2342 word = NULL;
2343 }
2344
2345 if (n) {
2346 r = strv_extend_strv(passenv, 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
e66cf1a3
LP
3687int config_parse_runtime_directory(
3688 const char *unit,
3689 const char *filename,
3690 unsigned line,
3691 const char *section,
3692 unsigned section_line,
3693 const char *lvalue,
3694 int ltype,
3695 const char *rvalue,
3696 void *data,
3697 void *userdata) {
3698
a2a5291b 3699 char***rt = data;
9b5864d9 3700 Unit *u = userdata;
035fe294 3701 const char *p;
e66cf1a3
LP
3702 int r;
3703
3704 assert(filename);
3705 assert(lvalue);
3706 assert(rvalue);
3707 assert(data);
3708
3709 if (isempty(rvalue)) {
3710 /* Empty assignment resets the list */
6796073e 3711 *rt = strv_free(*rt);
e66cf1a3
LP
3712 return 0;
3713 }
3714
035fe294
ZJS
3715 for (p = rvalue;;) {
3716 _cleanup_free_ char *word = NULL, *k = NULL;
e66cf1a3 3717
035fe294
ZJS
3718 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3719 if (r == 0)
3720 return 0;
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 }
e66cf1a3 3728
18913df9 3729 r = unit_full_printf(u, word, &k);
9b5864d9 3730 if (r < 0) {
035fe294
ZJS
3731 log_syntax(unit, LOG_ERR, filename, line, r,
3732 "Failed to resolve specifiers in \"%s\", ignoring: %m", word);
9b5864d9
MG
3733 continue;
3734 }
3735
035fe294
ZJS
3736 if (!filename_is_valid(k)) {
3737 log_syntax(unit, LOG_ERR, filename, line, 0,
3738 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
e66cf1a3
LP
3739 continue;
3740 }
3741
035fe294 3742 r = strv_push(rt, k);
e66cf1a3
LP
3743 if (r < 0)
3744 return log_oom();
035fe294 3745 k = NULL;
e66cf1a3 3746 }
e66cf1a3
LP
3747}
3748
3af00fb8
LP
3749int config_parse_set_status(
3750 const char *unit,
3751 const char *filename,
3752 unsigned line,
3753 const char *section,
3754 unsigned section_line,
3755 const char *lvalue,
3756 int ltype,
3757 const char *rvalue,
3758 void *data,
3759 void *userdata) {
3760
3af00fb8 3761 size_t l;
a2a5291b 3762 const char *word, *state;
3af00fb8
LP
3763 int r;
3764 ExitStatusSet *status_set = data;
3765
3766 assert(filename);
3767 assert(lvalue);
3768 assert(rvalue);
3769 assert(data);
3770
3e2d435b 3771 /* Empty assignment resets the list */
3af00fb8 3772 if (isempty(rvalue)) {
3e2d435b 3773 exit_status_set_free(status_set);
3af00fb8
LP
3774 return 0;
3775 }
3776
a2a5291b 3777 FOREACH_WORD(word, l, rvalue, state) {
3af00fb8
LP
3778 _cleanup_free_ char *temp;
3779 int val;
61593865 3780 Set **set;
3af00fb8 3781
a2a5291b 3782 temp = strndup(word, l);
3af00fb8
LP
3783 if (!temp)
3784 return log_oom();
3785
3786 r = safe_atoi(temp, &val);
3787 if (r < 0) {
3788 val = signal_from_string_try_harder(temp);
3789
1e2fd62d 3790 if (val <= 0) {
12ca818f 3791 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
61593865 3792 continue;
3af00fb8 3793 }
61593865 3794 set = &status_set->signal;
3af00fb8 3795 } else {
1e2fd62d 3796 if (val < 0 || val > 255) {
12ca818f 3797 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
1e2fd62d 3798 continue;
3af00fb8 3799 }
61593865 3800 set = &status_set->status;
3af00fb8 3801 }
1e2fd62d 3802
61593865 3803 r = set_ensure_allocated(set, NULL);
1e2fd62d
ZJS
3804 if (r < 0)
3805 return log_oom();
3806
61593865 3807 r = set_put(*set, INT_TO_PTR(val));
1e2fd62d 3808 if (r < 0) {
12ca818f 3809 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
1e2fd62d
ZJS
3810 return r;
3811 }
3af00fb8 3812 }
b2fadec6 3813 if (!isempty(state))
12ca818f 3814 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3af00fb8
LP
3815
3816 return 0;
3817}
3818
94828d2d
LP
3819int config_parse_namespace_path_strv(
3820 const char *unit,
3821 const char *filename,
3822 unsigned line,
3823 const char *section,
3824 unsigned section_line,
3825 const char *lvalue,
3826 int ltype,
3827 const char *rvalue,
3828 void *data,
3829 void *userdata) {
3830
a2a5291b 3831 char*** sv = data;
727f76d7
EV
3832 const char *prev;
3833 const char *cur;
94828d2d
LP
3834 int r;
3835
3836 assert(filename);
3837 assert(lvalue);
3838 assert(rvalue);
3839 assert(data);
3840
3841 if (isempty(rvalue)) {
3842 /* Empty assignment resets the list */
6796073e 3843 *sv = strv_free(*sv);
94828d2d
LP
3844 return 0;
3845 }
3846
727f76d7
EV
3847 prev = cur = rvalue;
3848 for (;;) {
3849 _cleanup_free_ char *word = NULL;
94828d2d
LP
3850 int offset;
3851
727f76d7 3852 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
0293a7a8
EV
3853 if (r == 0)
3854 break;
3855 if (r == -ENOMEM)
3856 return log_oom();
727f76d7 3857 if (r < 0) {
0293a7a8 3858 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
727f76d7
EV
3859 return 0;
3860 }
94828d2d 3861
727f76d7
EV
3862 if (!utf8_is_valid(word)) {
3863 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3864 prev = cur;
94828d2d
LP
3865 continue;
3866 }
3867
727f76d7
EV
3868 offset = word[0] == '-';
3869 if (!path_is_absolute(word + offset)) {
3870 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
3871 prev = cur;
94828d2d
LP
3872 continue;
3873 }
3874
727f76d7 3875 path_kill_slashes(word + offset);
94828d2d 3876
727f76d7 3877 r = strv_push(sv, word);
94828d2d
LP
3878 if (r < 0)
3879 return log_oom();
3880
727f76d7
EV
3881 prev = cur;
3882 word = NULL;
94828d2d
LP
3883 }
3884
3885 return 0;
3886}
3887
f1721625 3888int config_parse_no_new_privileges(
760b9d7c
LP
3889 const char* unit,
3890 const char *filename,
3891 unsigned line,
3892 const char *section,
3893 unsigned section_line,
3894 const char *lvalue,
3895 int ltype,
3896 const char *rvalue,
3897 void *data,
3898 void *userdata) {
3899
3900 ExecContext *c = data;
3901 int k;
3902
3903 assert(filename);
3904 assert(lvalue);
3905 assert(rvalue);
3906 assert(data);
3907
3908 k = parse_boolean(rvalue);
3909 if (k < 0) {
12ca818f 3910 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
760b9d7c
LP
3911 return 0;
3912 }
3913
9b232d32 3914 c->no_new_privileges = k;
760b9d7c
LP
3915
3916 return 0;
3917}
3918
1b8689f9 3919int config_parse_protect_home(
417116f2
LP
3920 const char* unit,
3921 const char *filename,
3922 unsigned line,
3923 const char *section,
3924 unsigned section_line,
3925 const char *lvalue,
3926 int ltype,
3927 const char *rvalue,
3928 void *data,
3929 void *userdata) {
3930
3931 ExecContext *c = data;
3932 int k;
3933
3934 assert(filename);
3935 assert(lvalue);
3936 assert(rvalue);
3937 assert(data);
3938
3939 /* Our enum shall be a superset of booleans, hence first try
61233823 3940 * to parse as boolean, and then as enum */
417116f2
LP
3941
3942 k = parse_boolean(rvalue);
3943 if (k > 0)
1b8689f9 3944 c->protect_home = PROTECT_HOME_YES;
417116f2 3945 else if (k == 0)
1b8689f9 3946 c->protect_home = PROTECT_HOME_NO;
417116f2 3947 else {
1b8689f9 3948 ProtectHome h;
417116f2 3949
1b8689f9 3950 h = protect_home_from_string(rvalue);
9ed794a3 3951 if (h < 0) {
12ca818f 3952 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
3953 return 0;
3954 }
3955
1b8689f9
LP
3956 c->protect_home = h;
3957 }
3958
3959 return 0;
3960}
3961
3962int config_parse_protect_system(
3963 const char* unit,
3964 const char *filename,
3965 unsigned line,
3966 const char *section,
3967 unsigned section_line,
3968 const char *lvalue,
3969 int ltype,
3970 const char *rvalue,
3971 void *data,
3972 void *userdata) {
3973
3974 ExecContext *c = data;
3975 int k;
3976
3977 assert(filename);
3978 assert(lvalue);
3979 assert(rvalue);
3980 assert(data);
3981
3982 /* Our enum shall be a superset of booleans, hence first try
61233823 3983 * to parse as boolean, and then as enum */
1b8689f9
LP
3984
3985 k = parse_boolean(rvalue);
3986 if (k > 0)
3987 c->protect_system = PROTECT_SYSTEM_YES;
3988 else if (k == 0)
3989 c->protect_system = PROTECT_SYSTEM_NO;
3990 else {
3991 ProtectSystem s;
3992
3993 s = protect_system_from_string(rvalue);
9ed794a3 3994 if (s < 0) {
12ca818f 3995 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
1b8689f9
LP
3996 return 0;
3997 }
3998
3999 c->protect_system = s;
417116f2
LP
4000 }
4001
4002 return 0;
4003}
4004
071830ff 4005#define FOLLOW_MAX 8
87f0e418 4006
9e2f7c11 4007static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
a837f088 4008 char *id = NULL;
0301abf4 4009 unsigned c = 0;
87f0e418
LP
4010 int fd, r;
4011 FILE *f;
87f0e418
LP
4012
4013 assert(filename);
4014 assert(*filename);
4015 assert(_f);
4016 assert(names);
4017
0301abf4
LP
4018 /* This will update the filename pointer if the loaded file is
4019 * reached by a symlink. The old string will be freed. */
87f0e418 4020
0301abf4 4021 for (;;) {
2c7108c4 4022 char *target, *name;
87f0e418 4023
0301abf4
LP
4024 if (c++ >= FOLLOW_MAX)
4025 return -ELOOP;
4026
b08d03ff
LP
4027 path_kill_slashes(*filename);
4028
87f0e418 4029 /* Add the file name we are currently looking at to
8f05424d
LP
4030 * the names of this unit, but only if it is a valid
4031 * unit name. */
2b6bf07d 4032 name = basename(*filename);
7410616c 4033 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
8f05424d 4034
15e11d81
LP
4035 id = set_get(names, name);
4036 if (!id) {
4037 id = strdup(name);
4038 if (!id)
8f05424d 4039 return -ENOMEM;
87f0e418 4040
ef42202a
ZJS
4041 r = set_consume(names, id);
4042 if (r < 0)
8f05424d 4043 return r;
87f0e418 4044 }
87f0e418
LP
4045 }
4046
0301abf4 4047 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
4048 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
4049 if (fd >= 0)
87f0e418
LP
4050 break;
4051
0301abf4
LP
4052 if (errno != ELOOP)
4053 return -errno;
4054
87f0e418 4055 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
4056 r = readlink_and_make_absolute(*filename, &target);
4057 if (r < 0)
0301abf4 4058 return r;
87f0e418 4059
0301abf4 4060 free(*filename);
2c7108c4 4061 *filename = target;
87f0e418
LP
4062 }
4063
9946996c
LP
4064 f = fdopen(fd, "re");
4065 if (!f) {
03e334a1 4066 safe_close(fd);
d4ad27a1 4067 return -errno;
87f0e418
LP
4068 }
4069
4070 *_f = f;
9e2f7c11 4071 *_final = id;
a837f088 4072
0301abf4 4073 return 0;
87f0e418
LP
4074}
4075
23a177ef
LP
4076static int merge_by_names(Unit **u, Set *names, const char *id) {
4077 char *k;
4078 int r;
4079
4080 assert(u);
4081 assert(*u);
4082 assert(names);
4083
4084 /* Let's try to add in all symlink names we found */
4085 while ((k = set_steal_first(names))) {
4086
4087 /* First try to merge in the other name into our
4088 * unit */
9946996c
LP
4089 r = unit_merge_by_name(*u, k);
4090 if (r < 0) {
23a177ef
LP
4091 Unit *other;
4092
4093 /* Hmm, we couldn't merge the other unit into
4094 * ours? Then let's try it the other way
4095 * round */
4096
7aad67e7
MS
4097 /* If the symlink name we are looking at is unit template, then
4098 we must search for instance of this template */
9d3e3406 4099 if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
7aad67e7
MS
4100 _cleanup_free_ char *instance = NULL;
4101
4102 r = unit_name_replace_instance(k, (*u)->instance, &instance);
4103 if (r < 0)
4104 return r;
4105
4106 other = manager_get_unit((*u)->manager, instance);
4107 } else
4108 other = manager_get_unit((*u)->manager, k);
4109
23a177ef
LP
4110 free(k);
4111
9946996c
LP
4112 if (other) {
4113 r = unit_merge(other, *u);
4114 if (r >= 0) {
23a177ef
LP
4115 *u = other;
4116 return merge_by_names(u, names, NULL);
4117 }
9946996c 4118 }
23a177ef
LP
4119
4120 return r;
4121 }
4122
4123 if (id == k)
4124 unit_choose_id(*u, id);
4125
4126 free(k);
4127 }
4128
4129 return 0;
4130}
4131
e537352b 4132static int load_from_path(Unit *u, const char *path) {
e48614c4
ZJS
4133 _cleanup_set_free_free_ Set *symlink_names = NULL;
4134 _cleanup_fclose_ FILE *f = NULL;
4135 _cleanup_free_ char *filename = NULL;
4136 char *id = NULL;
23a177ef 4137 Unit *merged;
45fb0699 4138 struct stat st;
a837f088 4139 int r;
23a177ef
LP
4140
4141 assert(u);
e537352b 4142 assert(path);
3efd4195 4143
d5099efc 4144 symlink_names = set_new(&string_hash_ops);
f975e971 4145 if (!symlink_names)
87f0e418 4146 return -ENOMEM;
3efd4195 4147
036643a2
LP
4148 if (path_is_absolute(path)) {
4149
9946996c 4150 filename = strdup(path);
e48614c4
ZJS
4151 if (!filename)
4152 return -ENOMEM;
036643a2 4153
9946996c
LP
4154 r = open_follow(&filename, &f, symlink_names, &id);
4155 if (r < 0) {
97b11eed 4156 filename = mfree(filename);
036643a2 4157 if (r != -ENOENT)
e48614c4 4158 return r;
036643a2
LP
4159 }
4160
4161 } else {
4162 char **p;
4163
a3c4eb07 4164 STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
036643a2
LP
4165
4166 /* Instead of opening the path right away, we manually
4167 * follow all symlinks and add their name to our unit
4168 * name set while doing so */
9946996c 4169 filename = path_make_absolute(path, *p);
e48614c4
ZJS
4170 if (!filename)
4171 return -ENOMEM;
036643a2 4172
ac155bb8
MS
4173 if (u->manager->unit_path_cache &&
4174 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
4175 r = -ENOENT;
4176 else
4177 r = open_follow(&filename, &f, symlink_names, &id);
a837f088
LP
4178 if (r >= 0)
4179 break;
4180 filename = mfree(filename);
a1feacf7
ZJS
4181
4182 /* ENOENT means that the file is missing or is a dangling symlink.
4183 * ENOTDIR means that one of paths we expect to be is a directory
4184 * is not a directory, we should just ignore that.
4185 * EACCES means that the directory or file permissions are wrong.
4186 */
4187 if (r == -EACCES)
4188 log_debug_errno(r, "Cannot access \"%s\": %m", filename);
4189 else if (!IN_SET(r, -ENOENT, -ENOTDIR))
a837f088 4190 return r;
fe51822e 4191
a837f088
LP
4192 /* Empty the symlink names for the next run */
4193 set_clear_free(symlink_names);
036643a2
LP
4194 }
4195 }
034c6ed7 4196
e48614c4 4197 if (!filename)
8f05424d 4198 /* Hmm, no suitable file found? */
e48614c4 4199 return 0;
87f0e418 4200
8a993b61 4201 if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
a837f088
LP
4202 log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
4203 return -ELOOP;
4204 }
4205
23a177ef 4206 merged = u;
9946996c
LP
4207 r = merge_by_names(&merged, symlink_names, id);
4208 if (r < 0)
e48614c4 4209 return r;
87f0e418 4210
23a177ef 4211 if (merged != u) {
ac155bb8 4212 u->load_state = UNIT_MERGED;
e48614c4 4213 return 0;
034c6ed7
LP
4214 }
4215
e48614c4
ZJS
4216 if (fstat(fileno(f), &st) < 0)
4217 return -errno;
45fb0699 4218
3a8db9fe 4219 if (null_or_empty(&st)) {
ac155bb8 4220 u->load_state = UNIT_MASKED;
3a8db9fe
ZJS
4221 u->fragment_mtime = 0;
4222 } else {
c2756a68 4223 u->load_state = UNIT_LOADED;
3a8db9fe 4224 u->fragment_mtime = timespec_load(&st.st_mtim);
c2756a68 4225
00dc5d76 4226 /* Now, parse the file contents */
36f822c4
ZJS
4227 r = config_parse(u->id, filename, f,
4228 UNIT_VTABLE(u)->sections,
4229 config_item_perf_lookup, load_fragment_gperf_lookup,
4230 false, true, false, u);
f975e971 4231 if (r < 0)
e48614c4 4232 return r;
00dc5d76 4233 }
b08d03ff 4234
ac155bb8
MS
4235 free(u->fragment_path);
4236 u->fragment_path = filename;
0301abf4 4237 filename = NULL;
87f0e418 4238
1b64d026
LP
4239 if (u->source_path) {
4240 if (stat(u->source_path, &st) >= 0)
4241 u->source_mtime = timespec_load(&st.st_mtim);
4242 else
4243 u->source_mtime = 0;
4244 }
4245
e48614c4 4246 return 0;
0301abf4
LP
4247}
4248
e537352b 4249int unit_load_fragment(Unit *u) {
23a177ef 4250 int r;
294d81f1
LP
4251 Iterator i;
4252 const char *t;
0301abf4
LP
4253
4254 assert(u);
ac155bb8
MS
4255 assert(u->load_state == UNIT_STUB);
4256 assert(u->id);
23a177ef 4257
3f5e8115
LP
4258 if (u->transient) {
4259 u->load_state = UNIT_LOADED;
4260 return 0;
4261 }
4262
294d81f1
LP
4263 /* First, try to find the unit under its id. We always look
4264 * for unit files in the default directories, to make it easy
4265 * to override things by placing things in /etc/systemd/system */
9946996c
LP
4266 r = load_from_path(u, u->id);
4267 if (r < 0)
294d81f1
LP
4268 return r;
4269
4270 /* Try to find an alias we can load this with */
abc08d4d 4271 if (u->load_state == UNIT_STUB) {
ac155bb8 4272 SET_FOREACH(t, u->names, i) {
294d81f1 4273
ac155bb8 4274 if (t == u->id)
294d81f1
LP
4275 continue;
4276
9946996c
LP
4277 r = load_from_path(u, t);
4278 if (r < 0)
294d81f1
LP
4279 return r;
4280
ac155bb8 4281 if (u->load_state != UNIT_STUB)
294d81f1
LP
4282 break;
4283 }
abc08d4d 4284 }
23a177ef 4285
294d81f1 4286 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 4287 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 4288
9946996c
LP
4289 r = load_from_path(u, u->fragment_path);
4290 if (r < 0)
23a177ef 4291 return r;
0301abf4 4292
ece174c5 4293 if (u->load_state == UNIT_STUB)
6ccb1b44
LP
4294 /* Hmm, this didn't work? Then let's get rid
4295 * of the fragment path stored for us, so that
4296 * we don't point to an invalid location. */
a1e58e8e 4297 u->fragment_path = mfree(u->fragment_path);
6ccb1b44
LP
4298 }
4299
294d81f1 4300 /* Look for a template */
ac155bb8 4301 if (u->load_state == UNIT_STUB && u->instance) {
7410616c 4302 _cleanup_free_ char *k = NULL;
294d81f1 4303
7410616c
LP
4304 r = unit_name_template(u->id, &k);
4305 if (r < 0)
4306 return r;
294d81f1
LP
4307
4308 r = load_from_path(u, k);
294d81f1 4309 if (r < 0)
9e2f7c11 4310 return r;
890f434c 4311
abc08d4d 4312 if (u->load_state == UNIT_STUB) {
ac155bb8 4313 SET_FOREACH(t, u->names, i) {
bc9fd78c 4314 _cleanup_free_ char *z = NULL;
87f0e418 4315
ac155bb8 4316 if (t == u->id)
23a177ef 4317 continue;
071830ff 4318
7410616c
LP
4319 r = unit_name_template(t, &z);
4320 if (r < 0)
4321 return r;
294d81f1 4322
bc9fd78c 4323 r = load_from_path(u, z);
294d81f1 4324 if (r < 0)
23a177ef 4325 return r;
890f434c 4326
ac155bb8 4327 if (u->load_state != UNIT_STUB)
23a177ef
LP
4328 break;
4329 }
abc08d4d 4330 }
071830ff
LP
4331 }
4332
23a177ef 4333 return 0;
3efd4195 4334}
e537352b
LP
4335
4336void unit_dump_config_items(FILE *f) {
f975e971
LP
4337 static const struct {
4338 const ConfigParserCallback callback;
4339 const char *rvalue;
4340 } table[] = {
7f8aa671 4341#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
4342 { config_parse_warn_compat, "NOTSUPPORTED" },
4343#endif
f975e971
LP
4344 { config_parse_int, "INTEGER" },
4345 { config_parse_unsigned, "UNSIGNED" },
5556b5fe 4346 { config_parse_iec_size, "SIZE" },
59f448cf 4347 { config_parse_iec_uint64, "SIZE" },
5556b5fe 4348 { config_parse_si_size, "SIZE" },
f975e971
LP
4349 { config_parse_bool, "BOOLEAN" },
4350 { config_parse_string, "STRING" },
4351 { config_parse_path, "PATH" },
4352 { config_parse_unit_path_printf, "PATH" },
4353 { config_parse_strv, "STRING [...]" },
4354 { config_parse_exec_nice, "NICE" },
4355 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4356 { config_parse_exec_io_class, "IOCLASS" },
4357 { config_parse_exec_io_priority, "IOPRIORITY" },
4358 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4359 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4360 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4361 { config_parse_mode, "MODE" },
4362 { config_parse_unit_env_file, "FILE" },
52c239d7
LB
4363 { config_parse_exec_output, "OUTPUT" },
4364 { config_parse_exec_input, "INPUT" },
ca37242e
LP
4365 { config_parse_log_facility, "FACILITY" },
4366 { config_parse_log_level, "LEVEL" },
f975e971 4367 { config_parse_exec_secure_bits, "SECUREBITS" },
a103496c 4368 { config_parse_capability_set, "BOUNDINGSET" },
f975e971 4369 { config_parse_limit, "LIMIT" },
f975e971 4370 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
4371 { config_parse_exec, "PATH [ARGUMENT [...]]" },
4372 { config_parse_service_type, "SERVICETYPE" },
4373 { config_parse_service_restart, "SERVICERESTART" },
4374#ifdef HAVE_SYSV_COMPAT
4375 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
4376#endif
4377 { config_parse_kill_mode, "KILLMODE" },
f757855e 4378 { config_parse_signal, "SIGNAL" },
f975e971
LP
4379 { config_parse_socket_listen, "SOCKET [...]" },
4380 { config_parse_socket_bind, "SOCKETBIND" },
4381 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 4382 { config_parse_sec, "SECONDS" },
d88a251b 4383 { config_parse_nsec, "NANOSECONDS" },
94828d2d 4384 { config_parse_namespace_path_strv, "PATH [...]" },
7c8fa05c 4385 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
4386 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4387 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 4388 { config_parse_trigger_unit, "UNIT" },
f975e971 4389 { config_parse_timer, "TIMER" },
f975e971 4390 { config_parse_path_spec, "PATH" },
f975e971
LP
4391 { config_parse_notify_access, "ACCESS" },
4392 { config_parse_ip_tos, "TOS" },
4393 { config_parse_unit_condition_path, "CONDITION" },
4394 { config_parse_unit_condition_string, "CONDITION" },
4395 { config_parse_unit_condition_null, "CONDITION" },
a016b922 4396 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
4397 { config_parse_documentation, "URL" },
4398 { config_parse_service_timeout, "SECONDS" },
87a47f99 4399 { config_parse_emergency_action, "ACTION" },
7f0386f6
LP
4400 { config_parse_set_status, "STATUS" },
4401 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 4402 { config_parse_environ, "ENVIRON" },
c0467cf3 4403#ifdef HAVE_SECCOMP
17df7223 4404 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 4405 { config_parse_syscall_archs, "ARCHS" },
17df7223 4406 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 4407 { config_parse_address_families, "FAMILIES" },
add00535 4408 { config_parse_restrict_namespaces, "NAMESPACES" },
c0467cf3 4409#endif
7f0386f6 4410 { config_parse_cpu_shares, "SHARES" },
66ebf6c0 4411 { config_parse_cpu_weight, "WEIGHT" },
7f0386f6
LP
4412 { config_parse_memory_limit, "LIMIT" },
4413 { config_parse_device_allow, "DEVICE" },
4414 { config_parse_device_policy, "POLICY" },
13c31542
TH
4415 { config_parse_io_limit, "LIMIT" },
4416 { config_parse_io_weight, "WEIGHT" },
4417 { config_parse_io_device_weight, "DEVICEWEIGHT" },
7f0386f6
LP
4418 { config_parse_blockio_bandwidth, "BANDWIDTH" },
4419 { config_parse_blockio_weight, "WEIGHT" },
4420 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4421 { config_parse_long, "LONG" },
4422 { config_parse_socket_service, "SERVICE" },
6a6751fe
LP
4423#ifdef HAVE_SELINUX
4424 { config_parse_exec_selinux_context, "LABEL" },
4425#endif
4426 { config_parse_job_mode, "MODE" },
4427 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 4428 { config_parse_personality, "PERSONALITY" },
f975e971
LP
4429 };
4430
4431 const char *prev = NULL;
4432 const char *i;
4433
4434 assert(f);
e537352b 4435
f975e971
LP
4436 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4437 const char *rvalue = "OTHER", *lvalue;
4438 unsigned j;
4439 size_t prefix_len;
4440 const char *dot;
4441 const ConfigPerfItem *p;
4442
4443 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4444
4445 dot = strchr(i, '.');
4446 lvalue = dot ? dot + 1 : i;
4447 prefix_len = dot-i;
4448
4449 if (dot)
641906e9 4450 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
4451 if (prev)
4452 fputc('\n', f);
4453
4454 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
4455 }
4456
4457 for (j = 0; j < ELEMENTSOF(table); j++)
4458 if (p->parse == table[j].callback) {
4459 rvalue = table[j].rvalue;
4460 break;
4461 }
4462
4463 fprintf(f, "%s=%s\n", lvalue, rvalue);
4464 prev = i;
4465 }
e537352b 4466}