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