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