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