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