]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
NEWS: update NEWS about ProtectKernelModules= option (#4445)
[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
52c239d7
LB
779DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input literal specifier");
780DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output literal specifier");
781
782int config_parse_exec_input(const char *unit,
783 const char *filename,
784 unsigned line,
785 const char *section,
786 unsigned section_line,
787 const char *lvalue,
788 int ltype,
789 const char *rvalue,
790 void *data,
791 void *userdata) {
792 ExecContext *c = data;
793 const char *name;
794 int r;
795
796 assert(data);
797 assert(filename);
798 assert(line);
799 assert(rvalue);
800
801 name = startswith(rvalue, "fd:");
802 if (name) {
803 /* Strip prefix and validate fd name */
804 if (!fdname_is_valid(name)) {
805 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
806 return 0;
807 }
808 c->std_input = EXEC_INPUT_NAMED_FD;
809 r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], name);
810 if (r < 0)
811 log_oom();
812 return r;
813 } else {
814 ExecInput ei = exec_input_from_string(rvalue);
815 if (ei == _EXEC_INPUT_INVALID)
816 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue);
817 else
818 c->std_input = ei;
819 return 0;
820 }
821}
822
823int config_parse_exec_output(const char *unit,
824 const char *filename,
825 unsigned line,
826 const char *section,
827 unsigned section_line,
828 const char *lvalue,
829 int ltype,
830 const char *rvalue,
831 void *data,
832 void *userdata) {
833 ExecContext *c = data;
834 ExecOutput eo;
835 const char *name;
836 int r;
837
838 assert(data);
839 assert(filename);
840 assert(line);
841 assert(lvalue);
842 assert(rvalue);
843
844 name = startswith(rvalue, "fd:");
845 if (name) {
846 /* Strip prefix and validate fd name */
847 if (!fdname_is_valid(name)) {
848 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
849 return 0;
850 }
851 eo = EXEC_OUTPUT_NAMED_FD;
852 } else {
853 eo = exec_output_from_string(rvalue);
854 if (eo == _EXEC_OUTPUT_INVALID) {
855 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue);
856 return 0;
857 }
858 }
859
860 if (streq(lvalue, "StandardOutput")) {
861 c->std_output = eo;
862 r = free_and_strdup(&c->stdio_fdname[STDOUT_FILENO], name);
863 if (r < 0)
864 log_oom();
865 return r;
866 } else if (streq(lvalue, "StandardError")) {
867 c->std_error = eo;
868 r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], name);
869 if (r < 0)
870 log_oom();
871 return r;
872 } else {
873 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output property, ignoring: %s", lvalue);
874 return 0;
875 }
876}
87f0e418 877
e8e581bf
ZJS
878int config_parse_exec_io_class(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) {
94f04347
LP
888
889 ExecContext *c = data;
890 int x;
891
892 assert(filename);
893 assert(lvalue);
894 assert(rvalue);
895 assert(data);
896
f8b69d1d
MS
897 x = ioprio_class_from_string(rvalue);
898 if (x < 0) {
12ca818f 899 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
c0b34696 900 return 0;
0d87eb42 901 }
94f04347
LP
902
903 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
904 c->ioprio_set = true;
905
906 return 0;
907}
908
e8e581bf
ZJS
909int config_parse_exec_io_priority(const char *unit,
910 const char *filename,
911 unsigned line,
912 const char *section,
71a61510 913 unsigned section_line,
e8e581bf
ZJS
914 const char *lvalue,
915 int ltype,
916 const char *rvalue,
917 void *data,
918 void *userdata) {
94f04347
LP
919
920 ExecContext *c = data;
e8e581bf 921 int i, r;
94f04347
LP
922
923 assert(filename);
924 assert(lvalue);
925 assert(rvalue);
926 assert(data);
927
e8e581bf
ZJS
928 r = safe_atoi(rvalue, &i);
929 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
12ca818f 930 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
c0b34696 931 return 0;
071830ff
LP
932 }
933
94f04347
LP
934 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
935 c->ioprio_set = true;
936
071830ff
LP
937 return 0;
938}
939
e8e581bf
ZJS
940int config_parse_exec_cpu_sched_policy(const char *unit,
941 const char *filename,
942 unsigned line,
943 const char *section,
71a61510 944 unsigned section_line,
e8e581bf
ZJS
945 const char *lvalue,
946 int ltype,
947 const char *rvalue,
948 void *data,
949 void *userdata) {
9eba9da4 950
94f04347
LP
951
952 ExecContext *c = data;
953 int x;
954
955 assert(filename);
956 assert(lvalue);
957 assert(rvalue);
958 assert(data);
959
f8b69d1d
MS
960 x = sched_policy_from_string(rvalue);
961 if (x < 0) {
12ca818f 962 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 963 return 0;
0d87eb42 964 }
94f04347
LP
965
966 c->cpu_sched_policy = x;
bb112710
HHPF
967 /* Moving to or from real-time policy? We need to adjust the priority */
968 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
94f04347
LP
969 c->cpu_sched_set = true;
970
971 return 0;
972}
973
e8e581bf
ZJS
974int config_parse_exec_cpu_sched_prio(const char *unit,
975 const char *filename,
976 unsigned line,
977 const char *section,
71a61510 978 unsigned section_line,
e8e581bf
ZJS
979 const char *lvalue,
980 int ltype,
981 const char *rvalue,
982 void *data,
983 void *userdata) {
9eba9da4
LP
984
985 ExecContext *c = data;
e8e581bf 986 int i, min, max, r;
9eba9da4
LP
987
988 assert(filename);
989 assert(lvalue);
990 assert(rvalue);
991 assert(data);
992
e8e581bf
ZJS
993 r = safe_atoi(rvalue, &i);
994 if (r < 0) {
12ca818f 995 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 996 return 0;
94f04347 997 }
9eba9da4 998
bb112710
HHPF
999 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1000 min = sched_get_priority_min(c->cpu_sched_policy);
1001 max = sched_get_priority_max(c->cpu_sched_policy);
1002
1003 if (i < min || i > max) {
12ca818f 1004 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
bb112710
HHPF
1005 return 0;
1006 }
1007
94f04347
LP
1008 c->cpu_sched_priority = i;
1009 c->cpu_sched_set = true;
1010
1011 return 0;
1012}
1013
e8e581bf
ZJS
1014int config_parse_exec_cpu_affinity(const char *unit,
1015 const char *filename,
1016 unsigned line,
1017 const char *section,
71a61510 1018 unsigned section_line,
e8e581bf
ZJS
1019 const char *lvalue,
1020 int ltype,
1021 const char *rvalue,
1022 void *data,
1023 void *userdata) {
94f04347
LP
1024
1025 ExecContext *c = data;
9d5ca7f8
FB
1026 _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
1027 int ncpus;
94f04347
LP
1028
1029 assert(filename);
1030 assert(lvalue);
1031 assert(rvalue);
1032 assert(data);
1033
765d143b 1034 ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
9d5ca7f8
FB
1035 if (ncpus < 0)
1036 return ncpus;
487393e9 1037
9d5ca7f8
FB
1038 if (c->cpuset)
1039 CPU_FREE(c->cpuset);
82c121a4 1040
9d5ca7f8
FB
1041 if (ncpus == 0)
1042 /* An empty assignment resets the CPU list */
1043 c->cpuset = NULL;
1044 else {
1045 c->cpuset = cpuset;
1046 cpuset = NULL;
9eba9da4 1047 }
9d5ca7f8 1048 c->cpuset_ncpus = ncpus;
9eba9da4 1049
94f04347
LP
1050 return 0;
1051}
1052
e8e581bf
ZJS
1053int config_parse_exec_secure_bits(const char *unit,
1054 const char *filename,
1055 unsigned line,
1056 const char *section,
71a61510 1057 unsigned section_line,
e8e581bf
ZJS
1058 const char *lvalue,
1059 int ltype,
1060 const char *rvalue,
1061 void *data,
1062 void *userdata) {
94f04347
LP
1063
1064 ExecContext *c = data;
94f04347 1065 size_t l;
a2a5291b 1066 const char *word, *state;
94f04347
LP
1067
1068 assert(filename);
1069 assert(lvalue);
1070 assert(rvalue);
1071 assert(data);
1072
74051b9b
LP
1073 if (isempty(rvalue)) {
1074 /* An empty assignment resets the field */
1075 c->secure_bits = 0;
1076 return 0;
1077 }
1078
a2a5291b
ZJS
1079 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1080 if (first_word(word, "keep-caps"))
cbb21cca 1081 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
a2a5291b 1082 else if (first_word(word, "keep-caps-locked"))
cbb21cca 1083 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
a2a5291b 1084 else if (first_word(word, "no-setuid-fixup"))
cbb21cca 1085 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
a2a5291b 1086 else if (first_word(word, "no-setuid-fixup-locked"))
cbb21cca 1087 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
a2a5291b 1088 else if (first_word(word, "noroot"))
cbb21cca 1089 c->secure_bits |= 1<<SECURE_NOROOT;
a2a5291b 1090 else if (first_word(word, "noroot-locked"))
cbb21cca 1091 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
9eba9da4 1092 else {
12ca818f 1093 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse secure bits, ignoring: %s", rvalue);
c0b34696 1094 return 0;
9eba9da4
LP
1095 }
1096 }
b2fadec6 1097 if (!isempty(state))
12ca818f 1098 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring.");
9eba9da4 1099
94f04347
LP
1100 return 0;
1101}
1102
a103496c 1103int config_parse_capability_set(
65dce264
LP
1104 const char *unit,
1105 const char *filename,
1106 unsigned line,
1107 const char *section,
1108 unsigned section_line,
1109 const char *lvalue,
1110 int ltype,
1111 const char *rvalue,
1112 void *data,
1113 void *userdata) {
94f04347 1114
a103496c
IP
1115 uint64_t *capability_set = data;
1116 uint64_t sum = 0, initial = 0;
260abb78 1117 bool invert = false;
65dce264 1118 const char *p;
94f04347
LP
1119
1120 assert(filename);
1121 assert(lvalue);
1122 assert(rvalue);
1123 assert(data);
1124
260abb78
LP
1125 if (rvalue[0] == '~') {
1126 invert = true;
1127 rvalue++;
1128 }
1129
a103496c
IP
1130 if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
1131 initial = CAP_ALL; /* initialized to all bits on */
755d4b67 1132 /* else "AmbientCapabilities" initialized to all bits off */
260abb78 1133
65dce264 1134 p = rvalue;
9ef57298
EV
1135 for (;;) {
1136 _cleanup_free_ char *word = NULL;
65dce264 1137 int cap, r;
94f04347 1138
65dce264 1139 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
9ef57298
EV
1140 if (r == 0)
1141 break;
1142 if (r == -ENOMEM)
74051b9b 1143 return log_oom();
9ef57298 1144 if (r < 0) {
65dce264 1145 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
9ef57298
EV
1146 break;
1147 }
94f04347 1148
9ef57298 1149 cap = capability_from_name(word);
2822da4f 1150 if (cap < 0) {
755d4b67 1151 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
8351ceae 1152 continue;
94f04347
LP
1153 }
1154
65dce264 1155 sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
94f04347 1156 }
9eba9da4 1157
a103496c
IP
1158 sum = invert ? ~sum : sum;
1159
1160 if (sum == 0 || *capability_set == initial)
1161 /* "" or uninitialized data -> replace */
1162 *capability_set = sum;
260abb78 1163 else
a103496c
IP
1164 /* previous data -> merge */
1165 *capability_set |= sum;
260abb78 1166
9eba9da4
LP
1167 return 0;
1168}
1169
91518d20 1170int config_parse_limit(
d580265e
LP
1171 const char *unit,
1172 const char *filename,
1173 unsigned line,
1174 const char *section,
1175 unsigned section_line,
1176 const char *lvalue,
1177 int ltype,
1178 const char *rvalue,
1179 void *data,
1180 void *userdata) {
412ea7a9 1181
d0a7c5f6
LP
1182 struct rlimit **rl = data, d = {};
1183 int r;
a4c18002
LP
1184
1185 assert(filename);
1186 assert(lvalue);
1187 assert(rvalue);
1188 assert(data);
1189
d0a7c5f6
LP
1190 r = rlimit_parse(ltype, rvalue, &d);
1191 if (r == -EILSEQ) {
1192 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1193 return 0;
1194 }
1195 if (r < 0) {
1196 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1197 return 0;
1198 }
a4c18002 1199
d0a7c5f6
LP
1200 if (rl[ltype])
1201 *rl[ltype] = d;
1202 else {
1203 rl[ltype] = newdup(struct rlimit, &d, 1);
1204 if (!rl[ltype])
1205 return log_oom();
1206 }
a4c18002 1207
d0a7c5f6 1208 return 0;
91518d20 1209}
a4c18002 1210
07459bb6 1211#ifdef HAVE_SYSV_COMPAT
e8e581bf
ZJS
1212int config_parse_sysv_priority(const char *unit,
1213 const char *filename,
1214 unsigned line,
1215 const char *section,
71a61510 1216 unsigned section_line,
e8e581bf
ZJS
1217 const char *lvalue,
1218 int ltype,
1219 const char *rvalue,
1220 void *data,
1221 void *userdata) {
a9a1e00a
LP
1222
1223 int *priority = data;
e8e581bf 1224 int i, r;
a9a1e00a
LP
1225
1226 assert(filename);
1227 assert(lvalue);
1228 assert(rvalue);
1229 assert(data);
1230
e8e581bf
ZJS
1231 r = safe_atoi(rvalue, &i);
1232 if (r < 0 || i < 0) {
12ca818f 1233 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
c0b34696 1234 return 0;
a9a1e00a
LP
1235 }
1236
1237 *priority = (int) i;
1238 return 0;
1239}
07459bb6 1240#endif
a9a1e00a 1241
023a4f67 1242DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
f975e971 1243DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
50159e6a 1244
e8e581bf
ZJS
1245int config_parse_exec_mount_flags(const char *unit,
1246 const char *filename,
1247 unsigned line,
1248 const char *section,
71a61510 1249 unsigned section_line,
e8e581bf
ZJS
1250 const char *lvalue,
1251 int ltype,
1252 const char *rvalue,
1253 void *data,
1254 void *userdata) {
15ae422b 1255
e28bb14a 1256
15ae422b 1257 unsigned long flags = 0;
e28bb14a 1258 ExecContext *c = data;
15ae422b
LP
1259
1260 assert(filename);
1261 assert(lvalue);
1262 assert(rvalue);
1263 assert(data);
1264
e28bb14a
SS
1265 if (streq(rvalue, "shared"))
1266 flags = MS_SHARED;
1267 else if (streq(rvalue, "slave"))
1268 flags = MS_SLAVE;
1269 else if (streq(rvalue, "private"))
1270 flags = MS_PRIVATE;
1271 else {
1272 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
1273 return 0;
15ae422b
LP
1274 }
1275
1276 c->mount_flags = flags;
e28bb14a 1277
15ae422b
LP
1278 return 0;
1279}
1280
5f8640fb
LP
1281int config_parse_exec_selinux_context(
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->selinux_context = mfree(c->selinux_context);
5f8640fb
LP
1306 c->selinux_context_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");
5f8640fb
LP
1319 return 0;
1320 }
1321
1322 free(c->selinux_context);
1323 c->selinux_context = k;
1324 c->selinux_context_ignore = ignore;
1325
1326 return 0;
1327}
1328
eef65bf3
MS
1329int config_parse_exec_apparmor_profile(
1330 const char *unit,
1331 const char *filename,
1332 unsigned line,
1333 const char *section,
1334 unsigned section_line,
1335 const char *lvalue,
1336 int ltype,
1337 const char *rvalue,
1338 void *data,
1339 void *userdata) {
1340
1341 ExecContext *c = data;
1342 Unit *u = userdata;
1343 bool ignore;
1344 char *k;
1345 int r;
1346
1347 assert(filename);
1348 assert(lvalue);
1349 assert(rvalue);
1350 assert(data);
1351
1352 if (isempty(rvalue)) {
a1e58e8e 1353 c->apparmor_profile = mfree(c->apparmor_profile);
eef65bf3
MS
1354 c->apparmor_profile_ignore = false;
1355 return 0;
1356 }
1357
1358 if (rvalue[0] == '-') {
1359 ignore = true;
1360 rvalue++;
1361 } else
1362 ignore = false;
1363
1364 r = unit_name_printf(u, rvalue, &k);
1365 if (r < 0) {
12ca818f 1366 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
eef65bf3
MS
1367 return 0;
1368 }
1369
1370 free(c->apparmor_profile);
1371 c->apparmor_profile = k;
1372 c->apparmor_profile_ignore = ignore;
1373
1374 return 0;
1375}
1376
2ca620c4
WC
1377int config_parse_exec_smack_process_label(
1378 const char *unit,
1379 const char *filename,
1380 unsigned line,
1381 const char *section,
1382 unsigned section_line,
1383 const char *lvalue,
1384 int ltype,
1385 const char *rvalue,
1386 void *data,
1387 void *userdata) {
1388
1389 ExecContext *c = data;
1390 Unit *u = userdata;
1391 bool ignore;
1392 char *k;
1393 int r;
1394
1395 assert(filename);
1396 assert(lvalue);
1397 assert(rvalue);
1398 assert(data);
1399
1400 if (isempty(rvalue)) {
a1e58e8e 1401 c->smack_process_label = mfree(c->smack_process_label);
2ca620c4
WC
1402 c->smack_process_label_ignore = false;
1403 return 0;
1404 }
1405
1406 if (rvalue[0] == '-') {
1407 ignore = true;
1408 rvalue++;
1409 } else
1410 ignore = false;
1411
1412 r = unit_name_printf(u, rvalue, &k);
1413 if (r < 0) {
12ca818f 1414 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
2ca620c4
WC
1415 return 0;
1416 }
1417
1418 free(c->smack_process_label);
1419 c->smack_process_label = k;
1420 c->smack_process_label_ignore = ignore;
1421
1422 return 0;
1423}
1424
e8e581bf
ZJS
1425int config_parse_timer(const char *unit,
1426 const char *filename,
1427 unsigned line,
1428 const char *section,
71a61510 1429 unsigned section_line,
e8e581bf
ZJS
1430 const char *lvalue,
1431 int ltype,
1432 const char *rvalue,
1433 void *data,
1434 void *userdata) {
871d7de4
LP
1435
1436 Timer *t = data;
2507992f 1437 usec_t usec = 0;
871d7de4
LP
1438 TimerValue *v;
1439 TimerBase b;
36697dc0 1440 CalendarSpec *c = NULL;
2507992f
DC
1441 Unit *u = userdata;
1442 _cleanup_free_ char *k = NULL;
1443 int r;
871d7de4
LP
1444
1445 assert(filename);
1446 assert(lvalue);
1447 assert(rvalue);
1448 assert(data);
1449
74051b9b
LP
1450 if (isempty(rvalue)) {
1451 /* Empty assignment resets list */
1452 timer_free_values(t);
1453 return 0;
1454 }
1455
36697dc0
LP
1456 b = timer_base_from_string(lvalue);
1457 if (b < 0) {
12ca818f 1458 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
c0b34696 1459 return 0;
871d7de4
LP
1460 }
1461
2507992f
DC
1462 r = unit_full_printf(u, rvalue, &k);
1463 if (r < 0) {
1464 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1465 return 0;
1466 }
1467
36697dc0 1468 if (b == TIMER_CALENDAR) {
2507992f
DC
1469 if (calendar_spec_from_string(k, &c) < 0) {
1470 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k);
36697dc0
LP
1471 return 0;
1472 }
36697dc0 1473 } else {
2507992f
DC
1474 if (parse_sec(k, &usec) < 0) {
1475 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k);
36697dc0
LP
1476 return 0;
1477 }
871d7de4
LP
1478 }
1479
36697dc0 1480 v = new0(TimerValue, 1);
4d5e13a1 1481 if (!v) {
0b76b4d8 1482 calendar_spec_free(c);
74051b9b 1483 return log_oom();
4d5e13a1 1484 }
871d7de4
LP
1485
1486 v->base = b;
2507992f 1487 v->value = usec;
36697dc0 1488 v->calendar_spec = c;
871d7de4 1489
71fda00f 1490 LIST_PREPEND(value, t->values, v);
871d7de4
LP
1491
1492 return 0;
1493}
1494
3ecaa09b
LP
1495int config_parse_trigger_unit(
1496 const char *unit,
1497 const char *filename,
1498 unsigned line,
1499 const char *section,
71a61510 1500 unsigned section_line,
3ecaa09b
LP
1501 const char *lvalue,
1502 int ltype,
1503 const char *rvalue,
1504 void *data,
1505 void *userdata) {
871d7de4 1506
74051b9b 1507 _cleanup_free_ char *p = NULL;
3ecaa09b
LP
1508 Unit *u = data;
1509 UnitType type;
1510 int r;
398ef8ba
LP
1511
1512 assert(filename);
1513 assert(lvalue);
1514 assert(rvalue);
1515 assert(data);
1516
3ecaa09b 1517 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
12ca818f 1518 log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
3ecaa09b
LP
1519 return 0;
1520 }
871d7de4 1521
19f6d710 1522 r = unit_name_printf(u, rvalue, &p);
12ca818f
LP
1523 if (r < 0) {
1524 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1525 return 0;
1526 }
74051b9b 1527
12ca818f 1528 type = unit_name_to_type(p);
3ecaa09b 1529 if (type < 0) {
12ca818f 1530 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
c0b34696 1531 return 0;
871d7de4
LP
1532 }
1533
3ecaa09b 1534 if (type == u->type) {
12ca818f 1535 log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
3ecaa09b
LP
1536 return 0;
1537 }
1538
12ca818f 1539 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
57020a3a 1540 if (r < 0) {
12ca818f 1541 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
c0b34696 1542 return 0;
871d7de4
LP
1543 }
1544
1545 return 0;
1546}
1547
e8e581bf
ZJS
1548int config_parse_path_spec(const char *unit,
1549 const char *filename,
1550 unsigned line,
1551 const char *section,
71a61510 1552 unsigned section_line,
e8e581bf
ZJS
1553 const char *lvalue,
1554 int ltype,
1555 const char *rvalue,
1556 void *data,
1557 void *userdata) {
01f78473
LP
1558
1559 Path *p = data;
1560 PathSpec *s;
1561 PathType b;
7fd1b19b 1562 _cleanup_free_ char *k = NULL;
19f6d710 1563 int r;
01f78473
LP
1564
1565 assert(filename);
1566 assert(lvalue);
1567 assert(rvalue);
1568 assert(data);
1569
74051b9b
LP
1570 if (isempty(rvalue)) {
1571 /* Empty assignment clears list */
1572 path_free_specs(p);
1573 return 0;
1574 }
1575
93e4c84b
LP
1576 b = path_type_from_string(lvalue);
1577 if (b < 0) {
12ca818f 1578 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 1579 return 0;
01f78473
LP
1580 }
1581
19f6d710
LP
1582 r = unit_full_printf(UNIT(p), rvalue, &k);
1583 if (r < 0) {
12ca818f
LP
1584 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1585 return 0;
487060c2 1586 }
93e4c84b
LP
1587
1588 if (!path_is_absolute(k)) {
12ca818f 1589 log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
c0b34696 1590 return 0;
01f78473
LP
1591 }
1592
93e4c84b 1593 s = new0(PathSpec, 1);
543295ad 1594 if (!s)
93e4c84b 1595 return log_oom();
01f78473 1596
718db961 1597 s->unit = UNIT(p);
93e4c84b 1598 s->path = path_kill_slashes(k);
543295ad 1599 k = NULL;
01f78473
LP
1600 s->type = b;
1601 s->inotify_fd = -1;
1602
71fda00f 1603 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
1604
1605 return 0;
1606}
1607
b02cb41c
LP
1608int config_parse_socket_service(
1609 const char *unit,
1610 const char *filename,
1611 unsigned line,
1612 const char *section,
1613 unsigned section_line,
1614 const char *lvalue,
1615 int ltype,
1616 const char *rvalue,
1617 void *data,
1618 void *userdata) {
d9ff321a 1619
4afd3348 1620 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8dd4c05b 1621 _cleanup_free_ char *p = NULL;
d9ff321a 1622 Socket *s = data;
4ff77f66 1623 Unit *x;
8dd4c05b 1624 int r;
d9ff321a
LP
1625
1626 assert(filename);
1627 assert(lvalue);
1628 assert(rvalue);
1629 assert(data);
1630
19f6d710 1631 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 1632 if (r < 0) {
b02cb41c 1633 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
613b411c
LP
1634 return 0;
1635 }
74051b9b 1636
613b411c 1637 if (!endswith(p, ".service")) {
12ca818f 1638 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
d9ff321a
LP
1639 return 0;
1640 }
1641
613b411c 1642 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 1643 if (r < 0) {
12ca818f 1644 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
d9ff321a
LP
1645 return 0;
1646 }
1647
4ff77f66
LP
1648 unit_ref_set(&s->service, x);
1649
d9ff321a
LP
1650 return 0;
1651}
1652
8dd4c05b
LP
1653int config_parse_fdname(
1654 const char *unit,
1655 const char *filename,
1656 unsigned line,
1657 const char *section,
1658 unsigned section_line,
1659 const char *lvalue,
1660 int ltype,
1661 const char *rvalue,
1662 void *data,
1663 void *userdata) {
1664
1665 _cleanup_free_ char *p = NULL;
1666 Socket *s = data;
1667 int r;
1668
1669 assert(filename);
1670 assert(lvalue);
1671 assert(rvalue);
1672 assert(data);
1673
1674 if (isempty(rvalue)) {
1675 s->fdname = mfree(s->fdname);
1676 return 0;
1677 }
1678
1679 r = unit_name_printf(UNIT(s), rvalue, &p);
1680 if (r < 0) {
1681 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1682 return 0;
1683 }
1684
1685 if (!fdname_is_valid(p)) {
1686 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
1687 return 0;
1688 }
1689
3b319885 1690 return free_and_replace(s->fdname, p);
8dd4c05b
LP
1691}
1692
b02cb41c
LP
1693int config_parse_service_sockets(
1694 const char *unit,
1695 const char *filename,
1696 unsigned line,
1697 const char *section,
1698 unsigned section_line,
1699 const char *lvalue,
1700 int ltype,
1701 const char *rvalue,
1702 void *data,
1703 void *userdata) {
f976f3f6
LP
1704
1705 Service *s = data;
7b2313f5 1706 const char *p;
b02cb41c 1707 int r;
f976f3f6
LP
1708
1709 assert(filename);
1710 assert(lvalue);
1711 assert(rvalue);
1712 assert(data);
1713
7b2313f5 1714 p = rvalue;
9ed794a3 1715 for (;;) {
6a0f3175 1716 _cleanup_free_ char *word = NULL, *k = NULL;
f976f3f6 1717
7b2313f5
SS
1718 r = extract_first_word(&p, &word, NULL, 0);
1719 if (r == 0)
1720 break;
1721 if (r == -ENOMEM)
74051b9b 1722 return log_oom();
7b2313f5
SS
1723 if (r < 0) {
1724 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
1725 break;
1726 }
f976f3f6 1727
7b2313f5 1728 r = unit_name_printf(UNIT(s), word, &k);
b02cb41c
LP
1729 if (r < 0) {
1730 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1731 continue;
1732 }
57020a3a 1733
b02cb41c 1734 if (!endswith(k, ".socket")) {
12ca818f 1735 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
f976f3f6
LP
1736 continue;
1737 }
1738
b02cb41c 1739 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
57020a3a 1740 if (r < 0)
b02cb41c 1741 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 1742
b02cb41c 1743 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
57020a3a 1744 if (r < 0)
b02cb41c 1745 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6
LP
1746 }
1747
1748 return 0;
1749}
1750
b02cb41c
LP
1751int config_parse_bus_name(
1752 const char *unit,
1753 const char *filename,
1754 unsigned line,
1755 const char *section,
1756 unsigned section_line,
1757 const char *lvalue,
1758 int ltype,
1759 const char *rvalue,
1760 void *data,
1761 void *userdata) {
1762
1763 _cleanup_free_ char *k = NULL;
1764 Unit *u = userdata;
1765 int r;
1766
1767 assert(filename);
1768 assert(lvalue);
1769 assert(rvalue);
1770 assert(u);
1771
1772 r = unit_full_printf(u, rvalue, &k);
1773 if (r < 0) {
1774 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1775 return 0;
1776 }
1777
1778 if (!service_name_is_valid(k)) {
12ca818f 1779 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
b02cb41c
LP
1780 return 0;
1781 }
1782
1783 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1784}
1785
aad41f08
LP
1786int config_parse_service_timeout(
1787 const char *unit,
1788 const char *filename,
1789 unsigned line,
1790 const char *section,
1791 unsigned section_line,
1792 const char *lvalue,
1793 int ltype,
1794 const char *rvalue,
1795 void *data,
1796 void *userdata) {
98709151
LN
1797
1798 Service *s = userdata;
aad41f08 1799 usec_t usec;
98709151
LN
1800 int r;
1801
1802 assert(filename);
1803 assert(lvalue);
1804 assert(rvalue);
1805 assert(s);
1806
aad41f08 1807 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
98709151 1808
aad41f08
LP
1809 r = parse_sec(rvalue, &usec);
1810 if (r < 0) {
1811 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1812 return 0;
1813 }
d568a335 1814
36c16a7c
LP
1815 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1816 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1817 * all other timeouts. */
aad41f08
LP
1818 if (usec <= 0)
1819 usec = USEC_INFINITY;
1820
1821 if (!streq(lvalue, "TimeoutStopSec")) {
1822 s->start_timeout_defined = true;
1823 s->timeout_start_usec = usec;
1824 }
36c16a7c 1825
aad41f08
LP
1826 if (!streq(lvalue, "TimeoutStartSec"))
1827 s->timeout_stop_usec = usec;
36c16a7c 1828
d568a335 1829 return 0;
98709151
LN
1830}
1831
89beff89
LP
1832int config_parse_sec_fix_0(
1833 const char *unit,
1834 const char *filename,
1835 unsigned line,
1836 const char *section,
1837 unsigned section_line,
1838 const char *lvalue,
1839 int ltype,
1840 const char *rvalue,
1841 void *data,
1842 void *userdata) {
1843
1844 usec_t *usec = data;
1845 int r;
1846
1847 assert(filename);
1848 assert(lvalue);
1849 assert(rvalue);
1850 assert(usec);
1851
1852 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1853 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1854 * timeout. */
1855
1856 r = parse_sec(rvalue, usec);
1857 if (r < 0) {
1858 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1859 return 0;
1860 }
1861
1862 if (*usec <= 0)
1863 *usec = USEC_INFINITY;
1864
1865 return 0;
1866}
1867
66dccd8d
LP
1868int config_parse_user_group(
1869 const char *unit,
1870 const char *filename,
1871 unsigned line,
1872 const char *section,
1873 unsigned section_line,
1874 const char *lvalue,
1875 int ltype,
1876 const char *rvalue,
1877 void *data,
1878 void *userdata) {
1879
1880 char **user = data, *n;
1881 Unit *u = userdata;
1882 int r;
1883
1884 assert(filename);
1885 assert(lvalue);
1886 assert(rvalue);
1887 assert(u);
1888
1889 if (isempty(rvalue))
1890 n = NULL;
1891 else {
1892 _cleanup_free_ char *k = NULL;
1893
1894 r = unit_full_printf(u, rvalue, &k);
1895 if (r < 0) {
1896 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1897 return 0;
1898 }
1899
1900 if (!valid_user_group_name_or_id(k)) {
1901 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
1902 return 0;
1903 }
1904
1905 n = k;
1906 k = NULL;
1907 }
1908
1909 free(*user);
1910 *user = n;
1911
1912 return 0;
1913}
1914
1915int config_parse_user_group_strv(
1916 const char *unit,
1917 const char *filename,
1918 unsigned line,
1919 const char *section,
1920 unsigned section_line,
1921 const char *lvalue,
1922 int ltype,
1923 const char *rvalue,
1924 void *data,
1925 void *userdata) {
1926
1927 char ***users = data;
1928 Unit *u = userdata;
1929 const char *p;
1930 int r;
1931
1932 assert(filename);
1933 assert(lvalue);
1934 assert(rvalue);
1935 assert(u);
1936
1937 if (isempty(rvalue)) {
1938 char **empty;
1939
1940 empty = new0(char*, 1);
1941 if (!empty)
1942 return log_oom();
1943
1944 strv_free(*users);
1945 *users = empty;
1946
1947 return 0;
1948 }
1949
1950 p = rvalue;
1951 for (;;) {
1952 _cleanup_free_ char *word = NULL, *k = NULL;
1953
1954 r = extract_first_word(&p, &word, WHITESPACE, 0);
1955 if (r == 0)
1956 break;
1957 if (r == -ENOMEM)
1958 return log_oom();
1959 if (r < 0) {
1960 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1961 break;
1962 }
1963
1964 r = unit_full_printf(u, word, &k);
1965 if (r < 0) {
1966 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
1967 continue;
1968 }
1969
1970 if (!valid_user_group_name_or_id(k)) {
1971 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
1972 continue;
1973 }
1974
1975 r = strv_push(users, k);
1976 if (r < 0)
1977 return log_oom();
1978
1979 k = NULL;
1980 }
1981
1982 return 0;
1983}
1984
e821075a
LP
1985int config_parse_busname_service(
1986 const char *unit,
1987 const char *filename,
1988 unsigned line,
1989 const char *section,
1990 unsigned section_line,
1991 const char *lvalue,
1992 int ltype,
1993 const char *rvalue,
1994 void *data,
1995 void *userdata) {
1996
4afd3348 1997 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
e821075a
LP
1998 BusName *n = data;
1999 int r;
2000 Unit *x;
2001 _cleanup_free_ char *p = NULL;
2002
2003 assert(filename);
2004 assert(lvalue);
2005 assert(rvalue);
2006 assert(data);
2007
2008 r = unit_name_printf(UNIT(n), rvalue, &p);
2009 if (r < 0) {
12ca818f 2010 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
e821075a
LP
2011 return 0;
2012 }
2013
2014 if (!endswith(p, ".service")) {
12ca818f 2015 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
e821075a
LP
2016 return 0;
2017 }
2018
2019 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
2020 if (r < 0) {
12ca818f 2021 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
e821075a
LP
2022 return 0;
2023 }
2024
2025 unit_ref_set(&n->service, x);
2026
2027 return 0;
2028}
2029
5369c77d 2030DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
a4152e3f 2031
54d76c92
DM
2032int config_parse_bus_policy(
2033 const char *unit,
2034 const char *filename,
2035 unsigned line,
2036 const char *section,
2037 unsigned section_line,
2038 const char *lvalue,
2039 int ltype,
2040 const char *rvalue,
2041 void *data,
2042 void *userdata) {
2043
2044 _cleanup_free_ BusNamePolicy *p = NULL;
2045 _cleanup_free_ char *id_str = NULL;
2046 BusName *busname = data;
2047 char *access_str;
54d76c92
DM
2048
2049 assert(filename);
2050 assert(lvalue);
2051 assert(rvalue);
2052 assert(data);
2053
2054 p = new0(BusNamePolicy, 1);
2055 if (!p)
2056 return log_oom();
2057
2058 if (streq(lvalue, "AllowUser"))
2059 p->type = BUSNAME_POLICY_TYPE_USER;
2060 else if (streq(lvalue, "AllowGroup"))
2061 p->type = BUSNAME_POLICY_TYPE_GROUP;
54d76c92
DM
2062 else
2063 assert_not_reached("Unknown lvalue");
2064
2065 id_str = strdup(rvalue);
2066 if (!id_str)
2067 return log_oom();
2068
a4152e3f
LP
2069 access_str = strpbrk(id_str, WHITESPACE);
2070 if (!access_str) {
12ca818f 2071 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
a4152e3f 2072 return 0;
54d76c92
DM
2073 }
2074
a4152e3f
LP
2075 *access_str = '\0';
2076 access_str++;
2077 access_str += strspn(access_str, WHITESPACE);
2078
5369c77d 2079 p->access = bus_policy_access_from_string(access_str);
54d76c92 2080 if (p->access < 0) {
12ca818f 2081 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
54d76c92
DM
2082 return 0;
2083 }
2084
a4152e3f
LP
2085 p->name = id_str;
2086 id_str = NULL;
2087
54d76c92
DM
2088 LIST_PREPEND(policy, busname->policy, p);
2089 p = NULL;
2090
2091 return 0;
2092}
2093
5f5d8eab
LP
2094int config_parse_working_directory(
2095 const char *unit,
2096 const char *filename,
2097 unsigned line,
2098 const char *section,
2099 unsigned section_line,
2100 const char *lvalue,
2101 int ltype,
2102 const char *rvalue,
2103 void *data,
2104 void *userdata) {
2105
2106 ExecContext *c = data;
2107 Unit *u = userdata;
2108 bool missing_ok;
2109 int r;
2110
2111 assert(filename);
2112 assert(lvalue);
2113 assert(rvalue);
2114 assert(c);
2115 assert(u);
2116
2117 if (rvalue[0] == '-') {
2118 missing_ok = true;
2119 rvalue++;
2120 } else
2121 missing_ok = false;
2122
2123 if (streq(rvalue, "~")) {
2124 c->working_directory_home = true;
2125 c->working_directory = mfree(c->working_directory);
2126 } else {
2127 _cleanup_free_ char *k = NULL;
2128
2129 r = unit_full_printf(u, rvalue, &k);
2130 if (r < 0) {
2131 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
2132 return 0;
2133 }
2134
2135 path_kill_slashes(k);
2136
2137 if (!utf8_is_valid(k)) {
0e05ee04 2138 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
5f5d8eab
LP
2139 return 0;
2140 }
2141
2142 if (!path_is_absolute(k)) {
2143 log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
2144 return 0;
2145 }
2146
3b319885 2147 free_and_replace(c->working_directory, k);
5f5d8eab
LP
2148
2149 c->working_directory_home = false;
2150 }
2151
2152 c->working_directory_missing_ok = missing_ok;
2153 return 0;
2154}
2155
e8e581bf
ZJS
2156int config_parse_unit_env_file(const char *unit,
2157 const char *filename,
2158 unsigned line,
2159 const char *section,
71a61510 2160 unsigned section_line,
e8e581bf
ZJS
2161 const char *lvalue,
2162 int ltype,
2163 const char *rvalue,
2164 void *data,
2165 void *userdata) {
ddb26e18 2166
853b8397 2167 char ***env = data;
8fef7659 2168 Unit *u = userdata;
19f6d710 2169 _cleanup_free_ char *n = NULL;
853b8397 2170 int r;
ddb26e18
LP
2171
2172 assert(filename);
2173 assert(lvalue);
2174 assert(rvalue);
2175 assert(data);
2176
74051b9b
LP
2177 if (isempty(rvalue)) {
2178 /* Empty assignment frees the list */
6796073e 2179 *env = strv_free(*env);
74051b9b
LP
2180 return 0;
2181 }
2182
19f6d710 2183 r = unit_full_printf(u, rvalue, &n);
12ca818f
LP
2184 if (r < 0) {
2185 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2186 return 0;
2187 }
8fef7659 2188
12ca818f
LP
2189 if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
2190 log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
afe4bfe2
LP
2191 return 0;
2192 }
2193
12ca818f 2194 r = strv_extend(env, n);
853b8397
LP
2195 if (r < 0)
2196 return log_oom();
2197
2198 return 0;
2199}
2200
e8e581bf
ZJS
2201int config_parse_environ(const char *unit,
2202 const char *filename,
2203 unsigned line,
2204 const char *section,
71a61510 2205 unsigned section_line,
e8e581bf
ZJS
2206 const char *lvalue,
2207 int ltype,
2208 const char *rvalue,
2209 void *data,
2210 void *userdata) {
853b8397
LP
2211
2212 Unit *u = userdata;
a2a5291b
ZJS
2213 char*** env = data;
2214 const char *word, *state;
853b8397
LP
2215 size_t l;
2216 _cleanup_free_ char *k = NULL;
19f6d710 2217 int r;
853b8397
LP
2218
2219 assert(filename);
2220 assert(lvalue);
2221 assert(rvalue);
97d0e5f8 2222 assert(data);
853b8397
LP
2223
2224 if (isempty(rvalue)) {
2225 /* Empty assignment resets the list */
6796073e 2226 *env = strv_free(*env);
853b8397
LP
2227 return 0;
2228 }
2229
19f6d710
LP
2230 if (u) {
2231 r = unit_full_printf(u, rvalue, &k);
12ca818f
LP
2232 if (r < 0) {
2233 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2234 return 0;
2235 }
19f6d710 2236 }
97d0e5f8 2237
12ca818f 2238 if (!k) {
19f6d710 2239 k = strdup(rvalue);
12ca818f
LP
2240 if (!k)
2241 return log_oom();
2242 }
ddb26e18 2243
a2a5291b 2244 FOREACH_WORD_QUOTED(word, l, k, state) {
67a3328f 2245 _cleanup_free_ char *n = NULL;
853b8397
LP
2246 char **x;
2247
527b7a42
LP
2248 r = cunescape_length(word, l, 0, &n);
2249 if (r < 0) {
2250 log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
2251 continue;
2252 }
853b8397
LP
2253
2254 if (!env_assignment_is_valid(n)) {
12ca818f 2255 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue);
853b8397
LP
2256 continue;
2257 }
2258
2259 x = strv_env_set(*env, n);
2260 if (!x)
2261 return log_oom();
2262
2263 strv_free(*env);
2264 *env = x;
2265 }
b2fadec6 2266 if (!isempty(state))
12ca818f 2267 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
ddb26e18 2268
8c7be95e 2269 return 0;
ddb26e18
LP
2270}
2271
b4c14404
FB
2272int config_parse_pass_environ(const char *unit,
2273 const char *filename,
2274 unsigned line,
2275 const char *section,
2276 unsigned section_line,
2277 const char *lvalue,
2278 int ltype,
2279 const char *rvalue,
2280 void *data,
2281 void *userdata) {
2282
2283 const char *whole_rvalue = rvalue;
2284 char*** passenv = data;
2285 _cleanup_strv_free_ char **n = NULL;
2286 size_t nlen = 0, nbufsize = 0;
2287 int r;
2288
2289 assert(filename);
2290 assert(lvalue);
2291 assert(rvalue);
2292 assert(data);
2293
2294 if (isempty(rvalue)) {
2295 /* Empty assignment resets the list */
2296 *passenv = strv_free(*passenv);
2297 return 0;
2298 }
2299
2300 for (;;) {
2301 _cleanup_free_ char *word = NULL;
2302
2303 r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
2304 if (r == 0)
2305 break;
2306 if (r == -ENOMEM)
2307 return log_oom();
2308 if (r < 0) {
2309 log_syntax(unit, LOG_ERR, filename, line, r,
2310 "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
2311 break;
2312 }
2313
2314 if (!env_name_is_valid(word)) {
2315 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2316 "Invalid environment name for %s, ignoring: %s", lvalue, word);
2317 continue;
2318 }
2319
2320 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2321 return log_oom();
2322 n[nlen++] = word;
2323 n[nlen] = NULL;
2324 word = NULL;
2325 }
2326
2327 if (n) {
2328 r = strv_extend_strv(passenv, n, true);
2329 if (r < 0)
2330 return r;
2331 }
2332
2333 return 0;
2334}
2335
e8e581bf
ZJS
2336int config_parse_ip_tos(const char *unit,
2337 const char *filename,
2338 unsigned line,
2339 const char *section,
71a61510 2340 unsigned section_line,
e8e581bf
ZJS
2341 const char *lvalue,
2342 int ltype,
2343 const char *rvalue,
2344 void *data,
2345 void *userdata) {
4fd5948e
LP
2346
2347 int *ip_tos = data, x;
4fd5948e
LP
2348
2349 assert(filename);
2350 assert(lvalue);
2351 assert(rvalue);
2352 assert(data);
2353
f8b69d1d
MS
2354 x = ip_tos_from_string(rvalue);
2355 if (x < 0) {
12ca818f 2356 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
f8b69d1d
MS
2357 return 0;
2358 }
4fd5948e
LP
2359
2360 *ip_tos = x;
2361 return 0;
2362}
2363
59fccdc5
LP
2364int config_parse_unit_condition_path(
2365 const char *unit,
2366 const char *filename,
2367 unsigned line,
2368 const char *section,
2369 unsigned section_line,
2370 const char *lvalue,
2371 int ltype,
2372 const char *rvalue,
2373 void *data,
2374 void *userdata) {
52661efd 2375
2fbe635a 2376 _cleanup_free_ char *p = NULL;
59fccdc5
LP
2377 Condition **list = data, *c;
2378 ConditionType t = ltype;
2379 bool trigger, negate;
2380 Unit *u = userdata;
19f6d710 2381 int r;
52661efd
LP
2382
2383 assert(filename);
2384 assert(lvalue);
2385 assert(rvalue);
2386 assert(data);
2387
74051b9b
LP
2388 if (isempty(rvalue)) {
2389 /* Empty assignment resets the list */
447021aa 2390 *list = condition_free_list(*list);
74051b9b
LP
2391 return 0;
2392 }
2393
ab7f148f
LP
2394 trigger = rvalue[0] == '|';
2395 if (trigger)
267632f0
LP
2396 rvalue++;
2397
ab7f148f
LP
2398 negate = rvalue[0] == '!';
2399 if (negate)
52661efd
LP
2400 rvalue++;
2401
19f6d710 2402 r = unit_full_printf(u, rvalue, &p);
59fccdc5 2403 if (r < 0) {
12ca818f 2404 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
59fccdc5 2405 return 0;
19f6d710 2406 }
095b2d7a
AK
2407
2408 if (!path_is_absolute(p)) {
12ca818f 2409 log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
52661efd
LP
2410 return 0;
2411 }
2412
59fccdc5 2413 c = condition_new(t, p, trigger, negate);
ab7f148f 2414 if (!c)
74051b9b 2415 return log_oom();
52661efd 2416
59fccdc5 2417 LIST_PREPEND(conditions, *list, c);
52661efd
LP
2418 return 0;
2419}
2420
59fccdc5
LP
2421int config_parse_unit_condition_string(
2422 const char *unit,
2423 const char *filename,
2424 unsigned line,
2425 const char *section,
2426 unsigned section_line,
2427 const char *lvalue,
2428 int ltype,
2429 const char *rvalue,
2430 void *data,
2431 void *userdata) {
039655a4 2432
2fbe635a 2433 _cleanup_free_ char *s = NULL;
59fccdc5
LP
2434 Condition **list = data, *c;
2435 ConditionType t = ltype;
2436 bool trigger, negate;
2437 Unit *u = userdata;
19f6d710 2438 int r;
039655a4
LP
2439
2440 assert(filename);
2441 assert(lvalue);
2442 assert(rvalue);
2443 assert(data);
2444
74051b9b
LP
2445 if (isempty(rvalue)) {
2446 /* Empty assignment resets the list */
447021aa 2447 *list = condition_free_list(*list);
74051b9b
LP
2448 return 0;
2449 }
2450
c0d6e764
LP
2451 trigger = rvalue[0] == '|';
2452 if (trigger)
267632f0
LP
2453 rvalue++;
2454
c0d6e764
LP
2455 negate = rvalue[0] == '!';
2456 if (negate)
039655a4
LP
2457 rvalue++;
2458
19f6d710 2459 r = unit_full_printf(u, rvalue, &s);
59fccdc5 2460 if (r < 0) {
12ca818f 2461 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
59fccdc5 2462 return 0;
19f6d710 2463 }
095b2d7a 2464
59fccdc5 2465 c = condition_new(t, s, trigger, negate);
c0d6e764
LP
2466 if (!c)
2467 return log_oom();
039655a4 2468
59fccdc5 2469 LIST_PREPEND(conditions, *list, c);
039655a4
LP
2470 return 0;
2471}
2472
59fccdc5
LP
2473int config_parse_unit_condition_null(
2474 const char *unit,
2475 const char *filename,
2476 unsigned line,
2477 const char *section,
2478 unsigned section_line,
2479 const char *lvalue,
2480 int ltype,
2481 const char *rvalue,
2482 void *data,
2483 void *userdata) {
d257ddef 2484
59fccdc5 2485 Condition **list = data, *c;
267632f0 2486 bool trigger, negate;
d257ddef
LP
2487 int b;
2488
2489 assert(filename);
2490 assert(lvalue);
2491 assert(rvalue);
2492 assert(data);
2493
74051b9b
LP
2494 if (isempty(rvalue)) {
2495 /* Empty assignment resets the list */
447021aa 2496 *list = condition_free_list(*list);
74051b9b
LP
2497 return 0;
2498 }
2499
2500 trigger = rvalue[0] == '|';
2501 if (trigger)
267632f0
LP
2502 rvalue++;
2503
74051b9b
LP
2504 negate = rvalue[0] == '!';
2505 if (negate)
d257ddef
LP
2506 rvalue++;
2507
74051b9b
LP
2508 b = parse_boolean(rvalue);
2509 if (b < 0) {
12ca818f 2510 log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
d257ddef
LP
2511 return 0;
2512 }
2513
2514 if (!b)
2515 negate = !negate;
2516
74051b9b
LP
2517 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2518 if (!c)
2519 return log_oom();
d257ddef 2520
59fccdc5 2521 LIST_PREPEND(conditions, *list, c);
d257ddef
LP
2522 return 0;
2523}
2524
f975e971 2525DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
bf500566 2526DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
c952c6ec 2527
a57f7e2c
LP
2528int config_parse_unit_requires_mounts_for(
2529 const char *unit,
2530 const char *filename,
2531 unsigned line,
2532 const char *section,
71a61510 2533 unsigned section_line,
a57f7e2c
LP
2534 const char *lvalue,
2535 int ltype,
2536 const char *rvalue,
2537 void *data,
2538 void *userdata) {
7c8fa05c
LP
2539
2540 Unit *u = userdata;
a2a5291b 2541 const char *word, *state;
a57f7e2c 2542 size_t l;
7c8fa05c
LP
2543
2544 assert(filename);
2545 assert(lvalue);
2546 assert(rvalue);
2547 assert(data);
2548
a2a5291b 2549 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
8a7935a2 2550 int r;
a57f7e2c
LP
2551 _cleanup_free_ char *n;
2552
a2a5291b 2553 n = strndup(word, l);
a57f7e2c
LP
2554 if (!n)
2555 return log_oom();
7c8fa05c 2556
a57f7e2c 2557 if (!utf8_is_valid(n)) {
0e05ee04 2558 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
a57f7e2c
LP
2559 continue;
2560 }
7c8fa05c 2561
a57f7e2c
LP
2562 r = unit_require_mounts_for(u, n);
2563 if (r < 0) {
12ca818f 2564 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue);
a57f7e2c
LP
2565 continue;
2566 }
2567 }
b2fadec6 2568 if (!isempty(state))
12ca818f 2569 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
7c8fa05c 2570
8a7935a2 2571 return 0;
7c8fa05c 2572}
9e372868 2573
e8e581bf
ZJS
2574int config_parse_documentation(const char *unit,
2575 const char *filename,
2576 unsigned line,
2577 const char *section,
71a61510 2578 unsigned section_line,
e8e581bf
ZJS
2579 const char *lvalue,
2580 int ltype,
2581 const char *rvalue,
2582 void *data,
2583 void *userdata) {
49dbfa7b
LP
2584
2585 Unit *u = userdata;
2586 int r;
2587 char **a, **b;
2588
2589 assert(filename);
2590 assert(lvalue);
2591 assert(rvalue);
2592 assert(u);
2593
74051b9b
LP
2594 if (isempty(rvalue)) {
2595 /* Empty assignment resets the list */
6796073e 2596 u->documentation = strv_free(u->documentation);
74051b9b
LP
2597 return 0;
2598 }
2599
71a61510 2600 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 2601 rvalue, data, userdata);
49dbfa7b
LP
2602 if (r < 0)
2603 return r;
2604
2605 for (a = b = u->documentation; a && *a; a++) {
2606
a2e03378 2607 if (documentation_url_is_valid(*a))
49dbfa7b
LP
2608 *(b++) = *a;
2609 else {
12ca818f 2610 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
49dbfa7b
LP
2611 free(*a);
2612 }
2613 }
f6d2d421
ZJS
2614 if (b)
2615 *b = NULL;
49dbfa7b
LP
2616
2617 return r;
2618}
2619
c0467cf3 2620#ifdef HAVE_SECCOMP
201c1cc2
TM
2621static int syscall_filter_parse_one(
2622 const char *unit,
2623 const char *filename,
2624 unsigned line,
2625 ExecContext *c,
2626 bool invert,
2627 const char *t,
2628 bool warn) {
2629 int r;
2630
2631 if (*t == '@') {
2632 const SystemCallFilterSet *set;
2633
2634 for (set = syscall_filter_sets; set->set_name; set++)
2635 if (streq(set->set_name, t)) {
2636 const char *sys;
2637
2638 NULSTR_FOREACH(sys, set->value) {
2639 r = syscall_filter_parse_one(unit, filename, line, c, invert, sys, false);
2640 if (r < 0)
2641 return r;
2642 }
2643 break;
2644 }
2645 } else {
2646 int id;
2647
2648 id = seccomp_syscall_resolve_name(t);
391b81cd 2649 if (id == __NR_SCMP_ERROR) {
201c1cc2
TM
2650 if (warn)
2651 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
2652 return 0;
2653 }
2654
2655 /* If we previously wanted to forbid a syscall and now
2656 * we want to allow it, then remove it from the list
2657 */
2658 if (!invert == c->syscall_whitelist) {
2659 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2660 if (r == 0)
2661 return 0;
2662 if (r < 0)
2663 return log_oom();
2664 } else
2665 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2666 }
2667 return 0;
2668}
2669
17df7223
LP
2670int config_parse_syscall_filter(
2671 const char *unit,
2672 const char *filename,
2673 unsigned line,
2674 const char *section,
2675 unsigned section_line,
2676 const char *lvalue,
2677 int ltype,
2678 const char *rvalue,
2679 void *data,
2680 void *userdata) {
2681
8351ceae
LP
2682 ExecContext *c = data;
2683 Unit *u = userdata;
b5fb3789 2684 bool invert = false;
a2a5291b 2685 const char *word, *state;
8351ceae 2686 size_t l;
17df7223 2687 int r;
8351ceae
LP
2688
2689 assert(filename);
2690 assert(lvalue);
2691 assert(rvalue);
2692 assert(u);
2693
74051b9b
LP
2694 if (isempty(rvalue)) {
2695 /* Empty assignment resets the list */
525d3cc7 2696 c->syscall_filter = set_free(c->syscall_filter);
17df7223 2697 c->syscall_whitelist = false;
74051b9b
LP
2698 return 0;
2699 }
2700
8351ceae
LP
2701 if (rvalue[0] == '~') {
2702 invert = true;
2703 rvalue++;
2704 }
2705
17df7223 2706 if (!c->syscall_filter) {
d5099efc 2707 c->syscall_filter = set_new(NULL);
17df7223
LP
2708 if (!c->syscall_filter)
2709 return log_oom();
2710
c0467cf3 2711 if (invert)
17df7223
LP
2712 /* Allow everything but the ones listed */
2713 c->syscall_whitelist = false;
c0467cf3 2714 else {
17df7223
LP
2715 /* Allow nothing but the ones listed */
2716 c->syscall_whitelist = true;
8351ceae 2717
17df7223 2718 /* Accept default syscalls if we are on a whitelist */
201c1cc2
TM
2719 r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false);
2720 if (r < 0)
2721 return r;
c0467cf3 2722 }
8351ceae
LP
2723 }
2724
a2a5291b 2725 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
7fd1b19b 2726 _cleanup_free_ char *t = NULL;
8351ceae 2727
a2a5291b 2728 t = strndup(word, l);
8351ceae 2729 if (!t)
74051b9b 2730 return log_oom();
8351ceae 2731
201c1cc2
TM
2732 r = syscall_filter_parse_one(unit, filename, line, c, invert, t, true);
2733 if (r < 0)
2734 return r;
c0467cf3 2735 }
b2fadec6 2736 if (!isempty(state))
12ca818f 2737 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
c0467cf3 2738
760b9d7c
LP
2739 /* Turn on NNP, but only if it wasn't configured explicitly
2740 * before, and only if we are in user mode. */
463d0d15 2741 if (!c->no_new_privileges_set && MANAGER_IS_USER(u->manager))
760b9d7c 2742 c->no_new_privileges = true;
17df7223
LP
2743
2744 return 0;
2745}
2746
57183d11
LP
2747int config_parse_syscall_archs(
2748 const char *unit,
2749 const char *filename,
2750 unsigned line,
2751 const char *section,
2752 unsigned section_line,
2753 const char *lvalue,
2754 int ltype,
2755 const char *rvalue,
2756 void *data,
2757 void *userdata) {
2758
d3b1c508 2759 Set **archs = data;
a2a5291b 2760 const char *word, *state;
57183d11
LP
2761 size_t l;
2762 int r;
2763
2764 if (isempty(rvalue)) {
525d3cc7 2765 *archs = set_free(*archs);
57183d11
LP
2766 return 0;
2767 }
2768
d5099efc 2769 r = set_ensure_allocated(archs, NULL);
57183d11
LP
2770 if (r < 0)
2771 return log_oom();
2772
a2a5291b 2773 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
57183d11
LP
2774 _cleanup_free_ char *t = NULL;
2775 uint32_t a;
2776
a2a5291b 2777 t = strndup(word, l);
57183d11
LP
2778 if (!t)
2779 return log_oom();
2780
2781 r = seccomp_arch_from_string(t, &a);
2782 if (r < 0) {
12ca818f 2783 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
57183d11
LP
2784 continue;
2785 }
2786
d3b1c508 2787 r = set_put(*archs, UINT32_TO_PTR(a + 1));
756c09e6 2788 if (r == 0)
57183d11
LP
2789 continue;
2790 if (r < 0)
2791 return log_oom();
2792 }
b2fadec6 2793 if (!isempty(state))
12ca818f 2794 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
57183d11
LP
2795
2796 return 0;
2797}
2798
17df7223
LP
2799int config_parse_syscall_errno(
2800 const char *unit,
2801 const char *filename,
2802 unsigned line,
2803 const char *section,
2804 unsigned section_line,
2805 const char *lvalue,
2806 int ltype,
2807 const char *rvalue,
2808 void *data,
2809 void *userdata) {
2810
2811 ExecContext *c = data;
2812 int e;
2813
2814 assert(filename);
2815 assert(lvalue);
2816 assert(rvalue);
2817
2818 if (isempty(rvalue)) {
2819 /* Empty assignment resets to KILL */
2820 c->syscall_errno = 0;
2821 return 0;
8351ceae
LP
2822 }
2823
17df7223
LP
2824 e = errno_from_name(rvalue);
2825 if (e < 0) {
12ca818f 2826 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
17df7223
LP
2827 return 0;
2828 }
8351ceae 2829
17df7223 2830 c->syscall_errno = e;
8351ceae
LP
2831 return 0;
2832}
4298d0b5
LP
2833
2834int config_parse_address_families(
2835 const char *unit,
2836 const char *filename,
2837 unsigned line,
2838 const char *section,
2839 unsigned section_line,
2840 const char *lvalue,
2841 int ltype,
2842 const char *rvalue,
2843 void *data,
2844 void *userdata) {
2845
2846 ExecContext *c = data;
4298d0b5 2847 bool invert = false;
a2a5291b 2848 const char *word, *state;
4298d0b5
LP
2849 size_t l;
2850 int r;
2851
2852 assert(filename);
2853 assert(lvalue);
2854 assert(rvalue);
4298d0b5
LP
2855
2856 if (isempty(rvalue)) {
2857 /* Empty assignment resets the list */
525d3cc7 2858 c->address_families = set_free(c->address_families);
4298d0b5
LP
2859 c->address_families_whitelist = false;
2860 return 0;
2861 }
2862
2863 if (rvalue[0] == '~') {
2864 invert = true;
2865 rvalue++;
2866 }
2867
2868 if (!c->address_families) {
d5099efc 2869 c->address_families = set_new(NULL);
4298d0b5
LP
2870 if (!c->address_families)
2871 return log_oom();
2872
2873 c->address_families_whitelist = !invert;
2874 }
2875
a2a5291b 2876 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
4298d0b5
LP
2877 _cleanup_free_ char *t = NULL;
2878 int af;
2879
a2a5291b 2880 t = strndup(word, l);
4298d0b5
LP
2881 if (!t)
2882 return log_oom();
2883
2884 af = af_from_name(t);
2885 if (af <= 0) {
12ca818f 2886 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t);
4298d0b5
LP
2887 continue;
2888 }
2889
2890 /* If we previously wanted to forbid an address family and now
2891 * we want to allow it, then remove it from the list
2892 */
2893 if (!invert == c->address_families_whitelist) {
2894 r = set_put(c->address_families, INT_TO_PTR(af));
756c09e6 2895 if (r == 0)
4298d0b5
LP
2896 continue;
2897 if (r < 0)
2898 return log_oom();
2899 } else
2900 set_remove(c->address_families, INT_TO_PTR(af));
2901 }
b2fadec6 2902 if (!isempty(state))
12ca818f 2903 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
4298d0b5
LP
2904
2905 return 0;
2906}
c0467cf3 2907#endif
8351ceae 2908
a016b922
LP
2909int config_parse_unit_slice(
2910 const char *unit,
2911 const char *filename,
2912 unsigned line,
2913 const char *section,
71a61510 2914 unsigned section_line,
a016b922
LP
2915 const char *lvalue,
2916 int ltype,
2917 const char *rvalue,
2918 void *data,
2919 void *userdata) {
2920
2921 _cleanup_free_ char *k = NULL;
d79200e2 2922 Unit *u = userdata, *slice = NULL;
a016b922
LP
2923 int r;
2924
2925 assert(filename);
2926 assert(lvalue);
2927 assert(rvalue);
2928 assert(u);
2929
19f6d710 2930 r = unit_name_printf(u, rvalue, &k);
d79200e2
LP
2931 if (r < 0) {
2932 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2933 return 0;
19f6d710 2934 }
a016b922 2935
19f6d710 2936 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
a016b922 2937 if (r < 0) {
d79200e2 2938 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
a016b922
LP
2939 return 0;
2940 }
2941
d79200e2
LP
2942 r = unit_set_slice(u, slice);
2943 if (r < 0) {
2944 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
a016b922
LP
2945 return 0;
2946 }
2947
a016b922
LP
2948 return 0;
2949}
2950
4ad49000
LP
2951DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2952
66ebf6c0
TH
2953int config_parse_cpu_weight(
2954 const char *unit,
2955 const char *filename,
2956 unsigned line,
2957 const char *section,
2958 unsigned section_line,
2959 const char *lvalue,
2960 int ltype,
2961 const char *rvalue,
2962 void *data,
2963 void *userdata) {
2964
2965 uint64_t *weight = data;
2966 int r;
2967
2968 assert(filename);
2969 assert(lvalue);
2970 assert(rvalue);
2971
2972 r = cg_weight_parse(rvalue, weight);
2973 if (r < 0) {
2974 log_syntax(unit, LOG_ERR, filename, line, r, "CPU weight '%s' invalid. Ignoring.", rvalue);
2975 return 0;
2976 }
2977
2978 return 0;
2979}
2980
4ad49000
LP
2981int config_parse_cpu_shares(
2982 const char *unit,
2983 const char *filename,
2984 unsigned line,
2985 const char *section,
71a61510 2986 unsigned section_line,
4ad49000
LP
2987 const char *lvalue,
2988 int ltype,
2989 const char *rvalue,
2990 void *data,
2991 void *userdata) {
2992
d53d9474 2993 uint64_t *shares = data;
95ae05c0
WC
2994 int r;
2995
2996 assert(filename);
2997 assert(lvalue);
2998 assert(rvalue);
2999
d53d9474
LP
3000 r = cg_cpu_shares_parse(rvalue, shares);
3001 if (r < 0) {
3002 log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
3003 return 0;
3004 }
3005
4ad49000
LP
3006 return 0;
3007}
3008
b2f8b02e
LP
3009int config_parse_cpu_quota(
3010 const char *unit,
3011 const char *filename,
3012 unsigned line,
3013 const char *section,
3014 unsigned section_line,
3015 const char *lvalue,
3016 int ltype,
3017 const char *rvalue,
3018 void *data,
3019 void *userdata) {
3020
3021 CGroupContext *c = data;
9184ca48 3022 int r;
b2f8b02e
LP
3023
3024 assert(filename);
3025 assert(lvalue);
3026 assert(rvalue);
3027
3028 if (isempty(rvalue)) {
3a43da28 3029 c->cpu_quota_per_sec_usec = USEC_INFINITY;
b2f8b02e
LP
3030 return 0;
3031 }
3032
5124866d 3033 r = parse_percent_unbounded(rvalue);
9184ca48
LP
3034 if (r <= 0) {
3035 log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
9a054909 3036 return 0;
b2f8b02e
LP
3037 }
3038
9184ca48 3039 c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
b2f8b02e
LP
3040 return 0;
3041}
3042
4ad49000
LP
3043int config_parse_memory_limit(
3044 const char *unit,
3045 const char *filename,
3046 unsigned line,
3047 const char *section,
71a61510 3048 unsigned section_line,
4ad49000
LP
3049 const char *lvalue,
3050 int ltype,
3051 const char *rvalue,
3052 void *data,
3053 void *userdata) {
3054
3055 CGroupContext *c = data;
da4d897e 3056 uint64_t bytes = CGROUP_LIMIT_MAX;
4ad49000
LP
3057 int r;
3058
e57c9ce1 3059 if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
875ae566
LP
3060
3061 r = parse_percent(rvalue);
3062 if (r < 0) {
3063 r = parse_size(rvalue, 1024, &bytes);
3064 if (r < 0) {
3065 log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
3066 return 0;
3067 }
3068 } else
d8cf2ac7 3069 bytes = physical_memory_scale(r, 100U);
875ae566 3070
b3785cd5
LP
3071 if (bytes <= 0 || bytes >= UINT64_MAX) {
3072 log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
da4d897e
TH
3073 return 0;
3074 }
4ad49000
LP
3075 }
3076
da4d897e
TH
3077 if (streq(lvalue, "MemoryLow"))
3078 c->memory_low = bytes;
3079 else if (streq(lvalue, "MemoryHigh"))
3080 c->memory_high = bytes;
3081 else if (streq(lvalue, "MemoryMax"))
3082 c->memory_max = bytes;
96e131ea
WC
3083 else if (streq(lvalue, "MemorySwapMax"))
3084 c->memory_swap_max = bytes;
3085 else if (streq(lvalue, "MemoryLimit"))
da4d897e 3086 c->memory_limit = bytes;
96e131ea
WC
3087 else
3088 return -EINVAL;
4ad49000 3089
4ad49000
LP
3090 return 0;
3091}
3092
03a7b521
LP
3093int config_parse_tasks_max(
3094 const char *unit,
3095 const char *filename,
3096 unsigned line,
3097 const char *section,
3098 unsigned section_line,
3099 const char *lvalue,
3100 int ltype,
3101 const char *rvalue,
3102 void *data,
3103 void *userdata) {
3104
f5058264
TH
3105 uint64_t *tasks_max = data, v;
3106 Unit *u = userdata;
03a7b521
LP
3107 int r;
3108
f5058264
TH
3109 if (isempty(rvalue)) {
3110 *tasks_max = u->manager->default_tasks_max;
3111 return 0;
3112 }
3113
3114 if (streq(rvalue, "infinity")) {
3115 *tasks_max = CGROUP_LIMIT_MAX;
03a7b521
LP
3116 return 0;
3117 }
3118
83f8e808
LP
3119 r = parse_percent(rvalue);
3120 if (r < 0) {
f5058264 3121 r = safe_atou64(rvalue, &v);
83f8e808
LP
3122 if (r < 0) {
3123 log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
3124 return 0;
3125 }
3126 } else
f5058264 3127 v = system_tasks_max_scale(r, 100U);
83f8e808 3128
f5058264 3129 if (v <= 0 || v >= UINT64_MAX) {
83f8e808 3130 log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
03a7b521
LP
3131 return 0;
3132 }
3133
f5058264 3134 *tasks_max = v;
03a7b521
LP
3135 return 0;
3136}
3137
4ad49000
LP
3138int config_parse_device_allow(
3139 const char *unit,
3140 const char *filename,
3141 unsigned line,
3142 const char *section,
71a61510 3143 unsigned section_line,
4ad49000
LP
3144 const char *lvalue,
3145 int ltype,
3146 const char *rvalue,
3147 void *data,
3148 void *userdata) {
3149
1116e14c 3150 _cleanup_free_ char *path = NULL, *t = NULL;
4ad49000
LP
3151 CGroupContext *c = data;
3152 CGroupDeviceAllow *a;
1116e14c 3153 const char *m = NULL;
4ad49000 3154 size_t n;
1116e14c 3155 int r;
4ad49000
LP
3156
3157 if (isempty(rvalue)) {
3158 while (c->device_allow)
3159 cgroup_context_free_device_allow(c, c->device_allow);
3160
3161 return 0;
3162 }
3163
1116e14c
NBS
3164 r = unit_full_printf(userdata, rvalue, &t);
3165 if(r < 0) {
3166 log_syntax(unit, LOG_WARNING, filename, line, r,
3167 "Failed to resolve specifiers in %s, ignoring: %m",
3168 rvalue);
3169 }
3170
3171 n = strcspn(t, WHITESPACE);
3172
3173 path = strndup(t, n);
4ad49000
LP
3174 if (!path)
3175 return log_oom();
3176
3ccb8862 3177 if (!is_deviceallow_pattern(path)) {
12ca818f 3178 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
3179 return 0;
3180 }
3181
1116e14c 3182 m = t + n + strspn(t + n, WHITESPACE);
4ad49000
LP
3183 if (isempty(m))
3184 m = "rwm";
3185
3186 if (!in_charset(m, "rwm")) {
12ca818f 3187 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
4ad49000
LP
3188 return 0;
3189 }
3190
3191 a = new0(CGroupDeviceAllow, 1);
3192 if (!a)
3193 return log_oom();
3194
3195 a->path = path;
3196 path = NULL;
3197 a->r = !!strchr(m, 'r');
3198 a->w = !!strchr(m, 'w');
3199 a->m = !!strchr(m, 'm');
3200
71fda00f 3201 LIST_PREPEND(device_allow, c->device_allow, a);
4ad49000
LP
3202 return 0;
3203}
3204
13c31542
TH
3205int config_parse_io_weight(
3206 const char *unit,
3207 const char *filename,
3208 unsigned line,
3209 const char *section,
3210 unsigned section_line,
3211 const char *lvalue,
3212 int ltype,
3213 const char *rvalue,
3214 void *data,
3215 void *userdata) {
3216
3217 uint64_t *weight = data;
3218 int r;
3219
3220 assert(filename);
3221 assert(lvalue);
3222 assert(rvalue);
3223
3224 r = cg_weight_parse(rvalue, weight);
3225 if (r < 0) {
3226 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
3227 return 0;
3228 }
3229
3230 return 0;
3231}
3232
3233int config_parse_io_device_weight(
3234 const char *unit,
3235 const char *filename,
3236 unsigned line,
3237 const char *section,
3238 unsigned section_line,
3239 const char *lvalue,
3240 int ltype,
3241 const char *rvalue,
3242 void *data,
3243 void *userdata) {
3244
3245 _cleanup_free_ char *path = NULL;
3246 CGroupIODeviceWeight *w;
3247 CGroupContext *c = data;
3248 const char *weight;
3249 uint64_t u;
3250 size_t n;
3251 int r;
3252
3253 assert(filename);
3254 assert(lvalue);
3255 assert(rvalue);
3256
3257 if (isempty(rvalue)) {
3258 while (c->io_device_weights)
3259 cgroup_context_free_io_device_weight(c, c->io_device_weights);
3260
3261 return 0;
3262 }
3263
3264 n = strcspn(rvalue, WHITESPACE);
3265 weight = rvalue + n;
3266 weight += strspn(weight, WHITESPACE);
3267
3268 if (isempty(weight)) {
3269 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3270 return 0;
3271 }
3272
3273 path = strndup(rvalue, n);
3274 if (!path)
3275 return log_oom();
3276
3277 if (!path_startswith(path, "/dev")) {
3278 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3279 return 0;
3280 }
3281
3282 r = cg_weight_parse(weight, &u);
3283 if (r < 0) {
3284 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
3285 return 0;
3286 }
3287
3288 assert(u != CGROUP_WEIGHT_INVALID);
3289
3290 w = new0(CGroupIODeviceWeight, 1);
3291 if (!w)
3292 return log_oom();
3293
3294 w->path = path;
3295 path = NULL;
3296
3297 w->weight = u;
3298
3299 LIST_PREPEND(device_weights, c->io_device_weights, w);
3300 return 0;
3301}
3302
3303int config_parse_io_limit(
3304 const char *unit,
3305 const char *filename,
3306 unsigned line,
3307 const char *section,
3308 unsigned section_line,
3309 const char *lvalue,
3310 int ltype,
3311 const char *rvalue,
3312 void *data,
3313 void *userdata) {
3314
3315 _cleanup_free_ char *path = NULL;
3316 CGroupIODeviceLimit *l = NULL, *t;
3317 CGroupContext *c = data;
9be57249 3318 CGroupIOLimitType type;
13c31542
TH
3319 const char *limit;
3320 uint64_t num;
13c31542
TH
3321 size_t n;
3322 int r;
3323
3324 assert(filename);
3325 assert(lvalue);
3326 assert(rvalue);
3327
9be57249
TH
3328 type = cgroup_io_limit_type_from_string(lvalue);
3329 assert(type >= 0);
13c31542
TH
3330
3331 if (isempty(rvalue)) {
3332 LIST_FOREACH(device_limits, l, c->io_device_limits)
9be57249 3333 l->limits[type] = cgroup_io_limit_defaults[type];
13c31542
TH
3334 return 0;
3335 }
3336
3337 n = strcspn(rvalue, WHITESPACE);
3338 limit = rvalue + n;
3339 limit += strspn(limit, WHITESPACE);
3340
3341 if (!*limit) {
3342 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3343 return 0;
3344 }
3345
3346 path = strndup(rvalue, n);
3347 if (!path)
3348 return log_oom();
3349
3350 if (!path_startswith(path, "/dev")) {
3351 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3352 return 0;
3353 }
3354
e57c9ce1 3355 if (streq("infinity", limit)) {
13c31542
TH
3356 num = CGROUP_LIMIT_MAX;
3357 } else {
3358 r = parse_size(limit, 1000, &num);
3359 if (r < 0 || num <= 0) {
3360 log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
3361 return 0;
3362 }
3363 }
3364
3365 LIST_FOREACH(device_limits, t, c->io_device_limits) {
3366 if (path_equal(path, t->path)) {
3367 l = t;
3368 break;
3369 }
3370 }
3371
3372 if (!l) {
9be57249
TH
3373 CGroupIOLimitType ttype;
3374
13c31542
TH
3375 l = new0(CGroupIODeviceLimit, 1);
3376 if (!l)
3377 return log_oom();
3378
3379 l->path = path;
3380 path = NULL;
9be57249
TH
3381 for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
3382 l->limits[ttype] = cgroup_io_limit_defaults[ttype];
13c31542
TH
3383
3384 LIST_PREPEND(device_limits, c->io_device_limits, l);
3385 }
3386
9be57249 3387 l->limits[type] = num;
13c31542
TH
3388
3389 return 0;
3390}
3391
4ad49000
LP
3392int config_parse_blockio_weight(
3393 const char *unit,
3394 const char *filename,
3395 unsigned line,
3396 const char *section,
71a61510 3397 unsigned section_line,
4ad49000
LP
3398 const char *lvalue,
3399 int ltype,
3400 const char *rvalue,
3401 void *data,
3402 void *userdata) {
3403
d53d9474 3404 uint64_t *weight = data;
95ae05c0
WC
3405 int r;
3406
3407 assert(filename);
3408 assert(lvalue);
3409 assert(rvalue);
3410
d53d9474
LP
3411 r = cg_blkio_weight_parse(rvalue, weight);
3412 if (r < 0) {
3413 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
3414 return 0;
3415 }
3416
8e7076ca
LP
3417 return 0;
3418}
3419
3420int config_parse_blockio_device_weight(
3421 const char *unit,
3422 const char *filename,
3423 unsigned line,
3424 const char *section,
71a61510 3425 unsigned section_line,
8e7076ca
LP
3426 const char *lvalue,
3427 int ltype,
3428 const char *rvalue,
3429 void *data,
3430 void *userdata) {
3431
4ad49000 3432 _cleanup_free_ char *path = NULL;
8e7076ca 3433 CGroupBlockIODeviceWeight *w;
4ad49000 3434 CGroupContext *c = data;
4ad49000 3435 const char *weight;
d53d9474 3436 uint64_t u;
4ad49000
LP
3437 size_t n;
3438 int r;
3439
3440 assert(filename);
3441 assert(lvalue);
3442 assert(rvalue);
3443
3444 if (isempty(rvalue)) {
4ad49000
LP
3445 while (c->blockio_device_weights)
3446 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3447
3448 return 0;
3449 }
3450
3451 n = strcspn(rvalue, WHITESPACE);
3452 weight = rvalue + n;
d53d9474
LP
3453 weight += strspn(weight, WHITESPACE);
3454
3455 if (isempty(weight)) {
12ca818f 3456 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
8e7076ca
LP
3457 return 0;
3458 }
4ad49000 3459
8e7076ca
LP
3460 path = strndup(rvalue, n);
3461 if (!path)
3462 return log_oom();
4ad49000 3463
8e7076ca 3464 if (!path_startswith(path, "/dev")) {
12ca818f 3465 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
8e7076ca
LP
3466 return 0;
3467 }
4ad49000 3468
d53d9474
LP
3469 r = cg_blkio_weight_parse(weight, &u);
3470 if (r < 0) {
3471 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
4ad49000
LP
3472 return 0;
3473 }
3474
d53d9474
LP
3475 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3476
8e7076ca
LP
3477 w = new0(CGroupBlockIODeviceWeight, 1);
3478 if (!w)
3479 return log_oom();
4ad49000 3480
8e7076ca
LP
3481 w->path = path;
3482 path = NULL;
4ad49000 3483
d53d9474 3484 w->weight = u;
4ad49000 3485
71fda00f 3486 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
3487 return 0;
3488}
3489
3490int config_parse_blockio_bandwidth(
3491 const char *unit,
3492 const char *filename,
3493 unsigned line,
3494 const char *section,
71a61510 3495 unsigned section_line,
4ad49000
LP
3496 const char *lvalue,
3497 int ltype,
3498 const char *rvalue,
3499 void *data,
3500 void *userdata) {
3501
3502 _cleanup_free_ char *path = NULL;
979d0311 3503 CGroupBlockIODeviceBandwidth *b = NULL, *t;
4ad49000
LP
3504 CGroupContext *c = data;
3505 const char *bandwidth;
59f448cf 3506 uint64_t bytes;
47c0980d 3507 bool read;
4ad49000
LP
3508 size_t n;
3509 int r;
3510
3511 assert(filename);
3512 assert(lvalue);
3513 assert(rvalue);
3514
47c0980d
G
3515 read = streq("BlockIOReadBandwidth", lvalue);
3516
4ad49000 3517 if (isempty(rvalue)) {
979d0311
TH
3518 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
3519 b->rbps = CGROUP_LIMIT_MAX;
3520 b->wbps = CGROUP_LIMIT_MAX;
3521 }
4ad49000
LP
3522 return 0;
3523 }
3524
3525 n = strcspn(rvalue, WHITESPACE);
3526 bandwidth = rvalue + n;
3527 bandwidth += strspn(bandwidth, WHITESPACE);
3528
3529 if (!*bandwidth) {
12ca818f 3530 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
4ad49000
LP
3531 return 0;
3532 }
3533
3534 path = strndup(rvalue, n);
3535 if (!path)
3536 return log_oom();
3537
3538 if (!path_startswith(path, "/dev")) {
12ca818f 3539 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
3540 return 0;
3541 }
3542
5556b5fe 3543 r = parse_size(bandwidth, 1000, &bytes);
4ad49000 3544 if (r < 0 || bytes <= 0) {
12ca818f 3545 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
3546 return 0;
3547 }
3548
979d0311
TH
3549 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
3550 if (path_equal(path, t->path)) {
3551 b = t;
3552 break;
3553 }
3554 }
4ad49000 3555
979d0311
TH
3556 if (!t) {
3557 b = new0(CGroupBlockIODeviceBandwidth, 1);
3558 if (!b)
3559 return log_oom();
3560
3561 b->path = path;
3562 path = NULL;
3563 b->rbps = CGROUP_LIMIT_MAX;
3564 b->wbps = CGROUP_LIMIT_MAX;
3565
3566 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3567 }
4ad49000 3568
979d0311
TH
3569 if (read)
3570 b->rbps = bytes;
3571 else
3572 b->wbps = bytes;
4ad49000
LP
3573
3574 return 0;
3575}
3576
d420282b
LP
3577DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3578
3579int config_parse_job_mode_isolate(
3580 const char *unit,
3581 const char *filename,
3582 unsigned line,
3583 const char *section,
3584 unsigned section_line,
3585 const char *lvalue,
3586 int ltype,
3587 const char *rvalue,
3588 void *data,
3589 void *userdata) {
3590
3591 JobMode *m = data;
3592 int r;
3593
3594 assert(filename);
3595 assert(lvalue);
3596 assert(rvalue);
3597
3598 r = parse_boolean(rvalue);
3599 if (r < 0) {
12ca818f 3600 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
d420282b
LP
3601 return 0;
3602 }
3603
3604 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3605 return 0;
3606}
3607
e66cf1a3
LP
3608int config_parse_runtime_directory(
3609 const char *unit,
3610 const char *filename,
3611 unsigned line,
3612 const char *section,
3613 unsigned section_line,
3614 const char *lvalue,
3615 int ltype,
3616 const char *rvalue,
3617 void *data,
3618 void *userdata) {
3619
a2a5291b 3620 char***rt = data;
9b5864d9 3621 Unit *u = userdata;
a2a5291b 3622 const char *word, *state;
e66cf1a3
LP
3623 size_t l;
3624 int r;
3625
3626 assert(filename);
3627 assert(lvalue);
3628 assert(rvalue);
3629 assert(data);
3630
3631 if (isempty(rvalue)) {
3632 /* Empty assignment resets the list */
6796073e 3633 *rt = strv_free(*rt);
e66cf1a3
LP
3634 return 0;
3635 }
3636
a2a5291b 3637 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
9b5864d9 3638 _cleanup_free_ char *t = NULL, *n = NULL;
e66cf1a3 3639
9b5864d9
MG
3640 t = strndup(word, l);
3641 if (!t)
e66cf1a3
LP
3642 return log_oom();
3643
9b5864d9
MG
3644 r = unit_name_printf(u, t, &n);
3645 if (r < 0) {
12ca818f 3646 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
9b5864d9
MG
3647 continue;
3648 }
3649
ae6c3cc0 3650 if (!filename_is_valid(n)) {
12ca818f 3651 log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
e66cf1a3
LP
3652 continue;
3653 }
3654
3655 r = strv_push(rt, n);
3656 if (r < 0)
3657 return log_oom();
3658
3659 n = NULL;
3660 }
b2fadec6 3661 if (!isempty(state))
12ca818f 3662 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
e66cf1a3
LP
3663
3664 return 0;
3665}
3666
3af00fb8
LP
3667int config_parse_set_status(
3668 const char *unit,
3669 const char *filename,
3670 unsigned line,
3671 const char *section,
3672 unsigned section_line,
3673 const char *lvalue,
3674 int ltype,
3675 const char *rvalue,
3676 void *data,
3677 void *userdata) {
3678
3af00fb8 3679 size_t l;
a2a5291b 3680 const char *word, *state;
3af00fb8
LP
3681 int r;
3682 ExitStatusSet *status_set = data;
3683
3684 assert(filename);
3685 assert(lvalue);
3686 assert(rvalue);
3687 assert(data);
3688
3e2d435b 3689 /* Empty assignment resets the list */
3af00fb8 3690 if (isempty(rvalue)) {
3e2d435b 3691 exit_status_set_free(status_set);
3af00fb8
LP
3692 return 0;
3693 }
3694
a2a5291b 3695 FOREACH_WORD(word, l, rvalue, state) {
3af00fb8
LP
3696 _cleanup_free_ char *temp;
3697 int val;
61593865 3698 Set **set;
3af00fb8 3699
a2a5291b 3700 temp = strndup(word, l);
3af00fb8
LP
3701 if (!temp)
3702 return log_oom();
3703
3704 r = safe_atoi(temp, &val);
3705 if (r < 0) {
3706 val = signal_from_string_try_harder(temp);
3707
1e2fd62d 3708 if (val <= 0) {
12ca818f 3709 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
61593865 3710 continue;
3af00fb8 3711 }
61593865 3712 set = &status_set->signal;
3af00fb8 3713 } else {
1e2fd62d 3714 if (val < 0 || val > 255) {
12ca818f 3715 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
1e2fd62d 3716 continue;
3af00fb8 3717 }
61593865 3718 set = &status_set->status;
3af00fb8 3719 }
1e2fd62d 3720
61593865 3721 r = set_ensure_allocated(set, NULL);
1e2fd62d
ZJS
3722 if (r < 0)
3723 return log_oom();
3724
61593865 3725 r = set_put(*set, INT_TO_PTR(val));
1e2fd62d 3726 if (r < 0) {
12ca818f 3727 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
1e2fd62d
ZJS
3728 return r;
3729 }
3af00fb8 3730 }
b2fadec6 3731 if (!isempty(state))
12ca818f 3732 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3af00fb8
LP
3733
3734 return 0;
3735}
3736
94828d2d
LP
3737int config_parse_namespace_path_strv(
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
a2a5291b 3749 char*** sv = data;
727f76d7
EV
3750 const char *prev;
3751 const char *cur;
94828d2d
LP
3752 int r;
3753
3754 assert(filename);
3755 assert(lvalue);
3756 assert(rvalue);
3757 assert(data);
3758
3759 if (isempty(rvalue)) {
3760 /* Empty assignment resets the list */
6796073e 3761 *sv = strv_free(*sv);
94828d2d
LP
3762 return 0;
3763 }
3764
727f76d7
EV
3765 prev = cur = rvalue;
3766 for (;;) {
3767 _cleanup_free_ char *word = NULL;
94828d2d
LP
3768 int offset;
3769
727f76d7 3770 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
0293a7a8
EV
3771 if (r == 0)
3772 break;
3773 if (r == -ENOMEM)
3774 return log_oom();
727f76d7 3775 if (r < 0) {
0293a7a8 3776 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
727f76d7
EV
3777 return 0;
3778 }
94828d2d 3779
727f76d7
EV
3780 if (!utf8_is_valid(word)) {
3781 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3782 prev = cur;
94828d2d
LP
3783 continue;
3784 }
3785
727f76d7
EV
3786 offset = word[0] == '-';
3787 if (!path_is_absolute(word + offset)) {
3788 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
3789 prev = cur;
94828d2d
LP
3790 continue;
3791 }
3792
727f76d7 3793 path_kill_slashes(word + offset);
94828d2d 3794
727f76d7 3795 r = strv_push(sv, word);
94828d2d
LP
3796 if (r < 0)
3797 return log_oom();
3798
727f76d7
EV
3799 prev = cur;
3800 word = NULL;
94828d2d
LP
3801 }
3802
3803 return 0;
3804}
3805
f1721625 3806int config_parse_no_new_privileges(
760b9d7c
LP
3807 const char* unit,
3808 const char *filename,
3809 unsigned line,
3810 const char *section,
3811 unsigned section_line,
3812 const char *lvalue,
3813 int ltype,
3814 const char *rvalue,
3815 void *data,
3816 void *userdata) {
3817
3818 ExecContext *c = data;
3819 int k;
3820
3821 assert(filename);
3822 assert(lvalue);
3823 assert(rvalue);
3824 assert(data);
3825
3826 k = parse_boolean(rvalue);
3827 if (k < 0) {
12ca818f 3828 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
760b9d7c
LP
3829 return 0;
3830 }
3831
3832 c->no_new_privileges = !!k;
3833 c->no_new_privileges_set = true;
3834
3835 return 0;
3836}
3837
1b8689f9 3838int config_parse_protect_home(
417116f2
LP
3839 const char* unit,
3840 const char *filename,
3841 unsigned line,
3842 const char *section,
3843 unsigned section_line,
3844 const char *lvalue,
3845 int ltype,
3846 const char *rvalue,
3847 void *data,
3848 void *userdata) {
3849
3850 ExecContext *c = data;
3851 int k;
3852
3853 assert(filename);
3854 assert(lvalue);
3855 assert(rvalue);
3856 assert(data);
3857
3858 /* Our enum shall be a superset of booleans, hence first try
61233823 3859 * to parse as boolean, and then as enum */
417116f2
LP
3860
3861 k = parse_boolean(rvalue);
3862 if (k > 0)
1b8689f9 3863 c->protect_home = PROTECT_HOME_YES;
417116f2 3864 else if (k == 0)
1b8689f9 3865 c->protect_home = PROTECT_HOME_NO;
417116f2 3866 else {
1b8689f9 3867 ProtectHome h;
417116f2 3868
1b8689f9 3869 h = protect_home_from_string(rvalue);
9ed794a3 3870 if (h < 0) {
12ca818f 3871 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
3872 return 0;
3873 }
3874
1b8689f9
LP
3875 c->protect_home = h;
3876 }
3877
3878 return 0;
3879}
3880
3881int config_parse_protect_system(
3882 const char* unit,
3883 const char *filename,
3884 unsigned line,
3885 const char *section,
3886 unsigned section_line,
3887 const char *lvalue,
3888 int ltype,
3889 const char *rvalue,
3890 void *data,
3891 void *userdata) {
3892
3893 ExecContext *c = data;
3894 int k;
3895
3896 assert(filename);
3897 assert(lvalue);
3898 assert(rvalue);
3899 assert(data);
3900
3901 /* Our enum shall be a superset of booleans, hence first try
61233823 3902 * to parse as boolean, and then as enum */
1b8689f9
LP
3903
3904 k = parse_boolean(rvalue);
3905 if (k > 0)
3906 c->protect_system = PROTECT_SYSTEM_YES;
3907 else if (k == 0)
3908 c->protect_system = PROTECT_SYSTEM_NO;
3909 else {
3910 ProtectSystem s;
3911
3912 s = protect_system_from_string(rvalue);
9ed794a3 3913 if (s < 0) {
12ca818f 3914 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
1b8689f9
LP
3915 return 0;
3916 }
3917
3918 c->protect_system = s;
417116f2
LP
3919 }
3920
3921 return 0;
3922}
3923
071830ff 3924#define FOLLOW_MAX 8
87f0e418 3925
9e2f7c11 3926static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
a837f088 3927 char *id = NULL;
0301abf4 3928 unsigned c = 0;
87f0e418
LP
3929 int fd, r;
3930 FILE *f;
87f0e418
LP
3931
3932 assert(filename);
3933 assert(*filename);
3934 assert(_f);
3935 assert(names);
3936
0301abf4
LP
3937 /* This will update the filename pointer if the loaded file is
3938 * reached by a symlink. The old string will be freed. */
87f0e418 3939
0301abf4 3940 for (;;) {
2c7108c4 3941 char *target, *name;
87f0e418 3942
0301abf4
LP
3943 if (c++ >= FOLLOW_MAX)
3944 return -ELOOP;
3945
b08d03ff
LP
3946 path_kill_slashes(*filename);
3947
87f0e418 3948 /* Add the file name we are currently looking at to
8f05424d
LP
3949 * the names of this unit, but only if it is a valid
3950 * unit name. */
2b6bf07d 3951 name = basename(*filename);
7410616c 3952 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
8f05424d 3953
15e11d81
LP
3954 id = set_get(names, name);
3955 if (!id) {
3956 id = strdup(name);
3957 if (!id)
8f05424d 3958 return -ENOMEM;
87f0e418 3959
ef42202a
ZJS
3960 r = set_consume(names, id);
3961 if (r < 0)
8f05424d 3962 return r;
87f0e418 3963 }
87f0e418
LP
3964 }
3965
0301abf4 3966 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
3967 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3968 if (fd >= 0)
87f0e418
LP
3969 break;
3970
0301abf4
LP
3971 if (errno != ELOOP)
3972 return -errno;
3973
87f0e418 3974 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
3975 r = readlink_and_make_absolute(*filename, &target);
3976 if (r < 0)
0301abf4 3977 return r;
87f0e418 3978
0301abf4 3979 free(*filename);
2c7108c4 3980 *filename = target;
87f0e418
LP
3981 }
3982
9946996c
LP
3983 f = fdopen(fd, "re");
3984 if (!f) {
03e334a1 3985 safe_close(fd);
d4ad27a1 3986 return -errno;
87f0e418
LP
3987 }
3988
3989 *_f = f;
9e2f7c11 3990 *_final = id;
a837f088 3991
0301abf4 3992 return 0;
87f0e418
LP
3993}
3994
23a177ef
LP
3995static int merge_by_names(Unit **u, Set *names, const char *id) {
3996 char *k;
3997 int r;
3998
3999 assert(u);
4000 assert(*u);
4001 assert(names);
4002
4003 /* Let's try to add in all symlink names we found */
4004 while ((k = set_steal_first(names))) {
4005
4006 /* First try to merge in the other name into our
4007 * unit */
9946996c
LP
4008 r = unit_merge_by_name(*u, k);
4009 if (r < 0) {
23a177ef
LP
4010 Unit *other;
4011
4012 /* Hmm, we couldn't merge the other unit into
4013 * ours? Then let's try it the other way
4014 * round */
4015
7aad67e7
MS
4016 /* If the symlink name we are looking at is unit template, then
4017 we must search for instance of this template */
9d3e3406 4018 if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
7aad67e7
MS
4019 _cleanup_free_ char *instance = NULL;
4020
4021 r = unit_name_replace_instance(k, (*u)->instance, &instance);
4022 if (r < 0)
4023 return r;
4024
4025 other = manager_get_unit((*u)->manager, instance);
4026 } else
4027 other = manager_get_unit((*u)->manager, k);
4028
23a177ef
LP
4029 free(k);
4030
9946996c
LP
4031 if (other) {
4032 r = unit_merge(other, *u);
4033 if (r >= 0) {
23a177ef
LP
4034 *u = other;
4035 return merge_by_names(u, names, NULL);
4036 }
9946996c 4037 }
23a177ef
LP
4038
4039 return r;
4040 }
4041
4042 if (id == k)
4043 unit_choose_id(*u, id);
4044
4045 free(k);
4046 }
4047
4048 return 0;
4049}
4050
e537352b 4051static int load_from_path(Unit *u, const char *path) {
e48614c4
ZJS
4052 _cleanup_set_free_free_ Set *symlink_names = NULL;
4053 _cleanup_fclose_ FILE *f = NULL;
4054 _cleanup_free_ char *filename = NULL;
4055 char *id = NULL;
23a177ef 4056 Unit *merged;
45fb0699 4057 struct stat st;
a837f088 4058 int r;
23a177ef
LP
4059
4060 assert(u);
e537352b 4061 assert(path);
3efd4195 4062
d5099efc 4063 symlink_names = set_new(&string_hash_ops);
f975e971 4064 if (!symlink_names)
87f0e418 4065 return -ENOMEM;
3efd4195 4066
036643a2
LP
4067 if (path_is_absolute(path)) {
4068
9946996c 4069 filename = strdup(path);
e48614c4
ZJS
4070 if (!filename)
4071 return -ENOMEM;
036643a2 4072
9946996c
LP
4073 r = open_follow(&filename, &f, symlink_names, &id);
4074 if (r < 0) {
97b11eed 4075 filename = mfree(filename);
036643a2 4076 if (r != -ENOENT)
e48614c4 4077 return r;
036643a2
LP
4078 }
4079
4080 } else {
4081 char **p;
4082
a3c4eb07 4083 STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
036643a2
LP
4084
4085 /* Instead of opening the path right away, we manually
4086 * follow all symlinks and add their name to our unit
4087 * name set while doing so */
9946996c 4088 filename = path_make_absolute(path, *p);
e48614c4
ZJS
4089 if (!filename)
4090 return -ENOMEM;
036643a2 4091
ac155bb8
MS
4092 if (u->manager->unit_path_cache &&
4093 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
4094 r = -ENOENT;
4095 else
4096 r = open_follow(&filename, &f, symlink_names, &id);
a837f088
LP
4097 if (r >= 0)
4098 break;
4099 filename = mfree(filename);
a1feacf7
ZJS
4100
4101 /* ENOENT means that the file is missing or is a dangling symlink.
4102 * ENOTDIR means that one of paths we expect to be is a directory
4103 * is not a directory, we should just ignore that.
4104 * EACCES means that the directory or file permissions are wrong.
4105 */
4106 if (r == -EACCES)
4107 log_debug_errno(r, "Cannot access \"%s\": %m", filename);
4108 else if (!IN_SET(r, -ENOENT, -ENOTDIR))
a837f088 4109 return r;
fe51822e 4110
a837f088
LP
4111 /* Empty the symlink names for the next run */
4112 set_clear_free(symlink_names);
036643a2
LP
4113 }
4114 }
034c6ed7 4115
e48614c4 4116 if (!filename)
8f05424d 4117 /* Hmm, no suitable file found? */
e48614c4 4118 return 0;
87f0e418 4119
8a993b61 4120 if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
a837f088
LP
4121 log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
4122 return -ELOOP;
4123 }
4124
23a177ef 4125 merged = u;
9946996c
LP
4126 r = merge_by_names(&merged, symlink_names, id);
4127 if (r < 0)
e48614c4 4128 return r;
87f0e418 4129
23a177ef 4130 if (merged != u) {
ac155bb8 4131 u->load_state = UNIT_MERGED;
e48614c4 4132 return 0;
034c6ed7
LP
4133 }
4134
e48614c4
ZJS
4135 if (fstat(fileno(f), &st) < 0)
4136 return -errno;
45fb0699 4137
3a8db9fe 4138 if (null_or_empty(&st)) {
ac155bb8 4139 u->load_state = UNIT_MASKED;
3a8db9fe
ZJS
4140 u->fragment_mtime = 0;
4141 } else {
c2756a68 4142 u->load_state = UNIT_LOADED;
3a8db9fe 4143 u->fragment_mtime = timespec_load(&st.st_mtim);
c2756a68 4144
00dc5d76 4145 /* Now, parse the file contents */
36f822c4
ZJS
4146 r = config_parse(u->id, filename, f,
4147 UNIT_VTABLE(u)->sections,
4148 config_item_perf_lookup, load_fragment_gperf_lookup,
4149 false, true, false, u);
f975e971 4150 if (r < 0)
e48614c4 4151 return r;
00dc5d76 4152 }
b08d03ff 4153
ac155bb8
MS
4154 free(u->fragment_path);
4155 u->fragment_path = filename;
0301abf4 4156 filename = NULL;
87f0e418 4157
1b64d026
LP
4158 if (u->source_path) {
4159 if (stat(u->source_path, &st) >= 0)
4160 u->source_mtime = timespec_load(&st.st_mtim);
4161 else
4162 u->source_mtime = 0;
4163 }
4164
e48614c4 4165 return 0;
0301abf4
LP
4166}
4167
e537352b 4168int unit_load_fragment(Unit *u) {
23a177ef 4169 int r;
294d81f1
LP
4170 Iterator i;
4171 const char *t;
0301abf4
LP
4172
4173 assert(u);
ac155bb8
MS
4174 assert(u->load_state == UNIT_STUB);
4175 assert(u->id);
23a177ef 4176
3f5e8115
LP
4177 if (u->transient) {
4178 u->load_state = UNIT_LOADED;
4179 return 0;
4180 }
4181
294d81f1
LP
4182 /* First, try to find the unit under its id. We always look
4183 * for unit files in the default directories, to make it easy
4184 * to override things by placing things in /etc/systemd/system */
9946996c
LP
4185 r = load_from_path(u, u->id);
4186 if (r < 0)
294d81f1
LP
4187 return r;
4188
4189 /* Try to find an alias we can load this with */
abc08d4d 4190 if (u->load_state == UNIT_STUB) {
ac155bb8 4191 SET_FOREACH(t, u->names, i) {
294d81f1 4192
ac155bb8 4193 if (t == u->id)
294d81f1
LP
4194 continue;
4195
9946996c
LP
4196 r = load_from_path(u, t);
4197 if (r < 0)
294d81f1
LP
4198 return r;
4199
ac155bb8 4200 if (u->load_state != UNIT_STUB)
294d81f1
LP
4201 break;
4202 }
abc08d4d 4203 }
23a177ef 4204
294d81f1 4205 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 4206 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 4207
9946996c
LP
4208 r = load_from_path(u, u->fragment_path);
4209 if (r < 0)
23a177ef 4210 return r;
0301abf4 4211
ece174c5 4212 if (u->load_state == UNIT_STUB)
6ccb1b44
LP
4213 /* Hmm, this didn't work? Then let's get rid
4214 * of the fragment path stored for us, so that
4215 * we don't point to an invalid location. */
a1e58e8e 4216 u->fragment_path = mfree(u->fragment_path);
6ccb1b44
LP
4217 }
4218
294d81f1 4219 /* Look for a template */
ac155bb8 4220 if (u->load_state == UNIT_STUB && u->instance) {
7410616c 4221 _cleanup_free_ char *k = NULL;
294d81f1 4222
7410616c
LP
4223 r = unit_name_template(u->id, &k);
4224 if (r < 0)
4225 return r;
294d81f1
LP
4226
4227 r = load_from_path(u, k);
294d81f1 4228 if (r < 0)
9e2f7c11 4229 return r;
890f434c 4230
abc08d4d 4231 if (u->load_state == UNIT_STUB) {
ac155bb8 4232 SET_FOREACH(t, u->names, i) {
bc9fd78c 4233 _cleanup_free_ char *z = NULL;
87f0e418 4234
ac155bb8 4235 if (t == u->id)
23a177ef 4236 continue;
071830ff 4237
7410616c
LP
4238 r = unit_name_template(t, &z);
4239 if (r < 0)
4240 return r;
294d81f1 4241
bc9fd78c 4242 r = load_from_path(u, z);
294d81f1 4243 if (r < 0)
23a177ef 4244 return r;
890f434c 4245
ac155bb8 4246 if (u->load_state != UNIT_STUB)
23a177ef
LP
4247 break;
4248 }
abc08d4d 4249 }
071830ff
LP
4250 }
4251
23a177ef 4252 return 0;
3efd4195 4253}
e537352b
LP
4254
4255void unit_dump_config_items(FILE *f) {
f975e971
LP
4256 static const struct {
4257 const ConfigParserCallback callback;
4258 const char *rvalue;
4259 } table[] = {
7f8aa671 4260#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
4261 { config_parse_warn_compat, "NOTSUPPORTED" },
4262#endif
f975e971
LP
4263 { config_parse_int, "INTEGER" },
4264 { config_parse_unsigned, "UNSIGNED" },
5556b5fe 4265 { config_parse_iec_size, "SIZE" },
59f448cf 4266 { config_parse_iec_uint64, "SIZE" },
5556b5fe 4267 { config_parse_si_size, "SIZE" },
f975e971
LP
4268 { config_parse_bool, "BOOLEAN" },
4269 { config_parse_string, "STRING" },
4270 { config_parse_path, "PATH" },
4271 { config_parse_unit_path_printf, "PATH" },
4272 { config_parse_strv, "STRING [...]" },
4273 { config_parse_exec_nice, "NICE" },
4274 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4275 { config_parse_exec_io_class, "IOCLASS" },
4276 { config_parse_exec_io_priority, "IOPRIORITY" },
4277 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4278 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4279 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4280 { config_parse_mode, "MODE" },
4281 { config_parse_unit_env_file, "FILE" },
52c239d7
LB
4282 { config_parse_exec_output, "OUTPUT" },
4283 { config_parse_exec_input, "INPUT" },
ca37242e
LP
4284 { config_parse_log_facility, "FACILITY" },
4285 { config_parse_log_level, "LEVEL" },
f975e971 4286 { config_parse_exec_secure_bits, "SECUREBITS" },
a103496c 4287 { config_parse_capability_set, "BOUNDINGSET" },
f975e971 4288 { config_parse_limit, "LIMIT" },
f975e971 4289 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
4290 { config_parse_exec, "PATH [ARGUMENT [...]]" },
4291 { config_parse_service_type, "SERVICETYPE" },
4292 { config_parse_service_restart, "SERVICERESTART" },
4293#ifdef HAVE_SYSV_COMPAT
4294 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
4295#endif
4296 { config_parse_kill_mode, "KILLMODE" },
f757855e 4297 { config_parse_signal, "SIGNAL" },
f975e971
LP
4298 { config_parse_socket_listen, "SOCKET [...]" },
4299 { config_parse_socket_bind, "SOCKETBIND" },
4300 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 4301 { config_parse_sec, "SECONDS" },
d88a251b 4302 { config_parse_nsec, "NANOSECONDS" },
94828d2d 4303 { config_parse_namespace_path_strv, "PATH [...]" },
7c8fa05c 4304 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
4305 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4306 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 4307 { config_parse_trigger_unit, "UNIT" },
f975e971 4308 { config_parse_timer, "TIMER" },
f975e971 4309 { config_parse_path_spec, "PATH" },
f975e971
LP
4310 { config_parse_notify_access, "ACCESS" },
4311 { config_parse_ip_tos, "TOS" },
4312 { config_parse_unit_condition_path, "CONDITION" },
4313 { config_parse_unit_condition_string, "CONDITION" },
4314 { config_parse_unit_condition_null, "CONDITION" },
a016b922 4315 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
4316 { config_parse_documentation, "URL" },
4317 { config_parse_service_timeout, "SECONDS" },
bf500566 4318 { config_parse_failure_action, "ACTION" },
7f0386f6
LP
4319 { config_parse_set_status, "STATUS" },
4320 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 4321 { config_parse_environ, "ENVIRON" },
c0467cf3 4322#ifdef HAVE_SECCOMP
17df7223 4323 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 4324 { config_parse_syscall_archs, "ARCHS" },
17df7223 4325 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 4326 { config_parse_address_families, "FAMILIES" },
c0467cf3 4327#endif
7f0386f6 4328 { config_parse_cpu_shares, "SHARES" },
66ebf6c0 4329 { config_parse_cpu_weight, "WEIGHT" },
7f0386f6
LP
4330 { config_parse_memory_limit, "LIMIT" },
4331 { config_parse_device_allow, "DEVICE" },
4332 { config_parse_device_policy, "POLICY" },
13c31542
TH
4333 { config_parse_io_limit, "LIMIT" },
4334 { config_parse_io_weight, "WEIGHT" },
4335 { config_parse_io_device_weight, "DEVICEWEIGHT" },
7f0386f6
LP
4336 { config_parse_blockio_bandwidth, "BANDWIDTH" },
4337 { config_parse_blockio_weight, "WEIGHT" },
4338 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4339 { config_parse_long, "LONG" },
4340 { config_parse_socket_service, "SERVICE" },
6a6751fe
LP
4341#ifdef HAVE_SELINUX
4342 { config_parse_exec_selinux_context, "LABEL" },
4343#endif
4344 { config_parse_job_mode, "MODE" },
4345 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 4346 { config_parse_personality, "PERSONALITY" },
f975e971
LP
4347 };
4348
4349 const char *prev = NULL;
4350 const char *i;
4351
4352 assert(f);
e537352b 4353
f975e971
LP
4354 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4355 const char *rvalue = "OTHER", *lvalue;
4356 unsigned j;
4357 size_t prefix_len;
4358 const char *dot;
4359 const ConfigPerfItem *p;
4360
4361 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4362
4363 dot = strchr(i, '.');
4364 lvalue = dot ? dot + 1 : i;
4365 prefix_len = dot-i;
4366
4367 if (dot)
641906e9 4368 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
4369 if (prev)
4370 fputc('\n', f);
4371
4372 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
4373 }
4374
4375 for (j = 0; j < ELEMENTSOF(table); j++)
4376 if (p->parse == table[j].callback) {
4377 rvalue = table[j].rvalue;
4378 break;
4379 }
4380
4381 fprintf(f, "%s=%s\n", lvalue, rvalue);
4382 prev = i;
4383 }
e537352b 4384}