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