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