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