]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
cgroup: remove support for NetClass= directive
[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"
67#include "utf8.h"
49cf4170 68#include "web-util.h"
57183d11 69
17df7223
LP
70int config_parse_warn_compat(
71 const char *unit,
72 const char *filename,
73 unsigned line,
74 const char *section,
75 unsigned section_line,
76 const char *lvalue,
77 int ltype,
78 const char *rvalue,
79 void *data,
80 void *userdata) {
a2c0e528
ZJS
81 Disabled reason = ltype;
82
83 switch(reason) {
84 case DISABLED_CONFIGURATION:
12ca818f 85 log_syntax(unit, LOG_DEBUG, filename, line, 0,
a2c0e528
ZJS
86 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
87 break;
9e37c954 88 case DISABLED_LEGACY:
12ca818f 89 log_syntax(unit, LOG_INFO, filename, line, 0,
9e37c954
ZJS
90 "Support for option %s= has been removed and it is ignored", lvalue);
91 break;
a2c0e528 92 case DISABLED_EXPERIMENTAL:
12ca818f 93 log_syntax(unit, LOG_INFO, filename, line, 0,
a2c0e528
ZJS
94 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
95 break;
96 };
e8e581bf 97
07459bb6
FF
98 return 0;
99}
07459bb6 100
f32b43bd
LP
101int config_parse_unit_deps(
102 const char *unit,
103 const char *filename,
104 unsigned line,
105 const char *section,
106 unsigned section_line,
107 const char *lvalue,
108 int ltype,
109 const char *rvalue,
110 void *data,
111 void *userdata) {
3efd4195 112
f975e971 113 UnitDependency d = ltype;
87f0e418 114 Unit *u = userdata;
3d793d29 115 const char *p;
3efd4195
LP
116
117 assert(filename);
118 assert(lvalue);
119 assert(rvalue);
3efd4195 120
3d793d29
SS
121 p = rvalue;
122 for(;;) {
123 _cleanup_free_ char *word = NULL, *k = NULL;
3efd4195 124 int r;
3efd4195 125
c89f52ac 126 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
3d793d29
SS
127 if (r == 0)
128 break;
129 if (r == -ENOMEM)
74051b9b 130 return log_oom();
3d793d29
SS
131 if (r < 0) {
132 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
133 break;
134 }
3efd4195 135
3d793d29 136 r = unit_name_printf(u, word, &k);
19f6d710 137 if (r < 0) {
12ca818f 138 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
19f6d710
LP
139 continue;
140 }
9e2f7c11 141
701cc384 142 r = unit_add_dependency_by_name(u, d, k, NULL, true);
57020a3a 143 if (r < 0)
12ca818f 144 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
3efd4195
LP
145 }
146
147 return 0;
148}
149
f32b43bd
LP
150int config_parse_obsolete_unit_deps(
151 const char *unit,
152 const char *filename,
153 unsigned line,
154 const char *section,
155 unsigned section_line,
156 const char *lvalue,
157 int ltype,
158 const char *rvalue,
159 void *data,
160 void *userdata) {
161
162 log_syntax(unit, LOG_WARNING, filename, line, 0,
163 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
164
165 return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
166}
167
b02cb41c
LP
168int config_parse_unit_string_printf(
169 const char *unit,
170 const char *filename,
171 unsigned line,
172 const char *section,
173 unsigned section_line,
174 const char *lvalue,
175 int ltype,
176 const char *rvalue,
177 void *data,
178 void *userdata) {
932921b5 179
74051b9b 180 _cleanup_free_ char *k = NULL;
b02cb41c 181 Unit *u = userdata;
19f6d710 182 int r;
932921b5
LP
183
184 assert(filename);
185 assert(lvalue);
186 assert(rvalue);
f2d3769a 187 assert(u);
932921b5 188
19f6d710 189 r = unit_full_printf(u, rvalue, &k);
b02cb41c
LP
190 if (r < 0) {
191 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
192 return 0;
193 }
932921b5 194
b02cb41c 195 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
932921b5
LP
196}
197
12ca818f
LP
198int config_parse_unit_strv_printf(
199 const char *unit,
200 const char *filename,
201 unsigned line,
202 const char *section,
203 unsigned section_line,
204 const char *lvalue,
205 int ltype,
206 const char *rvalue,
207 void *data,
208 void *userdata) {
8fef7659
LP
209
210 Unit *u = userdata;
74051b9b 211 _cleanup_free_ char *k = NULL;
19f6d710 212 int r;
8fef7659
LP
213
214 assert(filename);
215 assert(lvalue);
216 assert(rvalue);
217 assert(u);
218
19f6d710 219 r = unit_full_printf(u, rvalue, &k);
12ca818f
LP
220 if (r < 0) {
221 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
222 return 0;
223 }
8fef7659 224
12ca818f 225 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
8fef7659
LP
226}
227
5f5d8eab
LP
228int config_parse_unit_path_printf(
229 const char *unit,
230 const char *filename,
231 unsigned line,
232 const char *section,
233 unsigned section_line,
234 const char *lvalue,
235 int ltype,
236 const char *rvalue,
237 void *data,
238 void *userdata) {
6ea832a2 239
74051b9b 240 _cleanup_free_ char *k = NULL;
811ba7a0 241 Unit *u = userdata;
19f6d710 242 int r;
6ea832a2
LP
243
244 assert(filename);
245 assert(lvalue);
246 assert(rvalue);
6ea832a2
LP
247 assert(u);
248
19f6d710 249 r = unit_full_printf(u, rvalue, &k);
811ba7a0 250 if (r < 0) {
12ca818f 251 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
811ba7a0
LP
252 return 0;
253 }
6ea832a2 254
811ba7a0
LP
255 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
256}
257
258int config_parse_unit_path_strv_printf(
259 const char *unit,
260 const char *filename,
261 unsigned line,
262 const char *section,
263 unsigned section_line,
264 const char *lvalue,
265 int ltype,
266 const char *rvalue,
267 void *data,
268 void *userdata) {
269
a2a5291b
ZJS
270 char ***x = data;
271 const char *word, *state;
811ba7a0
LP
272 Unit *u = userdata;
273 size_t l;
274 int r;
275
276 assert(filename);
277 assert(lvalue);
278 assert(rvalue);
279 assert(u);
280
a2a5291b 281 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
811ba7a0
LP
282 _cleanup_free_ char *k = NULL;
283 char t[l+1];
284
a2a5291b 285 memcpy(t, word, l);
811ba7a0
LP
286 t[l] = 0;
287
288 r = unit_full_printf(u, t, &k);
289 if (r < 0) {
12ca818f 290 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", t);
811ba7a0
LP
291 return 0;
292 }
293
294 if (!utf8_is_valid(k)) {
0e05ee04 295 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
811ba7a0
LP
296 return 0;
297 }
298
299 if (!path_is_absolute(k)) {
12ca818f 300 log_syntax(unit, LOG_ERR, filename, line, 0, "Symlink path %s is not absolute, ignoring: %m", k);
811ba7a0
LP
301 return 0;
302 }
303
304 path_kill_slashes(k);
305
306 r = strv_push(x, k);
307 if (r < 0)
308 return log_oom();
309
310 k = NULL;
311 }
b2fadec6 312 if (!isempty(state))
12ca818f 313 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
811ba7a0
LP
314
315 return 0;
6ea832a2
LP
316}
317
e8e581bf
ZJS
318int config_parse_socket_listen(const char *unit,
319 const char *filename,
320 unsigned line,
321 const char *section,
71a61510 322 unsigned section_line,
e8e581bf
ZJS
323 const char *lvalue,
324 int ltype,
325 const char *rvalue,
326 void *data,
327 void *userdata) {
42f4e3c4 328
b1389b0d
ZJS
329 _cleanup_free_ SocketPort *p = NULL;
330 SocketPort *tail;
542563ba 331 Socket *s;
19f6d710 332 int r;
16354eff 333
42f4e3c4
LP
334 assert(filename);
335 assert(lvalue);
336 assert(rvalue);
337 assert(data);
338
595ed347 339 s = SOCKET(data);
542563ba 340
74051b9b
LP
341 if (isempty(rvalue)) {
342 /* An empty assignment removes all ports */
343 socket_free_ports(s);
344 return 0;
345 }
346
7f110ff9
LP
347 p = new0(SocketPort, 1);
348 if (!p)
74051b9b 349 return log_oom();
916abb21 350
74051b9b 351 if (ltype != SOCKET_SOCKET) {
916abb21 352
74051b9b 353 p->type = ltype;
19f6d710
LP
354 r = unit_full_printf(UNIT(s), rvalue, &p->path);
355 if (r < 0) {
12ca818f
LP
356 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
357 return 0;
916abb21
LP
358 }
359
360 path_kill_slashes(p->path);
361
7a22745a 362 } else if (streq(lvalue, "ListenNetlink")) {
74051b9b 363 _cleanup_free_ char *k = NULL;
1fd45a90 364
7a22745a 365 p->type = SOCKET_SOCKET;
19f6d710 366 r = unit_full_printf(UNIT(s), rvalue, &k);
12ca818f
LP
367 if (r < 0) {
368 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
369 return 0;
370 }
7a22745a 371
12ca818f 372 r = socket_address_parse_netlink(&p->address, k);
1fd45a90 373 if (r < 0) {
12ca818f 374 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
7a22745a
LP
375 return 0;
376 }
377
542563ba 378 } else {
74051b9b 379 _cleanup_free_ char *k = NULL;
1fd45a90 380
542563ba 381 p->type = SOCKET_SOCKET;
19f6d710 382 r = unit_full_printf(UNIT(s), rvalue, &k);
12ca818f
LP
383 if (r < 0) {
384 log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
385 return 0;
386 }
542563ba 387
12ca818f 388 r = socket_address_parse_and_warn(&p->address, k);
1fd45a90 389 if (r < 0) {
12ca818f 390 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
c0b34696 391 return 0;
542563ba
LP
392 }
393
394 if (streq(lvalue, "ListenStream"))
395 p->address.type = SOCK_STREAM;
396 else if (streq(lvalue, "ListenDatagram"))
397 p->address.type = SOCK_DGRAM;
398 else {
399 assert(streq(lvalue, "ListenSequentialPacket"));
400 p->address.type = SOCK_SEQPACKET;
401 }
402
403 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
12ca818f 404 log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
c0b34696 405 return 0;
542563ba 406 }
16354eff
LP
407 }
408
542563ba 409 p->fd = -1;
15087cdb
PS
410 p->auxiliary_fds = NULL;
411 p->n_auxiliary_fds = 0;
2e41a51e 412 p->socket = s;
49f91047
LP
413
414 if (s->ports) {
71fda00f
LP
415 LIST_FIND_TAIL(port, s->ports, tail);
416 LIST_INSERT_AFTER(port, s->ports, tail, p);
49f91047 417 } else
71fda00f 418 LIST_PREPEND(port, s->ports, p);
b1389b0d 419 p = NULL;
542563ba 420
16354eff 421 return 0;
42f4e3c4
LP
422}
423
74bb646e
SS
424int config_parse_socket_protocol(const char *unit,
425 const char *filename,
426 unsigned line,
427 const char *section,
428 unsigned section_line,
429 const char *lvalue,
430 int ltype,
431 const char *rvalue,
432 void *data,
433 void *userdata) {
434 Socket *s;
435
436 assert(filename);
437 assert(lvalue);
438 assert(rvalue);
439 assert(data);
440
441 s = SOCKET(data);
442
443 if (streq(rvalue, "udplite"))
444 s->socket_protocol = IPPROTO_UDPLITE;
445 else if (streq(rvalue, "sctp"))
446 s->socket_protocol = IPPROTO_SCTP;
447 else {
448 log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
449 return 0;
450 }
451
452 return 0;
453}
454
e8e581bf
ZJS
455int config_parse_socket_bind(const char *unit,
456 const char *filename,
457 unsigned line,
458 const char *section,
71a61510 459 unsigned section_line,
e8e581bf
ZJS
460 const char *lvalue,
461 int ltype,
462 const char *rvalue,
463 void *data,
464 void *userdata) {
42f4e3c4 465
542563ba 466 Socket *s;
c0120d99 467 SocketAddressBindIPv6Only b;
42f4e3c4
LP
468
469 assert(filename);
470 assert(lvalue);
471 assert(rvalue);
472 assert(data);
473
595ed347 474 s = SOCKET(data);
542563ba 475
5198dabc
LP
476 b = socket_address_bind_ipv6_only_from_string(rvalue);
477 if (b < 0) {
c0120d99
LP
478 int r;
479
5198dabc
LP
480 r = parse_boolean(rvalue);
481 if (r < 0) {
12ca818f 482 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
c0b34696 483 return 0;
c0120d99 484 }
42f4e3c4 485
c0120d99
LP
486 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
487 } else
488 s->bind_ipv6_only = b;
542563ba 489
42f4e3c4
LP
490 return 0;
491}
492
e8e581bf
ZJS
493int config_parse_exec_nice(const char *unit,
494 const char *filename,
495 unsigned line,
496 const char *section,
71a61510 497 unsigned section_line,
e8e581bf
ZJS
498 const char *lvalue,
499 int ltype,
500 const char *rvalue,
501 void *data,
502 void *userdata) {
034c6ed7 503
fb33a393 504 ExecContext *c = data;
e8e581bf 505 int priority, r;
034c6ed7
LP
506
507 assert(filename);
508 assert(lvalue);
509 assert(rvalue);
510 assert(data);
511
e8e581bf
ZJS
512 r = safe_atoi(rvalue, &priority);
513 if (r < 0) {
12ca818f 514 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
c0b34696 515 return 0;
034c6ed7
LP
516 }
517
518 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
12ca818f 519 log_syntax(unit, LOG_ERR, filename, line, 0, "Nice priority out of range, ignoring: %s", rvalue);
c0b34696 520 return 0;
034c6ed7
LP
521 }
522
fb33a393 523 c->nice = priority;
71155933 524 c->nice_set = true;
fb33a393 525
034c6ed7
LP
526 return 0;
527}
528
e8e581bf
ZJS
529int config_parse_exec_oom_score_adjust(const char* unit,
530 const char *filename,
531 unsigned line,
532 const char *section,
71a61510 533 unsigned section_line,
e8e581bf
ZJS
534 const char *lvalue,
535 int ltype,
536 const char *rvalue,
537 void *data,
538 void *userdata) {
034c6ed7 539
fb33a393 540 ExecContext *c = data;
e8e581bf 541 int oa, r;
034c6ed7
LP
542
543 assert(filename);
544 assert(lvalue);
545 assert(rvalue);
546 assert(data);
547
e8e581bf
ZJS
548 r = safe_atoi(rvalue, &oa);
549 if (r < 0) {
12ca818f 550 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
c0b34696 551 return 0;
034c6ed7
LP
552 }
553
dd6c17b1 554 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
12ca818f 555 log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
c0b34696 556 return 0;
034c6ed7
LP
557 }
558
dd6c17b1
LP
559 c->oom_score_adjust = oa;
560 c->oom_score_adjust_set = true;
fb33a393 561
034c6ed7
LP
562 return 0;
563}
564
527b7a42
LP
565int config_parse_exec(
566 const char *unit,
567 const char *filename,
568 unsigned line,
569 const char *section,
570 unsigned section_line,
571 const char *lvalue,
572 int ltype,
573 const char *rvalue,
574 void *data,
575 void *userdata) {
034c6ed7 576
cb48dfca 577 _cleanup_free_ char *cmd = NULL;
46a0d98a 578 ExecCommand **e = data;
cb48dfca 579 Unit *u = userdata;
46a0d98a
FB
580 const char *p;
581 bool semicolon;
7f110ff9 582 int r;
034c6ed7
LP
583
584 assert(filename);
585 assert(lvalue);
586 assert(rvalue);
61e5d8ed 587 assert(e);
cb48dfca 588 assert(u);
034c6ed7 589
74051b9b 590 e += ltype;
c83f1f30 591 rvalue += strspn(rvalue, WHITESPACE);
c83f1f30 592
74051b9b
LP
593 if (isempty(rvalue)) {
594 /* An empty assignment resets the list */
f1acf85a 595 *e = exec_command_free_list(*e);
74051b9b
LP
596 return 0;
597 }
598
cb48dfca
WC
599 r = unit_full_printf(u, rvalue, &cmd);
600 if (r < 0) {
601 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
602 return 0;
603 }
604
605 p = cmd;
46a0d98a 606 do {
dea7b6b0
LP
607 _cleanup_free_ char *path = NULL, *firstword = NULL;
608 bool separate_argv0 = false, ignore = false;
609 _cleanup_free_ ExecCommand *nce = NULL;
46a0d98a
FB
610 _cleanup_strv_free_ char **n = NULL;
611 size_t nlen = 0, nbufsize = 0;
46a0d98a 612 char *f;
dea7b6b0 613 int i;
6c666e26 614
46a0d98a
FB
615 semicolon = false;
616
12ba2c44 617 r = extract_first_word_and_warn(&p, &firstword, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
618 if (r <= 0)
619 return 0;
6c666e26 620
46a0d98a
FB
621 f = firstword;
622 for (i = 0; i < 2; i++) {
623 /* We accept an absolute path as first argument, or
624 * alternatively an absolute prefixed with @ to allow
625 * overriding of argv[0]. */
626 if (*f == '-' && !ignore)
627 ignore = true;
628 else if (*f == '@' && !separate_argv0)
629 separate_argv0 = true;
630 else
631 break;
632 f ++;
61e5d8ed 633 }
46a0d98a
FB
634
635 if (isempty(f)) {
636 /* First word is either "-" or "@" with no command. */
12ca818f 637 log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
b2fadec6
ZJS
638 return 0;
639 }
46a0d98a 640 if (!string_is_safe(f)) {
12ca818f 641 log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
46a0d98a
FB
642 return 0;
643 }
644 if (!path_is_absolute(f)) {
12ca818f 645 log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
46a0d98a
FB
646 return 0;
647 }
648 if (endswith(f, "/")) {
12ca818f 649 log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
46a0d98a
FB
650 return 0;
651 }
61e5d8ed 652
46a0d98a
FB
653 if (f == firstword) {
654 path = firstword;
655 firstword = NULL;
656 } else {
657 path = strdup(f);
658 if (!path)
659 return log_oom();
660 }
7f110ff9 661
46a0d98a
FB
662 if (!separate_argv0) {
663 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
664 return log_oom();
665 f = strdup(path);
666 if (!f)
667 return log_oom();
668 n[nlen++] = f;
669 n[nlen] = NULL;
670 }
7f110ff9 671
46a0d98a
FB
672 path_kill_slashes(path);
673
4b1c1753 674 while (!isempty(p)) {
46a0d98a
FB
675 _cleanup_free_ char *word = NULL;
676
677 /* Check explicitly for an unquoted semicolon as
678 * command separator token. */
679 if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
680 p ++;
681 p += strspn(p, WHITESPACE);
682 semicolon = true;
683 break;
c8539536 684 }
7f110ff9 685
46a0d98a 686 /* Check for \; explicitly, to not confuse it with \\;
68685607 687 * or "\;" or "\\;" etc. extract_first_word would
46a0d98a
FB
688 * return the same for all of those. */
689 if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
690 p += 2;
691 p += strspn(p, WHITESPACE);
692 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
693 return log_oom();
694 f = strdup(";");
695 if (!f)
696 return log_oom();
697 n[nlen++] = f;
698 n[nlen] = NULL;
699 continue;
61e5d8ed 700 }
c8539536 701
12ba2c44 702 r = extract_first_word_and_warn(&p, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
703 if (r == 0)
704 break;
705 else if (r < 0)
706 return 0;
707
708 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
709 return log_oom();
710 n[nlen++] = word;
711 n[nlen] = NULL;
712 word = NULL;
61e5d8ed
LP
713 }
714
46a0d98a 715 if (!n || !n[0]) {
12ca818f 716 log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
46a0d98a 717 return 0;
7f110ff9 718 }
6c666e26 719
7f110ff9 720 nce = new0(ExecCommand, 1);
46a0d98a
FB
721 if (!nce)
722 return log_oom();
61e5d8ed
LP
723
724 nce->argv = n;
725 nce->path = path;
b708e7ce 726 nce->ignore = ignore;
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
e8e581bf
ZJS
744int config_parse_socket_bindtodevice(const char* unit,
745 const char *filename,
746 unsigned line,
747 const char *section,
71a61510 748 unsigned section_line,
e8e581bf
ZJS
749 const char *lvalue,
750 int ltype,
751 const char *rvalue,
752 void *data,
753 void *userdata) {
acbb0225
LP
754
755 Socket *s = data;
756 char *n;
757
758 assert(filename);
759 assert(lvalue);
760 assert(rvalue);
761 assert(data);
762
763 if (rvalue[0] && !streq(rvalue, "*")) {
74051b9b
LP
764 n = strdup(rvalue);
765 if (!n)
766 return log_oom();
acbb0225
LP
767 } else
768 n = NULL;
769
770 free(s->bind_to_device);
771 s->bind_to_device = n;
772
773 return 0;
774}
775
f975e971
LP
776DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
777DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
87f0e418 778
e8e581bf
ZJS
779int config_parse_exec_io_class(const char *unit,
780 const char *filename,
781 unsigned line,
782 const char *section,
71a61510 783 unsigned section_line,
e8e581bf
ZJS
784 const char *lvalue,
785 int ltype,
786 const char *rvalue,
787 void *data,
788 void *userdata) {
94f04347
LP
789
790 ExecContext *c = data;
791 int x;
792
793 assert(filename);
794 assert(lvalue);
795 assert(rvalue);
796 assert(data);
797
f8b69d1d
MS
798 x = ioprio_class_from_string(rvalue);
799 if (x < 0) {
12ca818f 800 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
c0b34696 801 return 0;
0d87eb42 802 }
94f04347
LP
803
804 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
805 c->ioprio_set = true;
806
807 return 0;
808}
809
e8e581bf
ZJS
810int config_parse_exec_io_priority(const char *unit,
811 const char *filename,
812 unsigned line,
813 const char *section,
71a61510 814 unsigned section_line,
e8e581bf
ZJS
815 const char *lvalue,
816 int ltype,
817 const char *rvalue,
818 void *data,
819 void *userdata) {
94f04347
LP
820
821 ExecContext *c = data;
e8e581bf 822 int i, r;
94f04347
LP
823
824 assert(filename);
825 assert(lvalue);
826 assert(rvalue);
827 assert(data);
828
e8e581bf
ZJS
829 r = safe_atoi(rvalue, &i);
830 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
12ca818f 831 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
c0b34696 832 return 0;
071830ff
LP
833 }
834
94f04347
LP
835 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
836 c->ioprio_set = true;
837
071830ff
LP
838 return 0;
839}
840
e8e581bf
ZJS
841int config_parse_exec_cpu_sched_policy(const char *unit,
842 const char *filename,
843 unsigned line,
844 const char *section,
71a61510 845 unsigned section_line,
e8e581bf
ZJS
846 const char *lvalue,
847 int ltype,
848 const char *rvalue,
849 void *data,
850 void *userdata) {
9eba9da4 851
94f04347
LP
852
853 ExecContext *c = data;
854 int x;
855
856 assert(filename);
857 assert(lvalue);
858 assert(rvalue);
859 assert(data);
860
f8b69d1d
MS
861 x = sched_policy_from_string(rvalue);
862 if (x < 0) {
12ca818f 863 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 864 return 0;
0d87eb42 865 }
94f04347
LP
866
867 c->cpu_sched_policy = x;
bb112710
HHPF
868 /* Moving to or from real-time policy? We need to adjust the priority */
869 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
94f04347
LP
870 c->cpu_sched_set = true;
871
872 return 0;
873}
874
e8e581bf
ZJS
875int config_parse_exec_cpu_sched_prio(const char *unit,
876 const char *filename,
877 unsigned line,
878 const char *section,
71a61510 879 unsigned section_line,
e8e581bf
ZJS
880 const char *lvalue,
881 int ltype,
882 const char *rvalue,
883 void *data,
884 void *userdata) {
9eba9da4
LP
885
886 ExecContext *c = data;
e8e581bf 887 int i, min, max, r;
9eba9da4
LP
888
889 assert(filename);
890 assert(lvalue);
891 assert(rvalue);
892 assert(data);
893
e8e581bf
ZJS
894 r = safe_atoi(rvalue, &i);
895 if (r < 0) {
12ca818f 896 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 897 return 0;
94f04347 898 }
9eba9da4 899
bb112710
HHPF
900 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
901 min = sched_get_priority_min(c->cpu_sched_policy);
902 max = sched_get_priority_max(c->cpu_sched_policy);
903
904 if (i < min || i > max) {
12ca818f 905 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
bb112710
HHPF
906 return 0;
907 }
908
94f04347
LP
909 c->cpu_sched_priority = i;
910 c->cpu_sched_set = true;
911
912 return 0;
913}
914
e8e581bf
ZJS
915int config_parse_exec_cpu_affinity(const char *unit,
916 const char *filename,
917 unsigned line,
918 const char *section,
71a61510 919 unsigned section_line,
e8e581bf
ZJS
920 const char *lvalue,
921 int ltype,
922 const char *rvalue,
923 void *data,
924 void *userdata) {
94f04347
LP
925
926 ExecContext *c = data;
9d5ca7f8
FB
927 _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
928 int ncpus;
94f04347
LP
929
930 assert(filename);
931 assert(lvalue);
932 assert(rvalue);
933 assert(data);
934
765d143b 935 ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
9d5ca7f8
FB
936 if (ncpus < 0)
937 return ncpus;
487393e9 938
9d5ca7f8
FB
939 if (c->cpuset)
940 CPU_FREE(c->cpuset);
82c121a4 941
9d5ca7f8
FB
942 if (ncpus == 0)
943 /* An empty assignment resets the CPU list */
944 c->cpuset = NULL;
945 else {
946 c->cpuset = cpuset;
947 cpuset = NULL;
9eba9da4 948 }
9d5ca7f8 949 c->cpuset_ncpus = ncpus;
9eba9da4 950
94f04347
LP
951 return 0;
952}
953
e8e581bf
ZJS
954int config_parse_exec_capabilities(const char *unit,
955 const char *filename,
956 unsigned line,
957 const char *section,
71a61510 958 unsigned section_line,
e8e581bf
ZJS
959 const char *lvalue,
960 int ltype,
961 const char *rvalue,
962 void *data,
963 void *userdata) {
94f04347
LP
964
965 ExecContext *c = data;
966 cap_t cap;
967
968 assert(filename);
969 assert(lvalue);
970 assert(rvalue);
971 assert(data);
972
74051b9b
LP
973 cap = cap_from_text(rvalue);
974 if (!cap) {
12ca818f 975 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue);
c0b34696 976 return 0;
94f04347
LP
977 }
978
979 if (c->capabilities)
980 cap_free(c->capabilities);
981 c->capabilities = cap;
982
983 return 0;
984}
985
e8e581bf
ZJS
986int config_parse_exec_secure_bits(const char *unit,
987 const char *filename,
988 unsigned line,
989 const char *section,
71a61510 990 unsigned section_line,
e8e581bf
ZJS
991 const char *lvalue,
992 int ltype,
993 const char *rvalue,
994 void *data,
995 void *userdata) {
94f04347
LP
996
997 ExecContext *c = data;
94f04347 998 size_t l;
a2a5291b 999 const char *word, *state;
94f04347
LP
1000
1001 assert(filename);
1002 assert(lvalue);
1003 assert(rvalue);
1004 assert(data);
1005
74051b9b
LP
1006 if (isempty(rvalue)) {
1007 /* An empty assignment resets the field */
1008 c->secure_bits = 0;
1009 return 0;
1010 }
1011
a2a5291b
ZJS
1012 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1013 if (first_word(word, "keep-caps"))
cbb21cca 1014 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
a2a5291b 1015 else if (first_word(word, "keep-caps-locked"))
cbb21cca 1016 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
a2a5291b 1017 else if (first_word(word, "no-setuid-fixup"))
cbb21cca 1018 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
a2a5291b 1019 else if (first_word(word, "no-setuid-fixup-locked"))
cbb21cca 1020 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
a2a5291b 1021 else if (first_word(word, "noroot"))
cbb21cca 1022 c->secure_bits |= 1<<SECURE_NOROOT;
a2a5291b 1023 else if (first_word(word, "noroot-locked"))
cbb21cca 1024 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
9eba9da4 1025 else {
12ca818f 1026 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse secure bits, ignoring: %s", rvalue);
c0b34696 1027 return 0;
9eba9da4
LP
1028 }
1029 }
b2fadec6 1030 if (!isempty(state))
12ca818f 1031 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring.");
9eba9da4 1032
94f04347
LP
1033 return 0;
1034}
1035
a103496c 1036int config_parse_capability_set(
65dce264
LP
1037 const char *unit,
1038 const char *filename,
1039 unsigned line,
1040 const char *section,
1041 unsigned section_line,
1042 const char *lvalue,
1043 int ltype,
1044 const char *rvalue,
1045 void *data,
1046 void *userdata) {
94f04347 1047
a103496c
IP
1048 uint64_t *capability_set = data;
1049 uint64_t sum = 0, initial = 0;
260abb78 1050 bool invert = false;
65dce264 1051 const char *p;
94f04347
LP
1052
1053 assert(filename);
1054 assert(lvalue);
1055 assert(rvalue);
1056 assert(data);
1057
260abb78
LP
1058 if (rvalue[0] == '~') {
1059 invert = true;
1060 rvalue++;
1061 }
1062
a103496c
IP
1063 if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
1064 initial = CAP_ALL; /* initialized to all bits on */
755d4b67 1065 /* else "AmbientCapabilities" initialized to all bits off */
260abb78 1066
65dce264 1067 p = rvalue;
9ef57298
EV
1068 for (;;) {
1069 _cleanup_free_ char *word = NULL;
65dce264 1070 int cap, r;
94f04347 1071
65dce264 1072 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
9ef57298
EV
1073 if (r == 0)
1074 break;
1075 if (r == -ENOMEM)
74051b9b 1076 return log_oom();
9ef57298 1077 if (r < 0) {
65dce264 1078 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
9ef57298
EV
1079 break;
1080 }
94f04347 1081
9ef57298 1082 cap = capability_from_name(word);
2822da4f 1083 if (cap < 0) {
755d4b67 1084 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
8351ceae 1085 continue;
94f04347
LP
1086 }
1087
65dce264 1088 sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
94f04347 1089 }
9eba9da4 1090
a103496c
IP
1091 sum = invert ? ~sum : sum;
1092
1093 if (sum == 0 || *capability_set == initial)
1094 /* "" or uninitialized data -> replace */
1095 *capability_set = sum;
260abb78 1096 else
a103496c
IP
1097 /* previous data -> merge */
1098 *capability_set |= sum;
260abb78 1099
9eba9da4
LP
1100 return 0;
1101}
1102
91518d20 1103int config_parse_limit(
d580265e
LP
1104 const char *unit,
1105 const char *filename,
1106 unsigned line,
1107 const char *section,
1108 unsigned section_line,
1109 const char *lvalue,
1110 int ltype,
1111 const char *rvalue,
1112 void *data,
1113 void *userdata) {
412ea7a9 1114
d0a7c5f6
LP
1115 struct rlimit **rl = data, d = {};
1116 int r;
a4c18002
LP
1117
1118 assert(filename);
1119 assert(lvalue);
1120 assert(rvalue);
1121 assert(data);
1122
d0a7c5f6
LP
1123 r = rlimit_parse(ltype, rvalue, &d);
1124 if (r == -EILSEQ) {
1125 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1126 return 0;
1127 }
1128 if (r < 0) {
1129 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1130 return 0;
1131 }
a4c18002 1132
d0a7c5f6
LP
1133 if (rl[ltype])
1134 *rl[ltype] = d;
1135 else {
1136 rl[ltype] = newdup(struct rlimit, &d, 1);
1137 if (!rl[ltype])
1138 return log_oom();
1139 }
a4c18002 1140
d0a7c5f6 1141 return 0;
91518d20 1142}
a4c18002 1143
07459bb6 1144#ifdef HAVE_SYSV_COMPAT
e8e581bf
ZJS
1145int config_parse_sysv_priority(const char *unit,
1146 const char *filename,
1147 unsigned line,
1148 const char *section,
71a61510 1149 unsigned section_line,
e8e581bf
ZJS
1150 const char *lvalue,
1151 int ltype,
1152 const char *rvalue,
1153 void *data,
1154 void *userdata) {
a9a1e00a
LP
1155
1156 int *priority = data;
e8e581bf 1157 int i, r;
a9a1e00a
LP
1158
1159 assert(filename);
1160 assert(lvalue);
1161 assert(rvalue);
1162 assert(data);
1163
e8e581bf
ZJS
1164 r = safe_atoi(rvalue, &i);
1165 if (r < 0 || i < 0) {
12ca818f 1166 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
c0b34696 1167 return 0;
a9a1e00a
LP
1168 }
1169
1170 *priority = (int) i;
1171 return 0;
1172}
07459bb6 1173#endif
a9a1e00a 1174
023a4f67 1175DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
f975e971 1176DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
50159e6a 1177
e8e581bf
ZJS
1178int config_parse_exec_mount_flags(const char *unit,
1179 const char *filename,
1180 unsigned line,
1181 const char *section,
71a61510 1182 unsigned section_line,
e8e581bf
ZJS
1183 const char *lvalue,
1184 int ltype,
1185 const char *rvalue,
1186 void *data,
1187 void *userdata) {
15ae422b 1188
e28bb14a 1189
15ae422b 1190 unsigned long flags = 0;
e28bb14a 1191 ExecContext *c = data;
15ae422b
LP
1192
1193 assert(filename);
1194 assert(lvalue);
1195 assert(rvalue);
1196 assert(data);
1197
e28bb14a
SS
1198 if (streq(rvalue, "shared"))
1199 flags = MS_SHARED;
1200 else if (streq(rvalue, "slave"))
1201 flags = MS_SLAVE;
1202 else if (streq(rvalue, "private"))
1203 flags = MS_PRIVATE;
1204 else {
1205 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
1206 return 0;
15ae422b
LP
1207 }
1208
1209 c->mount_flags = flags;
e28bb14a 1210
15ae422b
LP
1211 return 0;
1212}
1213
5f8640fb
LP
1214int config_parse_exec_selinux_context(
1215 const char *unit,
1216 const char *filename,
1217 unsigned line,
1218 const char *section,
1219 unsigned section_line,
1220 const char *lvalue,
1221 int ltype,
1222 const char *rvalue,
1223 void *data,
1224 void *userdata) {
1225
1226 ExecContext *c = data;
1227 Unit *u = userdata;
1228 bool ignore;
1229 char *k;
1230 int r;
1231
1232 assert(filename);
1233 assert(lvalue);
1234 assert(rvalue);
1235 assert(data);
1236
1237 if (isempty(rvalue)) {
a1e58e8e 1238 c->selinux_context = mfree(c->selinux_context);
5f8640fb
LP
1239 c->selinux_context_ignore = false;
1240 return 0;
1241 }
1242
1243 if (rvalue[0] == '-') {
1244 ignore = true;
1245 rvalue++;
1246 } else
1247 ignore = false;
1248
1249 r = unit_name_printf(u, rvalue, &k);
1250 if (r < 0) {
12ca818f 1251 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
5f8640fb
LP
1252 return 0;
1253 }
1254
1255 free(c->selinux_context);
1256 c->selinux_context = k;
1257 c->selinux_context_ignore = ignore;
1258
1259 return 0;
1260}
1261
eef65bf3
MS
1262int config_parse_exec_apparmor_profile(
1263 const char *unit,
1264 const char *filename,
1265 unsigned line,
1266 const char *section,
1267 unsigned section_line,
1268 const char *lvalue,
1269 int ltype,
1270 const char *rvalue,
1271 void *data,
1272 void *userdata) {
1273
1274 ExecContext *c = data;
1275 Unit *u = userdata;
1276 bool ignore;
1277 char *k;
1278 int r;
1279
1280 assert(filename);
1281 assert(lvalue);
1282 assert(rvalue);
1283 assert(data);
1284
1285 if (isempty(rvalue)) {
a1e58e8e 1286 c->apparmor_profile = mfree(c->apparmor_profile);
eef65bf3
MS
1287 c->apparmor_profile_ignore = false;
1288 return 0;
1289 }
1290
1291 if (rvalue[0] == '-') {
1292 ignore = true;
1293 rvalue++;
1294 } else
1295 ignore = false;
1296
1297 r = unit_name_printf(u, rvalue, &k);
1298 if (r < 0) {
12ca818f 1299 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
eef65bf3
MS
1300 return 0;
1301 }
1302
1303 free(c->apparmor_profile);
1304 c->apparmor_profile = k;
1305 c->apparmor_profile_ignore = ignore;
1306
1307 return 0;
1308}
1309
2ca620c4
WC
1310int config_parse_exec_smack_process_label(
1311 const char *unit,
1312 const char *filename,
1313 unsigned line,
1314 const char *section,
1315 unsigned section_line,
1316 const char *lvalue,
1317 int ltype,
1318 const char *rvalue,
1319 void *data,
1320 void *userdata) {
1321
1322 ExecContext *c = data;
1323 Unit *u = userdata;
1324 bool ignore;
1325 char *k;
1326 int r;
1327
1328 assert(filename);
1329 assert(lvalue);
1330 assert(rvalue);
1331 assert(data);
1332
1333 if (isempty(rvalue)) {
a1e58e8e 1334 c->smack_process_label = mfree(c->smack_process_label);
2ca620c4
WC
1335 c->smack_process_label_ignore = false;
1336 return 0;
1337 }
1338
1339 if (rvalue[0] == '-') {
1340 ignore = true;
1341 rvalue++;
1342 } else
1343 ignore = false;
1344
1345 r = unit_name_printf(u, rvalue, &k);
1346 if (r < 0) {
12ca818f 1347 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
2ca620c4
WC
1348 return 0;
1349 }
1350
1351 free(c->smack_process_label);
1352 c->smack_process_label = k;
1353 c->smack_process_label_ignore = ignore;
1354
1355 return 0;
1356}
1357
e8e581bf
ZJS
1358int config_parse_timer(const char *unit,
1359 const char *filename,
1360 unsigned line,
1361 const char *section,
71a61510 1362 unsigned section_line,
e8e581bf
ZJS
1363 const char *lvalue,
1364 int ltype,
1365 const char *rvalue,
1366 void *data,
1367 void *userdata) {
871d7de4
LP
1368
1369 Timer *t = data;
36697dc0 1370 usec_t u = 0;
871d7de4
LP
1371 TimerValue *v;
1372 TimerBase b;
36697dc0 1373 CalendarSpec *c = NULL;
871d7de4
LP
1374
1375 assert(filename);
1376 assert(lvalue);
1377 assert(rvalue);
1378 assert(data);
1379
74051b9b
LP
1380 if (isempty(rvalue)) {
1381 /* Empty assignment resets list */
1382 timer_free_values(t);
1383 return 0;
1384 }
1385
36697dc0
LP
1386 b = timer_base_from_string(lvalue);
1387 if (b < 0) {
12ca818f 1388 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
c0b34696 1389 return 0;
871d7de4
LP
1390 }
1391
36697dc0
LP
1392 if (b == TIMER_CALENDAR) {
1393 if (calendar_spec_from_string(rvalue, &c) < 0) {
12ca818f 1394 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue);
36697dc0
LP
1395 return 0;
1396 }
36697dc0 1397 } else {
7f602784 1398 if (parse_sec(rvalue, &u) < 0) {
12ca818f 1399 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", rvalue);
36697dc0
LP
1400 return 0;
1401 }
871d7de4
LP
1402 }
1403
36697dc0 1404 v = new0(TimerValue, 1);
4d5e13a1 1405 if (!v) {
0b76b4d8 1406 calendar_spec_free(c);
74051b9b 1407 return log_oom();
4d5e13a1 1408 }
871d7de4
LP
1409
1410 v->base = b;
1411 v->value = u;
36697dc0 1412 v->calendar_spec = c;
871d7de4 1413
71fda00f 1414 LIST_PREPEND(value, t->values, v);
871d7de4
LP
1415
1416 return 0;
1417}
1418
3ecaa09b
LP
1419int config_parse_trigger_unit(
1420 const char *unit,
1421 const char *filename,
1422 unsigned line,
1423 const char *section,
71a61510 1424 unsigned section_line,
3ecaa09b
LP
1425 const char *lvalue,
1426 int ltype,
1427 const char *rvalue,
1428 void *data,
1429 void *userdata) {
871d7de4 1430
74051b9b 1431 _cleanup_free_ char *p = NULL;
3ecaa09b
LP
1432 Unit *u = data;
1433 UnitType type;
1434 int r;
398ef8ba
LP
1435
1436 assert(filename);
1437 assert(lvalue);
1438 assert(rvalue);
1439 assert(data);
1440
3ecaa09b 1441 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
12ca818f 1442 log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
3ecaa09b
LP
1443 return 0;
1444 }
871d7de4 1445
19f6d710 1446 r = unit_name_printf(u, rvalue, &p);
12ca818f
LP
1447 if (r < 0) {
1448 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1449 return 0;
1450 }
74051b9b 1451
12ca818f 1452 type = unit_name_to_type(p);
3ecaa09b 1453 if (type < 0) {
12ca818f 1454 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
c0b34696 1455 return 0;
871d7de4
LP
1456 }
1457
3ecaa09b 1458 if (type == u->type) {
12ca818f 1459 log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
3ecaa09b
LP
1460 return 0;
1461 }
1462
12ca818f 1463 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
57020a3a 1464 if (r < 0) {
12ca818f 1465 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
c0b34696 1466 return 0;
871d7de4
LP
1467 }
1468
1469 return 0;
1470}
1471
e8e581bf
ZJS
1472int config_parse_path_spec(const char *unit,
1473 const char *filename,
1474 unsigned line,
1475 const char *section,
71a61510 1476 unsigned section_line,
e8e581bf
ZJS
1477 const char *lvalue,
1478 int ltype,
1479 const char *rvalue,
1480 void *data,
1481 void *userdata) {
01f78473
LP
1482
1483 Path *p = data;
1484 PathSpec *s;
1485 PathType b;
7fd1b19b 1486 _cleanup_free_ char *k = NULL;
19f6d710 1487 int r;
01f78473
LP
1488
1489 assert(filename);
1490 assert(lvalue);
1491 assert(rvalue);
1492 assert(data);
1493
74051b9b
LP
1494 if (isempty(rvalue)) {
1495 /* Empty assignment clears list */
1496 path_free_specs(p);
1497 return 0;
1498 }
1499
93e4c84b
LP
1500 b = path_type_from_string(lvalue);
1501 if (b < 0) {
12ca818f 1502 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 1503 return 0;
01f78473
LP
1504 }
1505
19f6d710
LP
1506 r = unit_full_printf(UNIT(p), rvalue, &k);
1507 if (r < 0) {
12ca818f
LP
1508 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1509 return 0;
487060c2 1510 }
93e4c84b
LP
1511
1512 if (!path_is_absolute(k)) {
12ca818f 1513 log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
c0b34696 1514 return 0;
01f78473
LP
1515 }
1516
93e4c84b 1517 s = new0(PathSpec, 1);
543295ad 1518 if (!s)
93e4c84b 1519 return log_oom();
01f78473 1520
718db961 1521 s->unit = UNIT(p);
93e4c84b 1522 s->path = path_kill_slashes(k);
543295ad 1523 k = NULL;
01f78473
LP
1524 s->type = b;
1525 s->inotify_fd = -1;
1526
71fda00f 1527 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
1528
1529 return 0;
1530}
1531
b02cb41c
LP
1532int config_parse_socket_service(
1533 const char *unit,
1534 const char *filename,
1535 unsigned line,
1536 const char *section,
1537 unsigned section_line,
1538 const char *lvalue,
1539 int ltype,
1540 const char *rvalue,
1541 void *data,
1542 void *userdata) {
d9ff321a 1543
4afd3348 1544 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8dd4c05b 1545 _cleanup_free_ char *p = NULL;
d9ff321a 1546 Socket *s = data;
4ff77f66 1547 Unit *x;
8dd4c05b 1548 int r;
d9ff321a
LP
1549
1550 assert(filename);
1551 assert(lvalue);
1552 assert(rvalue);
1553 assert(data);
1554
19f6d710 1555 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 1556 if (r < 0) {
b02cb41c 1557 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
613b411c
LP
1558 return 0;
1559 }
74051b9b 1560
613b411c 1561 if (!endswith(p, ".service")) {
12ca818f 1562 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
d9ff321a
LP
1563 return 0;
1564 }
1565
613b411c 1566 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 1567 if (r < 0) {
12ca818f 1568 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
d9ff321a
LP
1569 return 0;
1570 }
1571
4ff77f66
LP
1572 unit_ref_set(&s->service, x);
1573
d9ff321a
LP
1574 return 0;
1575}
1576
8dd4c05b
LP
1577int config_parse_fdname(
1578 const char *unit,
1579 const char *filename,
1580 unsigned line,
1581 const char *section,
1582 unsigned section_line,
1583 const char *lvalue,
1584 int ltype,
1585 const char *rvalue,
1586 void *data,
1587 void *userdata) {
1588
1589 _cleanup_free_ char *p = NULL;
1590 Socket *s = data;
1591 int r;
1592
1593 assert(filename);
1594 assert(lvalue);
1595 assert(rvalue);
1596 assert(data);
1597
1598 if (isempty(rvalue)) {
1599 s->fdname = mfree(s->fdname);
1600 return 0;
1601 }
1602
1603 r = unit_name_printf(UNIT(s), rvalue, &p);
1604 if (r < 0) {
1605 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1606 return 0;
1607 }
1608
1609 if (!fdname_is_valid(p)) {
1610 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
1611 return 0;
1612 }
1613
1614 free(s->fdname);
1615 s->fdname = p;
1616 p = NULL;
1617
1618 return 0;
1619}
1620
b02cb41c
LP
1621int config_parse_service_sockets(
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) {
f976f3f6
LP
1632
1633 Service *s = data;
7b2313f5 1634 const char *p;
b02cb41c 1635 int r;
f976f3f6
LP
1636
1637 assert(filename);
1638 assert(lvalue);
1639 assert(rvalue);
1640 assert(data);
1641
7b2313f5
SS
1642 p = rvalue;
1643 for(;;) {
6a0f3175 1644 _cleanup_free_ char *word = NULL, *k = NULL;
f976f3f6 1645
7b2313f5
SS
1646 r = extract_first_word(&p, &word, NULL, 0);
1647 if (r == 0)
1648 break;
1649 if (r == -ENOMEM)
74051b9b 1650 return log_oom();
7b2313f5
SS
1651 if (r < 0) {
1652 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
1653 break;
1654 }
f976f3f6 1655
7b2313f5 1656 r = unit_name_printf(UNIT(s), word, &k);
b02cb41c
LP
1657 if (r < 0) {
1658 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1659 continue;
1660 }
57020a3a 1661
b02cb41c 1662 if (!endswith(k, ".socket")) {
12ca818f 1663 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
f976f3f6
LP
1664 continue;
1665 }
1666
b02cb41c 1667 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
57020a3a 1668 if (r < 0)
b02cb41c 1669 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 1670
b02cb41c 1671 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
57020a3a 1672 if (r < 0)
b02cb41c 1673 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6
LP
1674 }
1675
1676 return 0;
1677}
1678
b02cb41c
LP
1679int config_parse_bus_name(
1680 const char *unit,
1681 const char *filename,
1682 unsigned line,
1683 const char *section,
1684 unsigned section_line,
1685 const char *lvalue,
1686 int ltype,
1687 const char *rvalue,
1688 void *data,
1689 void *userdata) {
1690
1691 _cleanup_free_ char *k = NULL;
1692 Unit *u = userdata;
1693 int r;
1694
1695 assert(filename);
1696 assert(lvalue);
1697 assert(rvalue);
1698 assert(u);
1699
1700 r = unit_full_printf(u, rvalue, &k);
1701 if (r < 0) {
1702 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1703 return 0;
1704 }
1705
1706 if (!service_name_is_valid(k)) {
12ca818f 1707 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
b02cb41c
LP
1708 return 0;
1709 }
1710
1711 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1712}
1713
e8e581bf
ZJS
1714int config_parse_service_timeout(const char *unit,
1715 const char *filename,
1716 unsigned line,
1717 const char *section,
71a61510 1718 unsigned section_line,
e8e581bf
ZJS
1719 const char *lvalue,
1720 int ltype,
1721 const char *rvalue,
1722 void *data,
1723 void *userdata) {
98709151
LN
1724
1725 Service *s = userdata;
1726 int r;
1727
1728 assert(filename);
1729 assert(lvalue);
1730 assert(rvalue);
1731 assert(s);
1732
71a61510 1733 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 1734 rvalue, data, userdata);
74051b9b 1735 if (r < 0)
d568a335 1736 return r;
98709151 1737
d568a335
MS
1738 if (streq(lvalue, "TimeoutSec")) {
1739 s->start_timeout_defined = true;
1740 s->timeout_stop_usec = s->timeout_start_usec;
1741 } else if (streq(lvalue, "TimeoutStartSec"))
1742 s->start_timeout_defined = true;
1743
36c16a7c
LP
1744 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1745 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1746 * all other timeouts. */
1747
1748 if (s->timeout_start_usec <= 0)
1749 s->timeout_start_usec = USEC_INFINITY;
1750 if (s->timeout_stop_usec <= 0)
1751 s->timeout_stop_usec = USEC_INFINITY;
1752
d568a335 1753 return 0;
98709151
LN
1754}
1755
e821075a
LP
1756int config_parse_busname_service(
1757 const char *unit,
1758 const char *filename,
1759 unsigned line,
1760 const char *section,
1761 unsigned section_line,
1762 const char *lvalue,
1763 int ltype,
1764 const char *rvalue,
1765 void *data,
1766 void *userdata) {
1767
4afd3348 1768 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
e821075a
LP
1769 BusName *n = data;
1770 int r;
1771 Unit *x;
1772 _cleanup_free_ char *p = NULL;
1773
1774 assert(filename);
1775 assert(lvalue);
1776 assert(rvalue);
1777 assert(data);
1778
1779 r = unit_name_printf(UNIT(n), rvalue, &p);
1780 if (r < 0) {
12ca818f 1781 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
e821075a
LP
1782 return 0;
1783 }
1784
1785 if (!endswith(p, ".service")) {
12ca818f 1786 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
e821075a
LP
1787 return 0;
1788 }
1789
1790 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1791 if (r < 0) {
12ca818f 1792 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
e821075a
LP
1793 return 0;
1794 }
1795
1796 unit_ref_set(&n->service, x);
1797
1798 return 0;
1799}
1800
5369c77d 1801DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
a4152e3f 1802
54d76c92
DM
1803int config_parse_bus_policy(
1804 const char *unit,
1805 const char *filename,
1806 unsigned line,
1807 const char *section,
1808 unsigned section_line,
1809 const char *lvalue,
1810 int ltype,
1811 const char *rvalue,
1812 void *data,
1813 void *userdata) {
1814
1815 _cleanup_free_ BusNamePolicy *p = NULL;
1816 _cleanup_free_ char *id_str = NULL;
1817 BusName *busname = data;
1818 char *access_str;
54d76c92
DM
1819
1820 assert(filename);
1821 assert(lvalue);
1822 assert(rvalue);
1823 assert(data);
1824
1825 p = new0(BusNamePolicy, 1);
1826 if (!p)
1827 return log_oom();
1828
1829 if (streq(lvalue, "AllowUser"))
1830 p->type = BUSNAME_POLICY_TYPE_USER;
1831 else if (streq(lvalue, "AllowGroup"))
1832 p->type = BUSNAME_POLICY_TYPE_GROUP;
54d76c92
DM
1833 else
1834 assert_not_reached("Unknown lvalue");
1835
1836 id_str = strdup(rvalue);
1837 if (!id_str)
1838 return log_oom();
1839
a4152e3f
LP
1840 access_str = strpbrk(id_str, WHITESPACE);
1841 if (!access_str) {
12ca818f 1842 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
a4152e3f 1843 return 0;
54d76c92
DM
1844 }
1845
a4152e3f
LP
1846 *access_str = '\0';
1847 access_str++;
1848 access_str += strspn(access_str, WHITESPACE);
1849
5369c77d 1850 p->access = bus_policy_access_from_string(access_str);
54d76c92 1851 if (p->access < 0) {
12ca818f 1852 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
54d76c92
DM
1853 return 0;
1854 }
1855
a4152e3f
LP
1856 p->name = id_str;
1857 id_str = NULL;
1858
54d76c92
DM
1859 LIST_PREPEND(policy, busname->policy, p);
1860 p = NULL;
1861
1862 return 0;
1863}
1864
50199623
DM
1865int config_parse_bus_endpoint_policy(
1866 const char *unit,
1867 const char *filename,
1868 unsigned line,
1869 const char *section,
1870 unsigned section_line,
1871 const char *lvalue,
1872 int ltype,
1873 const char *rvalue,
1874 void *data,
1875 void *userdata) {
1876
1877 _cleanup_free_ char *name = NULL;
1878 BusPolicyAccess access;
1879 ExecContext *c = data;
1880 char *access_str;
1881 int r;
1882
1883 assert(filename);
1884 assert(lvalue);
1885 assert(rvalue);
1886 assert(data);
1887
1888 name = strdup(rvalue);
1889 if (!name)
1890 return log_oom();
1891
1892 access_str = strpbrk(name, WHITESPACE);
1893 if (!access_str) {
12ca818f 1894 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue);
50199623
DM
1895 return 0;
1896 }
1897
1898 *access_str = '\0';
1899 access_str++;
1900 access_str += strspn(access_str, WHITESPACE);
1901
1902 access = bus_policy_access_from_string(access_str);
1903 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1904 access >= _BUS_POLICY_ACCESS_MAX) {
12ca818f 1905 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str);
50199623
DM
1906 return 0;
1907 }
1908
1909 if (!c->bus_endpoint) {
1910 r = bus_endpoint_new(&c->bus_endpoint);
50199623 1911 if (r < 0)
12ca818f 1912 return log_error_errno(r, "Failed to create bus endpoint object: %m");
50199623
DM
1913 }
1914
1915 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1916}
1917
5f5d8eab
LP
1918int config_parse_working_directory(
1919 const char *unit,
1920 const char *filename,
1921 unsigned line,
1922 const char *section,
1923 unsigned section_line,
1924 const char *lvalue,
1925 int ltype,
1926 const char *rvalue,
1927 void *data,
1928 void *userdata) {
1929
1930 ExecContext *c = data;
1931 Unit *u = userdata;
1932 bool missing_ok;
1933 int r;
1934
1935 assert(filename);
1936 assert(lvalue);
1937 assert(rvalue);
1938 assert(c);
1939 assert(u);
1940
1941 if (rvalue[0] == '-') {
1942 missing_ok = true;
1943 rvalue++;
1944 } else
1945 missing_ok = false;
1946
1947 if (streq(rvalue, "~")) {
1948 c->working_directory_home = true;
1949 c->working_directory = mfree(c->working_directory);
1950 } else {
1951 _cleanup_free_ char *k = NULL;
1952
1953 r = unit_full_printf(u, rvalue, &k);
1954 if (r < 0) {
1955 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
1956 return 0;
1957 }
1958
1959 path_kill_slashes(k);
1960
1961 if (!utf8_is_valid(k)) {
0e05ee04 1962 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
5f5d8eab
LP
1963 return 0;
1964 }
1965
1966 if (!path_is_absolute(k)) {
1967 log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
1968 return 0;
1969 }
1970
1971 free(c->working_directory);
1972 c->working_directory = k;
1973 k = NULL;
1974
1975 c->working_directory_home = false;
1976 }
1977
1978 c->working_directory_missing_ok = missing_ok;
1979 return 0;
1980}
1981
e8e581bf
ZJS
1982int config_parse_unit_env_file(const char *unit,
1983 const char *filename,
1984 unsigned line,
1985 const char *section,
71a61510 1986 unsigned section_line,
e8e581bf
ZJS
1987 const char *lvalue,
1988 int ltype,
1989 const char *rvalue,
1990 void *data,
1991 void *userdata) {
ddb26e18 1992
853b8397 1993 char ***env = data;
8fef7659 1994 Unit *u = userdata;
19f6d710 1995 _cleanup_free_ char *n = NULL;
853b8397 1996 int r;
ddb26e18
LP
1997
1998 assert(filename);
1999 assert(lvalue);
2000 assert(rvalue);
2001 assert(data);
2002
74051b9b
LP
2003 if (isempty(rvalue)) {
2004 /* Empty assignment frees the list */
6796073e 2005 *env = strv_free(*env);
74051b9b
LP
2006 return 0;
2007 }
2008
19f6d710 2009 r = unit_full_printf(u, rvalue, &n);
12ca818f
LP
2010 if (r < 0) {
2011 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2012 return 0;
2013 }
8fef7659 2014
12ca818f
LP
2015 if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
2016 log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
afe4bfe2
LP
2017 return 0;
2018 }
2019
12ca818f 2020 r = strv_extend(env, n);
853b8397
LP
2021 if (r < 0)
2022 return log_oom();
2023
2024 return 0;
2025}
2026
e8e581bf
ZJS
2027int config_parse_environ(const char *unit,
2028 const char *filename,
2029 unsigned line,
2030 const char *section,
71a61510 2031 unsigned section_line,
e8e581bf
ZJS
2032 const char *lvalue,
2033 int ltype,
2034 const char *rvalue,
2035 void *data,
2036 void *userdata) {
853b8397
LP
2037
2038 Unit *u = userdata;
a2a5291b
ZJS
2039 char*** env = data;
2040 const char *word, *state;
853b8397
LP
2041 size_t l;
2042 _cleanup_free_ char *k = NULL;
19f6d710 2043 int r;
853b8397
LP
2044
2045 assert(filename);
2046 assert(lvalue);
2047 assert(rvalue);
97d0e5f8 2048 assert(data);
853b8397
LP
2049
2050 if (isempty(rvalue)) {
2051 /* Empty assignment resets the list */
6796073e 2052 *env = strv_free(*env);
853b8397
LP
2053 return 0;
2054 }
2055
19f6d710
LP
2056 if (u) {
2057 r = unit_full_printf(u, rvalue, &k);
12ca818f
LP
2058 if (r < 0) {
2059 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2060 return 0;
2061 }
19f6d710 2062 }
97d0e5f8 2063
12ca818f 2064 if (!k) {
19f6d710 2065 k = strdup(rvalue);
12ca818f
LP
2066 if (!k)
2067 return log_oom();
2068 }
ddb26e18 2069
a2a5291b 2070 FOREACH_WORD_QUOTED(word, l, k, state) {
67a3328f 2071 _cleanup_free_ char *n = NULL;
853b8397
LP
2072 char **x;
2073
527b7a42
LP
2074 r = cunescape_length(word, l, 0, &n);
2075 if (r < 0) {
2076 log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
2077 continue;
2078 }
853b8397
LP
2079
2080 if (!env_assignment_is_valid(n)) {
12ca818f 2081 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue);
853b8397
LP
2082 continue;
2083 }
2084
2085 x = strv_env_set(*env, n);
2086 if (!x)
2087 return log_oom();
2088
2089 strv_free(*env);
2090 *env = x;
2091 }
b2fadec6 2092 if (!isempty(state))
12ca818f 2093 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
ddb26e18 2094
8c7be95e 2095 return 0;
ddb26e18
LP
2096}
2097
b4c14404
FB
2098int config_parse_pass_environ(const char *unit,
2099 const char *filename,
2100 unsigned line,
2101 const char *section,
2102 unsigned section_line,
2103 const char *lvalue,
2104 int ltype,
2105 const char *rvalue,
2106 void *data,
2107 void *userdata) {
2108
2109 const char *whole_rvalue = rvalue;
2110 char*** passenv = data;
2111 _cleanup_strv_free_ char **n = NULL;
2112 size_t nlen = 0, nbufsize = 0;
2113 int r;
2114
2115 assert(filename);
2116 assert(lvalue);
2117 assert(rvalue);
2118 assert(data);
2119
2120 if (isempty(rvalue)) {
2121 /* Empty assignment resets the list */
2122 *passenv = strv_free(*passenv);
2123 return 0;
2124 }
2125
2126 for (;;) {
2127 _cleanup_free_ char *word = NULL;
2128
2129 r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
2130 if (r == 0)
2131 break;
2132 if (r == -ENOMEM)
2133 return log_oom();
2134 if (r < 0) {
2135 log_syntax(unit, LOG_ERR, filename, line, r,
2136 "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
2137 break;
2138 }
2139
2140 if (!env_name_is_valid(word)) {
2141 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2142 "Invalid environment name for %s, ignoring: %s", lvalue, word);
2143 continue;
2144 }
2145
2146 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2147 return log_oom();
2148 n[nlen++] = word;
2149 n[nlen] = NULL;
2150 word = NULL;
2151 }
2152
2153 if (n) {
2154 r = strv_extend_strv(passenv, n, true);
2155 if (r < 0)
2156 return r;
2157 }
2158
2159 return 0;
2160}
2161
e8e581bf
ZJS
2162int config_parse_ip_tos(const char *unit,
2163 const char *filename,
2164 unsigned line,
2165 const char *section,
71a61510 2166 unsigned section_line,
e8e581bf
ZJS
2167 const char *lvalue,
2168 int ltype,
2169 const char *rvalue,
2170 void *data,
2171 void *userdata) {
4fd5948e
LP
2172
2173 int *ip_tos = data, x;
4fd5948e
LP
2174
2175 assert(filename);
2176 assert(lvalue);
2177 assert(rvalue);
2178 assert(data);
2179
f8b69d1d
MS
2180 x = ip_tos_from_string(rvalue);
2181 if (x < 0) {
12ca818f 2182 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
f8b69d1d
MS
2183 return 0;
2184 }
4fd5948e
LP
2185
2186 *ip_tos = x;
2187 return 0;
2188}
2189
59fccdc5
LP
2190int config_parse_unit_condition_path(
2191 const char *unit,
2192 const char *filename,
2193 unsigned line,
2194 const char *section,
2195 unsigned section_line,
2196 const char *lvalue,
2197 int ltype,
2198 const char *rvalue,
2199 void *data,
2200 void *userdata) {
52661efd 2201
2fbe635a 2202 _cleanup_free_ char *p = NULL;
59fccdc5
LP
2203 Condition **list = data, *c;
2204 ConditionType t = ltype;
2205 bool trigger, negate;
2206 Unit *u = userdata;
19f6d710 2207 int r;
52661efd
LP
2208
2209 assert(filename);
2210 assert(lvalue);
2211 assert(rvalue);
2212 assert(data);
2213
74051b9b
LP
2214 if (isempty(rvalue)) {
2215 /* Empty assignment resets the list */
447021aa 2216 *list = condition_free_list(*list);
74051b9b
LP
2217 return 0;
2218 }
2219
ab7f148f
LP
2220 trigger = rvalue[0] == '|';
2221 if (trigger)
267632f0
LP
2222 rvalue++;
2223
ab7f148f
LP
2224 negate = rvalue[0] == '!';
2225 if (negate)
52661efd
LP
2226 rvalue++;
2227
19f6d710 2228 r = unit_full_printf(u, rvalue, &p);
59fccdc5 2229 if (r < 0) {
12ca818f 2230 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
59fccdc5 2231 return 0;
19f6d710 2232 }
095b2d7a
AK
2233
2234 if (!path_is_absolute(p)) {
12ca818f 2235 log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
52661efd
LP
2236 return 0;
2237 }
2238
59fccdc5 2239 c = condition_new(t, p, trigger, negate);
ab7f148f 2240 if (!c)
74051b9b 2241 return log_oom();
52661efd 2242
59fccdc5 2243 LIST_PREPEND(conditions, *list, c);
52661efd
LP
2244 return 0;
2245}
2246
59fccdc5
LP
2247int config_parse_unit_condition_string(
2248 const char *unit,
2249 const char *filename,
2250 unsigned line,
2251 const char *section,
2252 unsigned section_line,
2253 const char *lvalue,
2254 int ltype,
2255 const char *rvalue,
2256 void *data,
2257 void *userdata) {
039655a4 2258
2fbe635a 2259 _cleanup_free_ char *s = NULL;
59fccdc5
LP
2260 Condition **list = data, *c;
2261 ConditionType t = ltype;
2262 bool trigger, negate;
2263 Unit *u = userdata;
19f6d710 2264 int r;
039655a4
LP
2265
2266 assert(filename);
2267 assert(lvalue);
2268 assert(rvalue);
2269 assert(data);
2270
74051b9b
LP
2271 if (isempty(rvalue)) {
2272 /* Empty assignment resets the list */
447021aa 2273 *list = condition_free_list(*list);
74051b9b
LP
2274 return 0;
2275 }
2276
c0d6e764
LP
2277 trigger = rvalue[0] == '|';
2278 if (trigger)
267632f0
LP
2279 rvalue++;
2280
c0d6e764
LP
2281 negate = rvalue[0] == '!';
2282 if (negate)
039655a4
LP
2283 rvalue++;
2284
19f6d710 2285 r = unit_full_printf(u, rvalue, &s);
59fccdc5 2286 if (r < 0) {
12ca818f 2287 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
59fccdc5 2288 return 0;
19f6d710 2289 }
095b2d7a 2290
59fccdc5 2291 c = condition_new(t, s, trigger, negate);
c0d6e764
LP
2292 if (!c)
2293 return log_oom();
039655a4 2294
59fccdc5 2295 LIST_PREPEND(conditions, *list, c);
039655a4
LP
2296 return 0;
2297}
2298
59fccdc5
LP
2299int config_parse_unit_condition_null(
2300 const char *unit,
2301 const char *filename,
2302 unsigned line,
2303 const char *section,
2304 unsigned section_line,
2305 const char *lvalue,
2306 int ltype,
2307 const char *rvalue,
2308 void *data,
2309 void *userdata) {
d257ddef 2310
59fccdc5 2311 Condition **list = data, *c;
267632f0 2312 bool trigger, negate;
d257ddef
LP
2313 int b;
2314
2315 assert(filename);
2316 assert(lvalue);
2317 assert(rvalue);
2318 assert(data);
2319
74051b9b
LP
2320 if (isempty(rvalue)) {
2321 /* Empty assignment resets the list */
447021aa 2322 *list = condition_free_list(*list);
74051b9b
LP
2323 return 0;
2324 }
2325
2326 trigger = rvalue[0] == '|';
2327 if (trigger)
267632f0
LP
2328 rvalue++;
2329
74051b9b
LP
2330 negate = rvalue[0] == '!';
2331 if (negate)
d257ddef
LP
2332 rvalue++;
2333
74051b9b
LP
2334 b = parse_boolean(rvalue);
2335 if (b < 0) {
12ca818f 2336 log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
d257ddef
LP
2337 return 0;
2338 }
2339
2340 if (!b)
2341 negate = !negate;
2342
74051b9b
LP
2343 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2344 if (!c)
2345 return log_oom();
d257ddef 2346
59fccdc5 2347 LIST_PREPEND(conditions, *list, c);
d257ddef
LP
2348 return 0;
2349}
2350
f975e971 2351DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
bf500566 2352DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
c952c6ec 2353
a57f7e2c
LP
2354int config_parse_unit_requires_mounts_for(
2355 const char *unit,
2356 const char *filename,
2357 unsigned line,
2358 const char *section,
71a61510 2359 unsigned section_line,
a57f7e2c
LP
2360 const char *lvalue,
2361 int ltype,
2362 const char *rvalue,
2363 void *data,
2364 void *userdata) {
7c8fa05c
LP
2365
2366 Unit *u = userdata;
a2a5291b 2367 const char *word, *state;
a57f7e2c 2368 size_t l;
7c8fa05c
LP
2369
2370 assert(filename);
2371 assert(lvalue);
2372 assert(rvalue);
2373 assert(data);
2374
a2a5291b 2375 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
8a7935a2 2376 int r;
a57f7e2c
LP
2377 _cleanup_free_ char *n;
2378
a2a5291b 2379 n = strndup(word, l);
a57f7e2c
LP
2380 if (!n)
2381 return log_oom();
7c8fa05c 2382
a57f7e2c 2383 if (!utf8_is_valid(n)) {
0e05ee04 2384 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
a57f7e2c
LP
2385 continue;
2386 }
7c8fa05c 2387
a57f7e2c
LP
2388 r = unit_require_mounts_for(u, n);
2389 if (r < 0) {
12ca818f 2390 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue);
a57f7e2c
LP
2391 continue;
2392 }
2393 }
b2fadec6 2394 if (!isempty(state))
12ca818f 2395 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
7c8fa05c 2396
8a7935a2 2397 return 0;
7c8fa05c 2398}
9e372868 2399
e8e581bf
ZJS
2400int config_parse_documentation(const char *unit,
2401 const char *filename,
2402 unsigned line,
2403 const char *section,
71a61510 2404 unsigned section_line,
e8e581bf
ZJS
2405 const char *lvalue,
2406 int ltype,
2407 const char *rvalue,
2408 void *data,
2409 void *userdata) {
49dbfa7b
LP
2410
2411 Unit *u = userdata;
2412 int r;
2413 char **a, **b;
2414
2415 assert(filename);
2416 assert(lvalue);
2417 assert(rvalue);
2418 assert(u);
2419
74051b9b
LP
2420 if (isempty(rvalue)) {
2421 /* Empty assignment resets the list */
6796073e 2422 u->documentation = strv_free(u->documentation);
74051b9b
LP
2423 return 0;
2424 }
2425
71a61510 2426 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 2427 rvalue, data, userdata);
49dbfa7b
LP
2428 if (r < 0)
2429 return r;
2430
2431 for (a = b = u->documentation; a && *a; a++) {
2432
a2e03378 2433 if (documentation_url_is_valid(*a))
49dbfa7b
LP
2434 *(b++) = *a;
2435 else {
12ca818f 2436 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
49dbfa7b
LP
2437 free(*a);
2438 }
2439 }
f6d2d421
ZJS
2440 if (b)
2441 *b = NULL;
49dbfa7b
LP
2442
2443 return r;
2444}
2445
c0467cf3 2446#ifdef HAVE_SECCOMP
17df7223
LP
2447int config_parse_syscall_filter(
2448 const char *unit,
2449 const char *filename,
2450 unsigned line,
2451 const char *section,
2452 unsigned section_line,
2453 const char *lvalue,
2454 int ltype,
2455 const char *rvalue,
2456 void *data,
2457 void *userdata) {
2458
2459 static const char default_syscalls[] =
2460 "execve\0"
2461 "exit\0"
2462 "exit_group\0"
2463 "rt_sigreturn\0"
2464 "sigreturn\0";
2465
8351ceae
LP
2466 ExecContext *c = data;
2467 Unit *u = userdata;
b5fb3789 2468 bool invert = false;
a2a5291b 2469 const char *word, *state;
8351ceae 2470 size_t l;
17df7223 2471 int r;
8351ceae
LP
2472
2473 assert(filename);
2474 assert(lvalue);
2475 assert(rvalue);
2476 assert(u);
2477
74051b9b
LP
2478 if (isempty(rvalue)) {
2479 /* Empty assignment resets the list */
525d3cc7 2480 c->syscall_filter = set_free(c->syscall_filter);
17df7223 2481 c->syscall_whitelist = false;
74051b9b
LP
2482 return 0;
2483 }
2484
8351ceae
LP
2485 if (rvalue[0] == '~') {
2486 invert = true;
2487 rvalue++;
2488 }
2489
17df7223 2490 if (!c->syscall_filter) {
d5099efc 2491 c->syscall_filter = set_new(NULL);
17df7223
LP
2492 if (!c->syscall_filter)
2493 return log_oom();
2494
c0467cf3 2495 if (invert)
17df7223
LP
2496 /* Allow everything but the ones listed */
2497 c->syscall_whitelist = false;
c0467cf3 2498 else {
17df7223
LP
2499 const char *i;
2500
2501 /* Allow nothing but the ones listed */
2502 c->syscall_whitelist = true;
8351ceae 2503
17df7223
LP
2504 /* Accept default syscalls if we are on a whitelist */
2505 NULSTR_FOREACH(i, default_syscalls) {
2506 int id;
8351ceae 2507
17df7223 2508 id = seccomp_syscall_resolve_name(i);
c0467cf3
RC
2509 if (id < 0)
2510 continue;
8351ceae 2511
17df7223 2512 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
756c09e6 2513 if (r == 0)
17df7223
LP
2514 continue;
2515 if (r < 0)
2516 return log_oom();
c0467cf3
RC
2517 }
2518 }
8351ceae
LP
2519 }
2520
a2a5291b 2521 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
7fd1b19b 2522 _cleanup_free_ char *t = NULL;
17df7223 2523 int id;
8351ceae 2524
a2a5291b 2525 t = strndup(word, l);
8351ceae 2526 if (!t)
74051b9b 2527 return log_oom();
8351ceae 2528
c0467cf3 2529 id = seccomp_syscall_resolve_name(t);
8351ceae 2530 if (id < 0) {
12ca818f 2531 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
8351ceae
LP
2532 continue;
2533 }
2534
17df7223
LP
2535 /* If we previously wanted to forbid a syscall and now
2536 * we want to allow it, then remove it from the list
c0467cf3 2537 */
17df7223
LP
2538 if (!invert == c->syscall_whitelist) {
2539 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
756c09e6 2540 if (r == 0)
17df7223
LP
2541 continue;
2542 if (r < 0)
2543 return log_oom();
2544 } else
2545 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
c0467cf3 2546 }
b2fadec6 2547 if (!isempty(state))
12ca818f 2548 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
c0467cf3 2549
760b9d7c
LP
2550 /* Turn on NNP, but only if it wasn't configured explicitly
2551 * before, and only if we are in user mode. */
b2c23da8 2552 if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
760b9d7c 2553 c->no_new_privileges = true;
17df7223
LP
2554
2555 return 0;
2556}
2557
57183d11
LP
2558int config_parse_syscall_archs(
2559 const char *unit,
2560 const char *filename,
2561 unsigned line,
2562 const char *section,
2563 unsigned section_line,
2564 const char *lvalue,
2565 int ltype,
2566 const char *rvalue,
2567 void *data,
2568 void *userdata) {
2569
d3b1c508 2570 Set **archs = data;
a2a5291b 2571 const char *word, *state;
57183d11
LP
2572 size_t l;
2573 int r;
2574
2575 if (isempty(rvalue)) {
525d3cc7 2576 *archs = set_free(*archs);
57183d11
LP
2577 return 0;
2578 }
2579
d5099efc 2580 r = set_ensure_allocated(archs, NULL);
57183d11
LP
2581 if (r < 0)
2582 return log_oom();
2583
a2a5291b 2584 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
57183d11
LP
2585 _cleanup_free_ char *t = NULL;
2586 uint32_t a;
2587
a2a5291b 2588 t = strndup(word, l);
57183d11
LP
2589 if (!t)
2590 return log_oom();
2591
2592 r = seccomp_arch_from_string(t, &a);
2593 if (r < 0) {
12ca818f 2594 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
57183d11
LP
2595 continue;
2596 }
2597
d3b1c508 2598 r = set_put(*archs, UINT32_TO_PTR(a + 1));
756c09e6 2599 if (r == 0)
57183d11
LP
2600 continue;
2601 if (r < 0)
2602 return log_oom();
2603 }
b2fadec6 2604 if (!isempty(state))
12ca818f 2605 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
57183d11
LP
2606
2607 return 0;
2608}
2609
17df7223
LP
2610int config_parse_syscall_errno(
2611 const char *unit,
2612 const char *filename,
2613 unsigned line,
2614 const char *section,
2615 unsigned section_line,
2616 const char *lvalue,
2617 int ltype,
2618 const char *rvalue,
2619 void *data,
2620 void *userdata) {
2621
2622 ExecContext *c = data;
2623 int e;
2624
2625 assert(filename);
2626 assert(lvalue);
2627 assert(rvalue);
2628
2629 if (isempty(rvalue)) {
2630 /* Empty assignment resets to KILL */
2631 c->syscall_errno = 0;
2632 return 0;
8351ceae
LP
2633 }
2634
17df7223
LP
2635 e = errno_from_name(rvalue);
2636 if (e < 0) {
12ca818f 2637 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
17df7223
LP
2638 return 0;
2639 }
8351ceae 2640
17df7223 2641 c->syscall_errno = e;
8351ceae
LP
2642 return 0;
2643}
4298d0b5
LP
2644
2645int config_parse_address_families(
2646 const char *unit,
2647 const char *filename,
2648 unsigned line,
2649 const char *section,
2650 unsigned section_line,
2651 const char *lvalue,
2652 int ltype,
2653 const char *rvalue,
2654 void *data,
2655 void *userdata) {
2656
2657 ExecContext *c = data;
4298d0b5 2658 bool invert = false;
a2a5291b 2659 const char *word, *state;
4298d0b5
LP
2660 size_t l;
2661 int r;
2662
2663 assert(filename);
2664 assert(lvalue);
2665 assert(rvalue);
4298d0b5
LP
2666
2667 if (isempty(rvalue)) {
2668 /* Empty assignment resets the list */
525d3cc7 2669 c->address_families = set_free(c->address_families);
4298d0b5
LP
2670 c->address_families_whitelist = false;
2671 return 0;
2672 }
2673
2674 if (rvalue[0] == '~') {
2675 invert = true;
2676 rvalue++;
2677 }
2678
2679 if (!c->address_families) {
d5099efc 2680 c->address_families = set_new(NULL);
4298d0b5
LP
2681 if (!c->address_families)
2682 return log_oom();
2683
2684 c->address_families_whitelist = !invert;
2685 }
2686
a2a5291b 2687 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
4298d0b5
LP
2688 _cleanup_free_ char *t = NULL;
2689 int af;
2690
a2a5291b 2691 t = strndup(word, l);
4298d0b5
LP
2692 if (!t)
2693 return log_oom();
2694
2695 af = af_from_name(t);
2696 if (af <= 0) {
12ca818f 2697 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t);
4298d0b5
LP
2698 continue;
2699 }
2700
2701 /* If we previously wanted to forbid an address family and now
2702 * we want to allow it, then remove it from the list
2703 */
2704 if (!invert == c->address_families_whitelist) {
2705 r = set_put(c->address_families, INT_TO_PTR(af));
756c09e6 2706 if (r == 0)
4298d0b5
LP
2707 continue;
2708 if (r < 0)
2709 return log_oom();
2710 } else
2711 set_remove(c->address_families, INT_TO_PTR(af));
2712 }
b2fadec6 2713 if (!isempty(state))
12ca818f 2714 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
4298d0b5
LP
2715
2716 return 0;
2717}
c0467cf3 2718#endif
8351ceae 2719
a016b922
LP
2720int config_parse_unit_slice(
2721 const char *unit,
2722 const char *filename,
2723 unsigned line,
2724 const char *section,
71a61510 2725 unsigned section_line,
a016b922
LP
2726 const char *lvalue,
2727 int ltype,
2728 const char *rvalue,
2729 void *data,
2730 void *userdata) {
2731
2732 _cleanup_free_ char *k = NULL;
d79200e2 2733 Unit *u = userdata, *slice = NULL;
a016b922
LP
2734 int r;
2735
2736 assert(filename);
2737 assert(lvalue);
2738 assert(rvalue);
2739 assert(u);
2740
19f6d710 2741 r = unit_name_printf(u, rvalue, &k);
d79200e2
LP
2742 if (r < 0) {
2743 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2744 return 0;
19f6d710 2745 }
a016b922 2746
19f6d710 2747 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
a016b922 2748 if (r < 0) {
d79200e2 2749 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
a016b922
LP
2750 return 0;
2751 }
2752
d79200e2
LP
2753 r = unit_set_slice(u, slice);
2754 if (r < 0) {
2755 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
a016b922
LP
2756 return 0;
2757 }
2758
a016b922
LP
2759 return 0;
2760}
2761
4ad49000
LP
2762DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2763
2764int config_parse_cpu_shares(
2765 const char *unit,
2766 const char *filename,
2767 unsigned line,
2768 const char *section,
71a61510 2769 unsigned section_line,
4ad49000
LP
2770 const char *lvalue,
2771 int ltype,
2772 const char *rvalue,
2773 void *data,
2774 void *userdata) {
2775
d53d9474 2776 uint64_t *shares = data;
95ae05c0
WC
2777 int r;
2778
2779 assert(filename);
2780 assert(lvalue);
2781 assert(rvalue);
2782
d53d9474
LP
2783 r = cg_cpu_shares_parse(rvalue, shares);
2784 if (r < 0) {
2785 log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
2786 return 0;
2787 }
2788
4ad49000
LP
2789 return 0;
2790}
2791
b2f8b02e
LP
2792int config_parse_cpu_quota(
2793 const char *unit,
2794 const char *filename,
2795 unsigned line,
2796 const char *section,
2797 unsigned section_line,
2798 const char *lvalue,
2799 int ltype,
2800 const char *rvalue,
2801 void *data,
2802 void *userdata) {
2803
2804 CGroupContext *c = data;
9a054909 2805 double percent;
b2f8b02e
LP
2806
2807 assert(filename);
2808 assert(lvalue);
2809 assert(rvalue);
2810
2811 if (isempty(rvalue)) {
3a43da28 2812 c->cpu_quota_per_sec_usec = USEC_INFINITY;
b2f8b02e
LP
2813 return 0;
2814 }
2815
9a054909 2816 if (!endswith(rvalue, "%")) {
12ca818f 2817 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
9a054909
LP
2818 return 0;
2819 }
b2f8b02e 2820
9a054909 2821 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
12ca818f 2822 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue);
9a054909 2823 return 0;
b2f8b02e
LP
2824 }
2825
9a054909
LP
2826 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2827
b2f8b02e
LP
2828 return 0;
2829}
2830
4ad49000
LP
2831int config_parse_memory_limit(
2832 const char *unit,
2833 const char *filename,
2834 unsigned line,
2835 const char *section,
71a61510 2836 unsigned section_line,
4ad49000
LP
2837 const char *lvalue,
2838 int ltype,
2839 const char *rvalue,
2840 void *data,
2841 void *userdata) {
2842
2843 CGroupContext *c = data;
59f448cf 2844 uint64_t bytes;
4ad49000
LP
2845 int r;
2846
03a7b521 2847 if (isempty(rvalue) || streq(rvalue, "infinity")) {
ddca82ac 2848 c->memory_limit = (uint64_t) -1;
4ad49000
LP
2849 return 0;
2850 }
2851
5556b5fe 2852 r = parse_size(rvalue, 1024, &bytes);
03a7b521 2853 if (r < 0 || bytes < 1) {
12ca818f 2854 log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
2855 return 0;
2856 }
2857
59f448cf 2858 c->memory_limit = bytes;
4ad49000
LP
2859 return 0;
2860}
2861
03a7b521
LP
2862int config_parse_tasks_max(
2863 const char *unit,
2864 const char *filename,
2865 unsigned line,
2866 const char *section,
2867 unsigned section_line,
2868 const char *lvalue,
2869 int ltype,
2870 const char *rvalue,
2871 void *data,
2872 void *userdata) {
2873
0af20ea2 2874 uint64_t *tasks_max = data, u;
03a7b521
LP
2875 int r;
2876
2877 if (isempty(rvalue) || streq(rvalue, "infinity")) {
0af20ea2 2878 *tasks_max = (uint64_t) -1;
03a7b521
LP
2879 return 0;
2880 }
2881
2882 r = safe_atou64(rvalue, &u);
2883 if (r < 0 || u < 1) {
12ca818f 2884 log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
03a7b521
LP
2885 return 0;
2886 }
2887
0af20ea2 2888 *tasks_max = u;
03a7b521
LP
2889 return 0;
2890}
2891
4ad49000
LP
2892int config_parse_device_allow(
2893 const char *unit,
2894 const char *filename,
2895 unsigned line,
2896 const char *section,
71a61510 2897 unsigned section_line,
4ad49000
LP
2898 const char *lvalue,
2899 int ltype,
2900 const char *rvalue,
2901 void *data,
2902 void *userdata) {
2903
2904 _cleanup_free_ char *path = NULL;
2905 CGroupContext *c = data;
2906 CGroupDeviceAllow *a;
2907 const char *m;
2908 size_t n;
2909
2910 if (isempty(rvalue)) {
2911 while (c->device_allow)
2912 cgroup_context_free_device_allow(c, c->device_allow);
2913
2914 return 0;
2915 }
2916
2917 n = strcspn(rvalue, WHITESPACE);
2918 path = strndup(rvalue, n);
2919 if (!path)
2920 return log_oom();
2921
90060676
LP
2922 if (!startswith(path, "/dev/") &&
2923 !startswith(path, "block-") &&
2924 !startswith(path, "char-")) {
12ca818f 2925 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
2926 return 0;
2927 }
2928
2929 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2930 if (isempty(m))
2931 m = "rwm";
2932
2933 if (!in_charset(m, "rwm")) {
12ca818f 2934 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
4ad49000
LP
2935 return 0;
2936 }
2937
2938 a = new0(CGroupDeviceAllow, 1);
2939 if (!a)
2940 return log_oom();
2941
2942 a->path = path;
2943 path = NULL;
2944 a->r = !!strchr(m, 'r');
2945 a->w = !!strchr(m, 'w');
2946 a->m = !!strchr(m, 'm');
2947
71fda00f 2948 LIST_PREPEND(device_allow, c->device_allow, a);
4ad49000
LP
2949 return 0;
2950}
2951
2952int config_parse_blockio_weight(
2953 const char *unit,
2954 const char *filename,
2955 unsigned line,
2956 const char *section,
71a61510 2957 unsigned section_line,
4ad49000
LP
2958 const char *lvalue,
2959 int ltype,
2960 const char *rvalue,
2961 void *data,
2962 void *userdata) {
2963
d53d9474 2964 uint64_t *weight = data;
95ae05c0
WC
2965 int r;
2966
2967 assert(filename);
2968 assert(lvalue);
2969 assert(rvalue);
2970
d53d9474
LP
2971 r = cg_blkio_weight_parse(rvalue, weight);
2972 if (r < 0) {
2973 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
2974 return 0;
2975 }
2976
8e7076ca
LP
2977 return 0;
2978}
2979
2980int config_parse_blockio_device_weight(
2981 const char *unit,
2982 const char *filename,
2983 unsigned line,
2984 const char *section,
71a61510 2985 unsigned section_line,
8e7076ca
LP
2986 const char *lvalue,
2987 int ltype,
2988 const char *rvalue,
2989 void *data,
2990 void *userdata) {
2991
4ad49000 2992 _cleanup_free_ char *path = NULL;
8e7076ca 2993 CGroupBlockIODeviceWeight *w;
4ad49000 2994 CGroupContext *c = data;
4ad49000 2995 const char *weight;
d53d9474 2996 uint64_t u;
4ad49000
LP
2997 size_t n;
2998 int r;
2999
3000 assert(filename);
3001 assert(lvalue);
3002 assert(rvalue);
3003
3004 if (isempty(rvalue)) {
4ad49000
LP
3005 while (c->blockio_device_weights)
3006 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3007
3008 return 0;
3009 }
3010
3011 n = strcspn(rvalue, WHITESPACE);
3012 weight = rvalue + n;
d53d9474
LP
3013 weight += strspn(weight, WHITESPACE);
3014
3015 if (isempty(weight)) {
12ca818f 3016 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
8e7076ca
LP
3017 return 0;
3018 }
4ad49000 3019
8e7076ca
LP
3020 path = strndup(rvalue, n);
3021 if (!path)
3022 return log_oom();
4ad49000 3023
8e7076ca 3024 if (!path_startswith(path, "/dev")) {
12ca818f 3025 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
8e7076ca
LP
3026 return 0;
3027 }
4ad49000 3028
d53d9474
LP
3029 r = cg_blkio_weight_parse(weight, &u);
3030 if (r < 0) {
3031 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
4ad49000
LP
3032 return 0;
3033 }
3034
d53d9474
LP
3035 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3036
8e7076ca
LP
3037 w = new0(CGroupBlockIODeviceWeight, 1);
3038 if (!w)
3039 return log_oom();
4ad49000 3040
8e7076ca
LP
3041 w->path = path;
3042 path = NULL;
4ad49000 3043
d53d9474 3044 w->weight = u;
4ad49000 3045
71fda00f 3046 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
3047 return 0;
3048}
3049
3050int config_parse_blockio_bandwidth(
3051 const char *unit,
3052 const char *filename,
3053 unsigned line,
3054 const char *section,
71a61510 3055 unsigned section_line,
4ad49000
LP
3056 const char *lvalue,
3057 int ltype,
3058 const char *rvalue,
3059 void *data,
3060 void *userdata) {
3061
3062 _cleanup_free_ char *path = NULL;
3063 CGroupBlockIODeviceBandwidth *b;
3064 CGroupContext *c = data;
3065 const char *bandwidth;
59f448cf 3066 uint64_t bytes;
47c0980d 3067 bool read;
4ad49000
LP
3068 size_t n;
3069 int r;
3070
3071 assert(filename);
3072 assert(lvalue);
3073 assert(rvalue);
3074
47c0980d
G
3075 read = streq("BlockIOReadBandwidth", lvalue);
3076
4ad49000 3077 if (isempty(rvalue)) {
47c0980d
G
3078 CGroupBlockIODeviceBandwidth *next;
3079
3080 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
3081 if (b->read == read)
3082 cgroup_context_free_blockio_device_bandwidth(c, b);
4ad49000
LP
3083
3084 return 0;
3085 }
3086
3087 n = strcspn(rvalue, WHITESPACE);
3088 bandwidth = rvalue + n;
3089 bandwidth += strspn(bandwidth, WHITESPACE);
3090
3091 if (!*bandwidth) {
12ca818f 3092 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
4ad49000
LP
3093 return 0;
3094 }
3095
3096 path = strndup(rvalue, n);
3097 if (!path)
3098 return log_oom();
3099
3100 if (!path_startswith(path, "/dev")) {
12ca818f 3101 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
3102 return 0;
3103 }
3104
5556b5fe 3105 r = parse_size(bandwidth, 1000, &bytes);
4ad49000 3106 if (r < 0 || bytes <= 0) {
12ca818f 3107 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
3108 return 0;
3109 }
3110
3111 b = new0(CGroupBlockIODeviceBandwidth, 1);
3112 if (!b)
3113 return log_oom();
3114
3115 b->path = path;
3116 path = NULL;
59f448cf 3117 b->bandwidth = bytes;
47c0980d 3118 b->read = read;
4ad49000 3119
71fda00f 3120 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
4ad49000
LP
3121
3122 return 0;
3123}
3124
d420282b
LP
3125DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3126
3127int config_parse_job_mode_isolate(
3128 const char *unit,
3129 const char *filename,
3130 unsigned line,
3131 const char *section,
3132 unsigned section_line,
3133 const char *lvalue,
3134 int ltype,
3135 const char *rvalue,
3136 void *data,
3137 void *userdata) {
3138
3139 JobMode *m = data;
3140 int r;
3141
3142 assert(filename);
3143 assert(lvalue);
3144 assert(rvalue);
3145
3146 r = parse_boolean(rvalue);
3147 if (r < 0) {
12ca818f 3148 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
d420282b
LP
3149 return 0;
3150 }
3151
3152 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3153 return 0;
3154}
3155
e66cf1a3
LP
3156int config_parse_runtime_directory(
3157 const char *unit,
3158 const char *filename,
3159 unsigned line,
3160 const char *section,
3161 unsigned section_line,
3162 const char *lvalue,
3163 int ltype,
3164 const char *rvalue,
3165 void *data,
3166 void *userdata) {
3167
a2a5291b 3168 char***rt = data;
9b5864d9 3169 Unit *u = userdata;
a2a5291b 3170 const char *word, *state;
e66cf1a3
LP
3171 size_t l;
3172 int r;
3173
3174 assert(filename);
3175 assert(lvalue);
3176 assert(rvalue);
3177 assert(data);
3178
3179 if (isempty(rvalue)) {
3180 /* Empty assignment resets the list */
6796073e 3181 *rt = strv_free(*rt);
e66cf1a3
LP
3182 return 0;
3183 }
3184
a2a5291b 3185 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
9b5864d9 3186 _cleanup_free_ char *t = NULL, *n = NULL;
e66cf1a3 3187
9b5864d9
MG
3188 t = strndup(word, l);
3189 if (!t)
e66cf1a3
LP
3190 return log_oom();
3191
9b5864d9
MG
3192 r = unit_name_printf(u, t, &n);
3193 if (r < 0) {
12ca818f 3194 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
9b5864d9
MG
3195 continue;
3196 }
3197
ae6c3cc0 3198 if (!filename_is_valid(n)) {
12ca818f 3199 log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
e66cf1a3
LP
3200 continue;
3201 }
3202
3203 r = strv_push(rt, n);
3204 if (r < 0)
3205 return log_oom();
3206
3207 n = NULL;
3208 }
b2fadec6 3209 if (!isempty(state))
12ca818f 3210 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
e66cf1a3
LP
3211
3212 return 0;
3213}
3214
3af00fb8
LP
3215int config_parse_set_status(
3216 const char *unit,
3217 const char *filename,
3218 unsigned line,
3219 const char *section,
3220 unsigned section_line,
3221 const char *lvalue,
3222 int ltype,
3223 const char *rvalue,
3224 void *data,
3225 void *userdata) {
3226
3af00fb8 3227 size_t l;
a2a5291b 3228 const char *word, *state;
3af00fb8
LP
3229 int r;
3230 ExitStatusSet *status_set = data;
3231
3232 assert(filename);
3233 assert(lvalue);
3234 assert(rvalue);
3235 assert(data);
3236
3e2d435b 3237 /* Empty assignment resets the list */
3af00fb8 3238 if (isempty(rvalue)) {
3e2d435b 3239 exit_status_set_free(status_set);
3af00fb8
LP
3240 return 0;
3241 }
3242
a2a5291b 3243 FOREACH_WORD(word, l, rvalue, state) {
3af00fb8
LP
3244 _cleanup_free_ char *temp;
3245 int val;
61593865 3246 Set **set;
3af00fb8 3247
a2a5291b 3248 temp = strndup(word, l);
3af00fb8
LP
3249 if (!temp)
3250 return log_oom();
3251
3252 r = safe_atoi(temp, &val);
3253 if (r < 0) {
3254 val = signal_from_string_try_harder(temp);
3255
1e2fd62d 3256 if (val <= 0) {
12ca818f 3257 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
61593865 3258 continue;
3af00fb8 3259 }
61593865 3260 set = &status_set->signal;
3af00fb8 3261 } else {
1e2fd62d 3262 if (val < 0 || val > 255) {
12ca818f 3263 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
1e2fd62d 3264 continue;
3af00fb8 3265 }
61593865 3266 set = &status_set->status;
3af00fb8 3267 }
1e2fd62d 3268
61593865 3269 r = set_ensure_allocated(set, NULL);
1e2fd62d
ZJS
3270 if (r < 0)
3271 return log_oom();
3272
61593865 3273 r = set_put(*set, INT_TO_PTR(val));
1e2fd62d 3274 if (r < 0) {
12ca818f 3275 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
1e2fd62d
ZJS
3276 return r;
3277 }
3af00fb8 3278 }
b2fadec6 3279 if (!isempty(state))
12ca818f 3280 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3af00fb8
LP
3281
3282 return 0;
3283}
3284
94828d2d
LP
3285int config_parse_namespace_path_strv(
3286 const char *unit,
3287 const char *filename,
3288 unsigned line,
3289 const char *section,
3290 unsigned section_line,
3291 const char *lvalue,
3292 int ltype,
3293 const char *rvalue,
3294 void *data,
3295 void *userdata) {
3296
a2a5291b 3297 char*** sv = data;
727f76d7
EV
3298 const char *prev;
3299 const char *cur;
94828d2d
LP
3300 int r;
3301
3302 assert(filename);
3303 assert(lvalue);
3304 assert(rvalue);
3305 assert(data);
3306
3307 if (isempty(rvalue)) {
3308 /* Empty assignment resets the list */
6796073e 3309 *sv = strv_free(*sv);
94828d2d
LP
3310 return 0;
3311 }
3312
727f76d7
EV
3313 prev = cur = rvalue;
3314 for (;;) {
3315 _cleanup_free_ char *word = NULL;
94828d2d
LP
3316 int offset;
3317
727f76d7 3318 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
0293a7a8
EV
3319 if (r == 0)
3320 break;
3321 if (r == -ENOMEM)
3322 return log_oom();
727f76d7 3323 if (r < 0) {
0293a7a8 3324 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
727f76d7
EV
3325 return 0;
3326 }
94828d2d 3327
727f76d7
EV
3328 if (!utf8_is_valid(word)) {
3329 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3330 prev = cur;
94828d2d
LP
3331 continue;
3332 }
3333
727f76d7
EV
3334 offset = word[0] == '-';
3335 if (!path_is_absolute(word + offset)) {
3336 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
3337 prev = cur;
94828d2d
LP
3338 continue;
3339 }
3340
727f76d7 3341 path_kill_slashes(word + offset);
94828d2d 3342
727f76d7 3343 r = strv_push(sv, word);
94828d2d
LP
3344 if (r < 0)
3345 return log_oom();
3346
727f76d7
EV
3347 prev = cur;
3348 word = NULL;
94828d2d
LP
3349 }
3350
3351 return 0;
3352}
3353
f1721625 3354int config_parse_no_new_privileges(
760b9d7c
LP
3355 const char* unit,
3356 const char *filename,
3357 unsigned line,
3358 const char *section,
3359 unsigned section_line,
3360 const char *lvalue,
3361 int ltype,
3362 const char *rvalue,
3363 void *data,
3364 void *userdata) {
3365
3366 ExecContext *c = data;
3367 int k;
3368
3369 assert(filename);
3370 assert(lvalue);
3371 assert(rvalue);
3372 assert(data);
3373
3374 k = parse_boolean(rvalue);
3375 if (k < 0) {
12ca818f 3376 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
760b9d7c
LP
3377 return 0;
3378 }
3379
3380 c->no_new_privileges = !!k;
3381 c->no_new_privileges_set = true;
3382
3383 return 0;
3384}
3385
1b8689f9 3386int config_parse_protect_home(
417116f2
LP
3387 const char* unit,
3388 const char *filename,
3389 unsigned line,
3390 const char *section,
3391 unsigned section_line,
3392 const char *lvalue,
3393 int ltype,
3394 const char *rvalue,
3395 void *data,
3396 void *userdata) {
3397
3398 ExecContext *c = data;
3399 int k;
3400
3401 assert(filename);
3402 assert(lvalue);
3403 assert(rvalue);
3404 assert(data);
3405
3406 /* Our enum shall be a superset of booleans, hence first try
3407 * to parse as as boolean, and then as enum */
3408
3409 k = parse_boolean(rvalue);
3410 if (k > 0)
1b8689f9 3411 c->protect_home = PROTECT_HOME_YES;
417116f2 3412 else if (k == 0)
1b8689f9 3413 c->protect_home = PROTECT_HOME_NO;
417116f2 3414 else {
1b8689f9 3415 ProtectHome h;
417116f2 3416
1b8689f9 3417 h = protect_home_from_string(rvalue);
417116f2 3418 if (h < 0){
12ca818f 3419 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
3420 return 0;
3421 }
3422
1b8689f9
LP
3423 c->protect_home = h;
3424 }
3425
3426 return 0;
3427}
3428
3429int config_parse_protect_system(
3430 const char* unit,
3431 const char *filename,
3432 unsigned line,
3433 const char *section,
3434 unsigned section_line,
3435 const char *lvalue,
3436 int ltype,
3437 const char *rvalue,
3438 void *data,
3439 void *userdata) {
3440
3441 ExecContext *c = data;
3442 int k;
3443
3444 assert(filename);
3445 assert(lvalue);
3446 assert(rvalue);
3447 assert(data);
3448
3449 /* Our enum shall be a superset of booleans, hence first try
3450 * to parse as as boolean, and then as enum */
3451
3452 k = parse_boolean(rvalue);
3453 if (k > 0)
3454 c->protect_system = PROTECT_SYSTEM_YES;
3455 else if (k == 0)
3456 c->protect_system = PROTECT_SYSTEM_NO;
3457 else {
3458 ProtectSystem s;
3459
3460 s = protect_system_from_string(rvalue);
3461 if (s < 0){
12ca818f 3462 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
1b8689f9
LP
3463 return 0;
3464 }
3465
3466 c->protect_system = s;
417116f2
LP
3467 }
3468
3469 return 0;
3470}
3471
071830ff 3472#define FOLLOW_MAX 8
87f0e418 3473
9e2f7c11 3474static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
0301abf4 3475 unsigned c = 0;
87f0e418
LP
3476 int fd, r;
3477 FILE *f;
0301abf4 3478 char *id = NULL;
87f0e418
LP
3479
3480 assert(filename);
3481 assert(*filename);
3482 assert(_f);
3483 assert(names);
3484
0301abf4
LP
3485 /* This will update the filename pointer if the loaded file is
3486 * reached by a symlink. The old string will be freed. */
87f0e418 3487
0301abf4 3488 for (;;) {
2c7108c4 3489 char *target, *name;
87f0e418 3490
0301abf4
LP
3491 if (c++ >= FOLLOW_MAX)
3492 return -ELOOP;
3493
b08d03ff
LP
3494 path_kill_slashes(*filename);
3495
87f0e418 3496 /* Add the file name we are currently looking at to
8f05424d
LP
3497 * the names of this unit, but only if it is a valid
3498 * unit name. */
2b6bf07d 3499 name = basename(*filename);
87f0e418 3500
7410616c 3501 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
8f05424d 3502
15e11d81
LP
3503 id = set_get(names, name);
3504 if (!id) {
3505 id = strdup(name);
3506 if (!id)
8f05424d 3507 return -ENOMEM;
87f0e418 3508
ef42202a
ZJS
3509 r = set_consume(names, id);
3510 if (r < 0)
8f05424d 3511 return r;
87f0e418 3512 }
87f0e418
LP
3513 }
3514
0301abf4 3515 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
3516 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3517 if (fd >= 0)
87f0e418
LP
3518 break;
3519
0301abf4
LP
3520 if (errno != ELOOP)
3521 return -errno;
3522
87f0e418 3523 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
3524 r = readlink_and_make_absolute(*filename, &target);
3525 if (r < 0)
0301abf4 3526 return r;
87f0e418 3527
0301abf4 3528 free(*filename);
2c7108c4 3529 *filename = target;
87f0e418
LP
3530 }
3531
9946996c
LP
3532 f = fdopen(fd, "re");
3533 if (!f) {
03e334a1 3534 safe_close(fd);
d4ad27a1 3535 return -errno;
87f0e418
LP
3536 }
3537
3538 *_f = f;
9e2f7c11 3539 *_final = id;
0301abf4 3540 return 0;
87f0e418
LP
3541}
3542
23a177ef
LP
3543static int merge_by_names(Unit **u, Set *names, const char *id) {
3544 char *k;
3545 int r;
3546
3547 assert(u);
3548 assert(*u);
3549 assert(names);
3550
3551 /* Let's try to add in all symlink names we found */
3552 while ((k = set_steal_first(names))) {
3553
3554 /* First try to merge in the other name into our
3555 * unit */
9946996c
LP
3556 r = unit_merge_by_name(*u, k);
3557 if (r < 0) {
23a177ef
LP
3558 Unit *other;
3559
3560 /* Hmm, we couldn't merge the other unit into
3561 * ours? Then let's try it the other way
3562 * round */
3563
ac155bb8 3564 other = manager_get_unit((*u)->manager, k);
23a177ef
LP
3565 free(k);
3566
9946996c
LP
3567 if (other) {
3568 r = unit_merge(other, *u);
3569 if (r >= 0) {
23a177ef
LP
3570 *u = other;
3571 return merge_by_names(u, names, NULL);
3572 }
9946996c 3573 }
23a177ef
LP
3574
3575 return r;
3576 }
3577
3578 if (id == k)
3579 unit_choose_id(*u, id);
3580
3581 free(k);
3582 }
3583
3584 return 0;
3585}
3586
e537352b 3587static int load_from_path(Unit *u, const char *path) {
0301abf4 3588 int r;
e48614c4
ZJS
3589 _cleanup_set_free_free_ Set *symlink_names = NULL;
3590 _cleanup_fclose_ FILE *f = NULL;
3591 _cleanup_free_ char *filename = NULL;
3592 char *id = NULL;
23a177ef 3593 Unit *merged;
45fb0699 3594 struct stat st;
23a177ef
LP
3595
3596 assert(u);
e537352b 3597 assert(path);
3efd4195 3598
d5099efc 3599 symlink_names = set_new(&string_hash_ops);
f975e971 3600 if (!symlink_names)
87f0e418 3601 return -ENOMEM;
3efd4195 3602
036643a2
LP
3603 if (path_is_absolute(path)) {
3604
9946996c 3605 filename = strdup(path);
e48614c4
ZJS
3606 if (!filename)
3607 return -ENOMEM;
036643a2 3608
9946996c
LP
3609 r = open_follow(&filename, &f, symlink_names, &id);
3610 if (r < 0) {
97b11eed 3611 filename = mfree(filename);
036643a2 3612 if (r != -ENOENT)
e48614c4 3613 return r;
036643a2
LP
3614 }
3615
3616 } else {
3617 char **p;
3618
ac155bb8 3619 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
036643a2
LP
3620
3621 /* Instead of opening the path right away, we manually
3622 * follow all symlinks and add their name to our unit
3623 * name set while doing so */
9946996c 3624 filename = path_make_absolute(path, *p);
e48614c4
ZJS
3625 if (!filename)
3626 return -ENOMEM;
036643a2 3627
ac155bb8
MS
3628 if (u->manager->unit_path_cache &&
3629 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
3630 r = -ENOENT;
3631 else
3632 r = open_follow(&filename, &f, symlink_names, &id);
3633
3634 if (r < 0) {
97b11eed 3635 filename = mfree(filename);
036643a2 3636 if (r != -ENOENT)
e48614c4 3637 return r;
036643a2
LP
3638
3639 /* Empty the symlink names for the next run */
9946996c 3640 set_clear_free(symlink_names);
036643a2
LP
3641 continue;
3642 }
3643
3644 break;
3645 }
3646 }
034c6ed7 3647
e48614c4 3648 if (!filename)
8f05424d 3649 /* Hmm, no suitable file found? */
e48614c4 3650 return 0;
87f0e418 3651
23a177ef 3652 merged = u;
9946996c
LP
3653 r = merge_by_names(&merged, symlink_names, id);
3654 if (r < 0)
e48614c4 3655 return r;
87f0e418 3656
23a177ef 3657 if (merged != u) {
ac155bb8 3658 u->load_state = UNIT_MERGED;
e48614c4 3659 return 0;
034c6ed7
LP
3660 }
3661
e48614c4
ZJS
3662 if (fstat(fileno(f), &st) < 0)
3663 return -errno;
45fb0699 3664
00dc5d76 3665 if (null_or_empty(&st))
ac155bb8 3666 u->load_state = UNIT_MASKED;
00dc5d76 3667 else {
c2756a68
LP
3668 u->load_state = UNIT_LOADED;
3669
00dc5d76 3670 /* Now, parse the file contents */
36f822c4
ZJS
3671 r = config_parse(u->id, filename, f,
3672 UNIT_VTABLE(u)->sections,
3673 config_item_perf_lookup, load_fragment_gperf_lookup,
3674 false, true, false, u);
f975e971 3675 if (r < 0)
e48614c4 3676 return r;
00dc5d76 3677 }
b08d03ff 3678
ac155bb8
MS
3679 free(u->fragment_path);
3680 u->fragment_path = filename;
0301abf4 3681 filename = NULL;
87f0e418 3682
ac155bb8 3683 u->fragment_mtime = timespec_load(&st.st_mtim);
45fb0699 3684
1b64d026
LP
3685 if (u->source_path) {
3686 if (stat(u->source_path, &st) >= 0)
3687 u->source_mtime = timespec_load(&st.st_mtim);
3688 else
3689 u->source_mtime = 0;
3690 }
3691
e48614c4 3692 return 0;
0301abf4
LP
3693}
3694
e537352b 3695int unit_load_fragment(Unit *u) {
23a177ef 3696 int r;
294d81f1
LP
3697 Iterator i;
3698 const char *t;
0301abf4
LP
3699
3700 assert(u);
ac155bb8
MS
3701 assert(u->load_state == UNIT_STUB);
3702 assert(u->id);
23a177ef 3703
3f5e8115
LP
3704 if (u->transient) {
3705 u->load_state = UNIT_LOADED;
3706 return 0;
3707 }
3708
294d81f1
LP
3709 /* First, try to find the unit under its id. We always look
3710 * for unit files in the default directories, to make it easy
3711 * to override things by placing things in /etc/systemd/system */
9946996c
LP
3712 r = load_from_path(u, u->id);
3713 if (r < 0)
294d81f1
LP
3714 return r;
3715
3716 /* Try to find an alias we can load this with */
abc08d4d 3717 if (u->load_state == UNIT_STUB) {
ac155bb8 3718 SET_FOREACH(t, u->names, i) {
294d81f1 3719
ac155bb8 3720 if (t == u->id)
294d81f1
LP
3721 continue;
3722
9946996c
LP
3723 r = load_from_path(u, t);
3724 if (r < 0)
294d81f1
LP
3725 return r;
3726
ac155bb8 3727 if (u->load_state != UNIT_STUB)
294d81f1
LP
3728 break;
3729 }
abc08d4d 3730 }
23a177ef 3731
294d81f1 3732 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 3733 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 3734
9946996c
LP
3735 r = load_from_path(u, u->fragment_path);
3736 if (r < 0)
23a177ef 3737 return r;
0301abf4 3738
ece174c5 3739 if (u->load_state == UNIT_STUB)
6ccb1b44
LP
3740 /* Hmm, this didn't work? Then let's get rid
3741 * of the fragment path stored for us, so that
3742 * we don't point to an invalid location. */
a1e58e8e 3743 u->fragment_path = mfree(u->fragment_path);
6ccb1b44
LP
3744 }
3745
294d81f1 3746 /* Look for a template */
ac155bb8 3747 if (u->load_state == UNIT_STUB && u->instance) {
7410616c 3748 _cleanup_free_ char *k = NULL;
294d81f1 3749
7410616c
LP
3750 r = unit_name_template(u->id, &k);
3751 if (r < 0)
3752 return r;
294d81f1
LP
3753
3754 r = load_from_path(u, k);
294d81f1 3755 if (r < 0)
9e2f7c11 3756 return r;
890f434c 3757
abc08d4d 3758 if (u->load_state == UNIT_STUB) {
ac155bb8 3759 SET_FOREACH(t, u->names, i) {
bc9fd78c 3760 _cleanup_free_ char *z = NULL;
87f0e418 3761
ac155bb8 3762 if (t == u->id)
23a177ef 3763 continue;
071830ff 3764
7410616c
LP
3765 r = unit_name_template(t, &z);
3766 if (r < 0)
3767 return r;
294d81f1 3768
bc9fd78c 3769 r = load_from_path(u, z);
294d81f1 3770 if (r < 0)
23a177ef 3771 return r;
890f434c 3772
ac155bb8 3773 if (u->load_state != UNIT_STUB)
23a177ef
LP
3774 break;
3775 }
abc08d4d 3776 }
071830ff
LP
3777 }
3778
23a177ef 3779 return 0;
3efd4195 3780}
e537352b
LP
3781
3782void unit_dump_config_items(FILE *f) {
f975e971
LP
3783 static const struct {
3784 const ConfigParserCallback callback;
3785 const char *rvalue;
3786 } table[] = {
7f8aa671 3787#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
3788 { config_parse_warn_compat, "NOTSUPPORTED" },
3789#endif
f975e971
LP
3790 { config_parse_int, "INTEGER" },
3791 { config_parse_unsigned, "UNSIGNED" },
5556b5fe 3792 { config_parse_iec_size, "SIZE" },
59f448cf 3793 { config_parse_iec_uint64, "SIZE" },
5556b5fe 3794 { config_parse_si_size, "SIZE" },
f975e971
LP
3795 { config_parse_bool, "BOOLEAN" },
3796 { config_parse_string, "STRING" },
3797 { config_parse_path, "PATH" },
3798 { config_parse_unit_path_printf, "PATH" },
3799 { config_parse_strv, "STRING [...]" },
3800 { config_parse_exec_nice, "NICE" },
3801 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3802 { config_parse_exec_io_class, "IOCLASS" },
3803 { config_parse_exec_io_priority, "IOPRIORITY" },
3804 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3805 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3806 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3807 { config_parse_mode, "MODE" },
3808 { config_parse_unit_env_file, "FILE" },
3809 { config_parse_output, "OUTPUT" },
3810 { config_parse_input, "INPUT" },
ca37242e
LP
3811 { config_parse_log_facility, "FACILITY" },
3812 { config_parse_log_level, "LEVEL" },
f975e971
LP
3813 { config_parse_exec_capabilities, "CAPABILITIES" },
3814 { config_parse_exec_secure_bits, "SECUREBITS" },
a103496c 3815 { config_parse_capability_set, "BOUNDINGSET" },
f975e971 3816 { config_parse_limit, "LIMIT" },
f975e971 3817 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
3818 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3819 { config_parse_service_type, "SERVICETYPE" },
3820 { config_parse_service_restart, "SERVICERESTART" },
3821#ifdef HAVE_SYSV_COMPAT
3822 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
3823#endif
3824 { config_parse_kill_mode, "KILLMODE" },
f757855e 3825 { config_parse_signal, "SIGNAL" },
f975e971
LP
3826 { config_parse_socket_listen, "SOCKET [...]" },
3827 { config_parse_socket_bind, "SOCKETBIND" },
3828 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 3829 { config_parse_sec, "SECONDS" },
d88a251b 3830 { config_parse_nsec, "NANOSECONDS" },
94828d2d 3831 { config_parse_namespace_path_strv, "PATH [...]" },
7c8fa05c 3832 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
3833 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3834 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 3835 { config_parse_trigger_unit, "UNIT" },
f975e971 3836 { config_parse_timer, "TIMER" },
f975e971 3837 { config_parse_path_spec, "PATH" },
f975e971
LP
3838 { config_parse_notify_access, "ACCESS" },
3839 { config_parse_ip_tos, "TOS" },
3840 { config_parse_unit_condition_path, "CONDITION" },
3841 { config_parse_unit_condition_string, "CONDITION" },
3842 { config_parse_unit_condition_null, "CONDITION" },
a016b922 3843 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
3844 { config_parse_documentation, "URL" },
3845 { config_parse_service_timeout, "SECONDS" },
bf500566 3846 { config_parse_failure_action, "ACTION" },
7f0386f6
LP
3847 { config_parse_set_status, "STATUS" },
3848 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 3849 { config_parse_environ, "ENVIRON" },
c0467cf3 3850#ifdef HAVE_SECCOMP
17df7223 3851 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 3852 { config_parse_syscall_archs, "ARCHS" },
17df7223 3853 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 3854 { config_parse_address_families, "FAMILIES" },
c0467cf3 3855#endif
7f0386f6
LP
3856 { config_parse_cpu_shares, "SHARES" },
3857 { config_parse_memory_limit, "LIMIT" },
3858 { config_parse_device_allow, "DEVICE" },
3859 { config_parse_device_policy, "POLICY" },
3860 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3861 { config_parse_blockio_weight, "WEIGHT" },
3862 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3863 { config_parse_long, "LONG" },
3864 { config_parse_socket_service, "SERVICE" },
6a6751fe
LP
3865#ifdef HAVE_SELINUX
3866 { config_parse_exec_selinux_context, "LABEL" },
3867#endif
3868 { config_parse_job_mode, "MODE" },
3869 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 3870 { config_parse_personality, "PERSONALITY" },
f975e971
LP
3871 };
3872
3873 const char *prev = NULL;
3874 const char *i;
3875
3876 assert(f);
e537352b 3877
f975e971
LP
3878 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3879 const char *rvalue = "OTHER", *lvalue;
3880 unsigned j;
3881 size_t prefix_len;
3882 const char *dot;
3883 const ConfigPerfItem *p;
3884
3885 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3886
3887 dot = strchr(i, '.');
3888 lvalue = dot ? dot + 1 : i;
3889 prefix_len = dot-i;
3890
3891 if (dot)
641906e9 3892 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
3893 if (prev)
3894 fputc('\n', f);
3895
3896 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3897 }
3898
3899 for (j = 0; j < ELEMENTSOF(table); j++)
3900 if (p->parse == table[j].callback) {
3901 rvalue = table[j].rvalue;
3902 break;
3903 }
3904
3905 fprintf(f, "%s=%s\n", lvalue, rvalue);
3906 prev = i;
3907 }
e537352b 3908}