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