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