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