]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
tree-wide: drop unneded WHITESPACE param to extract_first_word
[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
9a82ab95 609 r = extract_first_word_and_warn(&p, &firstword, NULL, 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
9a82ab95 698 r = extract_first_word_and_warn(&p, &word, NULL, 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
9a82ab95 1954 r = extract_first_word(&p, &word, NULL, 0);
66dccd8d
LP
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
9a82ab95 2303 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
b4c14404
FB
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");
87a47f99 2526DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "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
8130926d 2621
201c1cc2
TM
2622static int syscall_filter_parse_one(
2623 const char *unit,
2624 const char *filename,
2625 unsigned line,
2626 ExecContext *c,
2627 bool invert,
2628 const char *t,
2629 bool warn) {
2630 int r;
2631
8130926d
LP
2632 if (t[0] == '@') {
2633 const SyscallFilterSet *set;
2634 const char *i;
201c1cc2 2635
8130926d
LP
2636 set = syscall_filter_set_find(t);
2637 if (!set) {
2638 if (warn)
2639 log_syntax(unit, LOG_WARNING, filename, line, 0, "Don't know system call group, ignoring: %s", t);
2640 return 0;
2641 }
201c1cc2 2642
8130926d
LP
2643 NULSTR_FOREACH(i, set->value) {
2644 r = syscall_filter_parse_one(unit, filename, line, c, invert, i, false);
2645 if (r < 0)
2646 return r;
2647 }
201c1cc2
TM
2648 } else {
2649 int id;
2650
2651 id = seccomp_syscall_resolve_name(t);
391b81cd 2652 if (id == __NR_SCMP_ERROR) {
201c1cc2 2653 if (warn)
8130926d 2654 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
201c1cc2
TM
2655 return 0;
2656 }
2657
2658 /* If we previously wanted to forbid a syscall and now
2659 * we want to allow it, then remove it from the list
2660 */
2661 if (!invert == c->syscall_whitelist) {
2662 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2663 if (r == 0)
2664 return 0;
2665 if (r < 0)
2666 return log_oom();
2667 } else
8130926d 2668 (void) set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
201c1cc2 2669 }
8130926d 2670
201c1cc2
TM
2671 return 0;
2672}
2673
17df7223
LP
2674int config_parse_syscall_filter(
2675 const char *unit,
2676 const char *filename,
2677 unsigned line,
2678 const char *section,
2679 unsigned section_line,
2680 const char *lvalue,
2681 int ltype,
2682 const char *rvalue,
2683 void *data,
2684 void *userdata) {
2685
8351ceae
LP
2686 ExecContext *c = data;
2687 Unit *u = userdata;
b5fb3789 2688 bool invert = false;
8130926d 2689 const char *p;
17df7223 2690 int r;
8351ceae
LP
2691
2692 assert(filename);
2693 assert(lvalue);
2694 assert(rvalue);
2695 assert(u);
2696
74051b9b
LP
2697 if (isempty(rvalue)) {
2698 /* Empty assignment resets the list */
525d3cc7 2699 c->syscall_filter = set_free(c->syscall_filter);
17df7223 2700 c->syscall_whitelist = false;
74051b9b
LP
2701 return 0;
2702 }
2703
8351ceae
LP
2704 if (rvalue[0] == '~') {
2705 invert = true;
2706 rvalue++;
2707 }
2708
17df7223 2709 if (!c->syscall_filter) {
d5099efc 2710 c->syscall_filter = set_new(NULL);
17df7223
LP
2711 if (!c->syscall_filter)
2712 return log_oom();
2713
c0467cf3 2714 if (invert)
17df7223
LP
2715 /* Allow everything but the ones listed */
2716 c->syscall_whitelist = false;
c0467cf3 2717 else {
17df7223
LP
2718 /* Allow nothing but the ones listed */
2719 c->syscall_whitelist = true;
8351ceae 2720
17df7223 2721 /* Accept default syscalls if we are on a whitelist */
201c1cc2
TM
2722 r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false);
2723 if (r < 0)
2724 return r;
c0467cf3 2725 }
8351ceae
LP
2726 }
2727
8130926d
LP
2728 p = rvalue;
2729 for (;;) {
2730 _cleanup_free_ char *word = NULL;
8351ceae 2731
8130926d
LP
2732 r = extract_first_word(&p, &word, NULL, 0);
2733 if (r == 0)
2734 break;
2735 if (r == -ENOMEM)
74051b9b 2736 return log_oom();
8130926d
LP
2737 if (r < 0) {
2738 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
2739 break;
2740 }
8351ceae 2741
8130926d 2742 r = syscall_filter_parse_one(unit, filename, line, c, invert, word, true);
201c1cc2
TM
2743 if (r < 0)
2744 return r;
c0467cf3
RC
2745 }
2746
17df7223
LP
2747 return 0;
2748}
2749
57183d11
LP
2750int config_parse_syscall_archs(
2751 const char *unit,
2752 const char *filename,
2753 unsigned line,
2754 const char *section,
2755 unsigned section_line,
2756 const char *lvalue,
2757 int ltype,
2758 const char *rvalue,
2759 void *data,
2760 void *userdata) {
2761
d3b1c508 2762 Set **archs = data;
a2a5291b 2763 const char *word, *state;
57183d11
LP
2764 size_t l;
2765 int r;
2766
2767 if (isempty(rvalue)) {
525d3cc7 2768 *archs = set_free(*archs);
57183d11
LP
2769 return 0;
2770 }
2771
d5099efc 2772 r = set_ensure_allocated(archs, NULL);
57183d11
LP
2773 if (r < 0)
2774 return log_oom();
2775
a2a5291b 2776 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
57183d11
LP
2777 _cleanup_free_ char *t = NULL;
2778 uint32_t a;
2779
a2a5291b 2780 t = strndup(word, l);
57183d11
LP
2781 if (!t)
2782 return log_oom();
2783
2784 r = seccomp_arch_from_string(t, &a);
2785 if (r < 0) {
12ca818f 2786 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
57183d11
LP
2787 continue;
2788 }
2789
d3b1c508 2790 r = set_put(*archs, UINT32_TO_PTR(a + 1));
756c09e6 2791 if (r == 0)
57183d11
LP
2792 continue;
2793 if (r < 0)
2794 return log_oom();
2795 }
b2fadec6 2796 if (!isempty(state))
12ca818f 2797 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
57183d11
LP
2798
2799 return 0;
2800}
2801
17df7223
LP
2802int config_parse_syscall_errno(
2803 const char *unit,
2804 const char *filename,
2805 unsigned line,
2806 const char *section,
2807 unsigned section_line,
2808 const char *lvalue,
2809 int ltype,
2810 const char *rvalue,
2811 void *data,
2812 void *userdata) {
2813
2814 ExecContext *c = data;
2815 int e;
2816
2817 assert(filename);
2818 assert(lvalue);
2819 assert(rvalue);
2820
2821 if (isempty(rvalue)) {
2822 /* Empty assignment resets to KILL */
2823 c->syscall_errno = 0;
2824 return 0;
8351ceae
LP
2825 }
2826
17df7223
LP
2827 e = errno_from_name(rvalue);
2828 if (e < 0) {
12ca818f 2829 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
17df7223
LP
2830 return 0;
2831 }
8351ceae 2832
17df7223 2833 c->syscall_errno = e;
8351ceae
LP
2834 return 0;
2835}
4298d0b5
LP
2836
2837int config_parse_address_families(
2838 const char *unit,
2839 const char *filename,
2840 unsigned line,
2841 const char *section,
2842 unsigned section_line,
2843 const char *lvalue,
2844 int ltype,
2845 const char *rvalue,
2846 void *data,
2847 void *userdata) {
2848
2849 ExecContext *c = data;
4298d0b5 2850 bool invert = false;
a2a5291b 2851 const char *word, *state;
4298d0b5
LP
2852 size_t l;
2853 int r;
2854
2855 assert(filename);
2856 assert(lvalue);
2857 assert(rvalue);
4298d0b5
LP
2858
2859 if (isempty(rvalue)) {
2860 /* Empty assignment resets the list */
525d3cc7 2861 c->address_families = set_free(c->address_families);
4298d0b5
LP
2862 c->address_families_whitelist = false;
2863 return 0;
2864 }
2865
2866 if (rvalue[0] == '~') {
2867 invert = true;
2868 rvalue++;
2869 }
2870
2871 if (!c->address_families) {
d5099efc 2872 c->address_families = set_new(NULL);
4298d0b5
LP
2873 if (!c->address_families)
2874 return log_oom();
2875
2876 c->address_families_whitelist = !invert;
2877 }
2878
a2a5291b 2879 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
4298d0b5
LP
2880 _cleanup_free_ char *t = NULL;
2881 int af;
2882
a2a5291b 2883 t = strndup(word, l);
4298d0b5
LP
2884 if (!t)
2885 return log_oom();
2886
2887 af = af_from_name(t);
2888 if (af <= 0) {
12ca818f 2889 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t);
4298d0b5
LP
2890 continue;
2891 }
2892
2893 /* If we previously wanted to forbid an address family and now
2894 * we want to allow it, then remove it from the list
2895 */
2896 if (!invert == c->address_families_whitelist) {
2897 r = set_put(c->address_families, INT_TO_PTR(af));
756c09e6 2898 if (r == 0)
4298d0b5
LP
2899 continue;
2900 if (r < 0)
2901 return log_oom();
2902 } else
2903 set_remove(c->address_families, INT_TO_PTR(af));
2904 }
b2fadec6 2905 if (!isempty(state))
12ca818f 2906 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
4298d0b5
LP
2907
2908 return 0;
2909}
c0467cf3 2910#endif
8351ceae 2911
a016b922
LP
2912int config_parse_unit_slice(
2913 const char *unit,
2914 const char *filename,
2915 unsigned line,
2916 const char *section,
71a61510 2917 unsigned section_line,
a016b922
LP
2918 const char *lvalue,
2919 int ltype,
2920 const char *rvalue,
2921 void *data,
2922 void *userdata) {
2923
2924 _cleanup_free_ char *k = NULL;
d79200e2 2925 Unit *u = userdata, *slice = NULL;
a016b922
LP
2926 int r;
2927
2928 assert(filename);
2929 assert(lvalue);
2930 assert(rvalue);
2931 assert(u);
2932
19f6d710 2933 r = unit_name_printf(u, rvalue, &k);
d79200e2
LP
2934 if (r < 0) {
2935 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2936 return 0;
19f6d710 2937 }
a016b922 2938
19f6d710 2939 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
a016b922 2940 if (r < 0) {
d79200e2 2941 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
a016b922
LP
2942 return 0;
2943 }
2944
d79200e2
LP
2945 r = unit_set_slice(u, slice);
2946 if (r < 0) {
2947 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
a016b922
LP
2948 return 0;
2949 }
2950
a016b922
LP
2951 return 0;
2952}
2953
4ad49000
LP
2954DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2955
66ebf6c0
TH
2956int config_parse_cpu_weight(
2957 const char *unit,
2958 const char *filename,
2959 unsigned line,
2960 const char *section,
2961 unsigned section_line,
2962 const char *lvalue,
2963 int ltype,
2964 const char *rvalue,
2965 void *data,
2966 void *userdata) {
2967
2968 uint64_t *weight = data;
2969 int r;
2970
2971 assert(filename);
2972 assert(lvalue);
2973 assert(rvalue);
2974
2975 r = cg_weight_parse(rvalue, weight);
2976 if (r < 0) {
2977 log_syntax(unit, LOG_ERR, filename, line, r, "CPU weight '%s' invalid. Ignoring.", rvalue);
2978 return 0;
2979 }
2980
2981 return 0;
2982}
2983
4ad49000
LP
2984int config_parse_cpu_shares(
2985 const char *unit,
2986 const char *filename,
2987 unsigned line,
2988 const char *section,
71a61510 2989 unsigned section_line,
4ad49000
LP
2990 const char *lvalue,
2991 int ltype,
2992 const char *rvalue,
2993 void *data,
2994 void *userdata) {
2995
d53d9474 2996 uint64_t *shares = data;
95ae05c0
WC
2997 int r;
2998
2999 assert(filename);
3000 assert(lvalue);
3001 assert(rvalue);
3002
d53d9474
LP
3003 r = cg_cpu_shares_parse(rvalue, shares);
3004 if (r < 0) {
3005 log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
3006 return 0;
3007 }
3008
4ad49000
LP
3009 return 0;
3010}
3011
b2f8b02e
LP
3012int config_parse_cpu_quota(
3013 const char *unit,
3014 const char *filename,
3015 unsigned line,
3016 const char *section,
3017 unsigned section_line,
3018 const char *lvalue,
3019 int ltype,
3020 const char *rvalue,
3021 void *data,
3022 void *userdata) {
3023
3024 CGroupContext *c = data;
9184ca48 3025 int r;
b2f8b02e
LP
3026
3027 assert(filename);
3028 assert(lvalue);
3029 assert(rvalue);
3030
3031 if (isempty(rvalue)) {
3a43da28 3032 c->cpu_quota_per_sec_usec = USEC_INFINITY;
b2f8b02e
LP
3033 return 0;
3034 }
3035
5124866d 3036 r = parse_percent_unbounded(rvalue);
9184ca48
LP
3037 if (r <= 0) {
3038 log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
9a054909 3039 return 0;
b2f8b02e
LP
3040 }
3041
9184ca48 3042 c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
b2f8b02e
LP
3043 return 0;
3044}
3045
4ad49000
LP
3046int config_parse_memory_limit(
3047 const char *unit,
3048 const char *filename,
3049 unsigned line,
3050 const char *section,
71a61510 3051 unsigned section_line,
4ad49000
LP
3052 const char *lvalue,
3053 int ltype,
3054 const char *rvalue,
3055 void *data,
3056 void *userdata) {
3057
3058 CGroupContext *c = data;
da4d897e 3059 uint64_t bytes = CGROUP_LIMIT_MAX;
4ad49000
LP
3060 int r;
3061
e57c9ce1 3062 if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
875ae566
LP
3063
3064 r = parse_percent(rvalue);
3065 if (r < 0) {
3066 r = parse_size(rvalue, 1024, &bytes);
3067 if (r < 0) {
3068 log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
3069 return 0;
3070 }
3071 } else
d8cf2ac7 3072 bytes = physical_memory_scale(r, 100U);
875ae566 3073
b3785cd5
LP
3074 if (bytes <= 0 || bytes >= UINT64_MAX) {
3075 log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
da4d897e
TH
3076 return 0;
3077 }
4ad49000
LP
3078 }
3079
da4d897e
TH
3080 if (streq(lvalue, "MemoryLow"))
3081 c->memory_low = bytes;
3082 else if (streq(lvalue, "MemoryHigh"))
3083 c->memory_high = bytes;
3084 else if (streq(lvalue, "MemoryMax"))
3085 c->memory_max = bytes;
96e131ea
WC
3086 else if (streq(lvalue, "MemorySwapMax"))
3087 c->memory_swap_max = bytes;
3088 else if (streq(lvalue, "MemoryLimit"))
da4d897e 3089 c->memory_limit = bytes;
96e131ea
WC
3090 else
3091 return -EINVAL;
4ad49000 3092
4ad49000
LP
3093 return 0;
3094}
3095
03a7b521
LP
3096int config_parse_tasks_max(
3097 const char *unit,
3098 const char *filename,
3099 unsigned line,
3100 const char *section,
3101 unsigned section_line,
3102 const char *lvalue,
3103 int ltype,
3104 const char *rvalue,
3105 void *data,
3106 void *userdata) {
3107
f5058264
TH
3108 uint64_t *tasks_max = data, v;
3109 Unit *u = userdata;
03a7b521
LP
3110 int r;
3111
f5058264
TH
3112 if (isempty(rvalue)) {
3113 *tasks_max = u->manager->default_tasks_max;
3114 return 0;
3115 }
3116
3117 if (streq(rvalue, "infinity")) {
3118 *tasks_max = CGROUP_LIMIT_MAX;
03a7b521
LP
3119 return 0;
3120 }
3121
83f8e808
LP
3122 r = parse_percent(rvalue);
3123 if (r < 0) {
f5058264 3124 r = safe_atou64(rvalue, &v);
83f8e808
LP
3125 if (r < 0) {
3126 log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
3127 return 0;
3128 }
3129 } else
f5058264 3130 v = system_tasks_max_scale(r, 100U);
83f8e808 3131
f5058264 3132 if (v <= 0 || v >= UINT64_MAX) {
83f8e808 3133 log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
03a7b521
LP
3134 return 0;
3135 }
3136
f5058264 3137 *tasks_max = v;
03a7b521
LP
3138 return 0;
3139}
3140
4ad49000
LP
3141int config_parse_device_allow(
3142 const char *unit,
3143 const char *filename,
3144 unsigned line,
3145 const char *section,
71a61510 3146 unsigned section_line,
4ad49000
LP
3147 const char *lvalue,
3148 int ltype,
3149 const char *rvalue,
3150 void *data,
3151 void *userdata) {
3152
1116e14c 3153 _cleanup_free_ char *path = NULL, *t = NULL;
4ad49000
LP
3154 CGroupContext *c = data;
3155 CGroupDeviceAllow *a;
1116e14c 3156 const char *m = NULL;
4ad49000 3157 size_t n;
1116e14c 3158 int r;
4ad49000
LP
3159
3160 if (isempty(rvalue)) {
3161 while (c->device_allow)
3162 cgroup_context_free_device_allow(c, c->device_allow);
3163
3164 return 0;
3165 }
3166
1116e14c
NBS
3167 r = unit_full_printf(userdata, rvalue, &t);
3168 if(r < 0) {
3169 log_syntax(unit, LOG_WARNING, filename, line, r,
3170 "Failed to resolve specifiers in %s, ignoring: %m",
3171 rvalue);
3172 }
3173
3174 n = strcspn(t, WHITESPACE);
3175
3176 path = strndup(t, n);
4ad49000
LP
3177 if (!path)
3178 return log_oom();
3179
3ccb8862 3180 if (!is_deviceallow_pattern(path)) {
12ca818f 3181 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
3182 return 0;
3183 }
3184
1116e14c 3185 m = t + n + strspn(t + n, WHITESPACE);
4ad49000
LP
3186 if (isempty(m))
3187 m = "rwm";
3188
3189 if (!in_charset(m, "rwm")) {
12ca818f 3190 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
4ad49000
LP
3191 return 0;
3192 }
3193
3194 a = new0(CGroupDeviceAllow, 1);
3195 if (!a)
3196 return log_oom();
3197
3198 a->path = path;
3199 path = NULL;
3200 a->r = !!strchr(m, 'r');
3201 a->w = !!strchr(m, 'w');
3202 a->m = !!strchr(m, 'm');
3203
71fda00f 3204 LIST_PREPEND(device_allow, c->device_allow, a);
4ad49000
LP
3205 return 0;
3206}
3207
13c31542
TH
3208int config_parse_io_weight(
3209 const char *unit,
3210 const char *filename,
3211 unsigned line,
3212 const char *section,
3213 unsigned section_line,
3214 const char *lvalue,
3215 int ltype,
3216 const char *rvalue,
3217 void *data,
3218 void *userdata) {
3219
3220 uint64_t *weight = data;
3221 int r;
3222
3223 assert(filename);
3224 assert(lvalue);
3225 assert(rvalue);
3226
3227 r = cg_weight_parse(rvalue, weight);
3228 if (r < 0) {
3229 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
3230 return 0;
3231 }
3232
3233 return 0;
3234}
3235
3236int config_parse_io_device_weight(
3237 const char *unit,
3238 const char *filename,
3239 unsigned line,
3240 const char *section,
3241 unsigned section_line,
3242 const char *lvalue,
3243 int ltype,
3244 const char *rvalue,
3245 void *data,
3246 void *userdata) {
3247
3248 _cleanup_free_ char *path = NULL;
3249 CGroupIODeviceWeight *w;
3250 CGroupContext *c = data;
3251 const char *weight;
3252 uint64_t u;
3253 size_t n;
3254 int r;
3255
3256 assert(filename);
3257 assert(lvalue);
3258 assert(rvalue);
3259
3260 if (isempty(rvalue)) {
3261 while (c->io_device_weights)
3262 cgroup_context_free_io_device_weight(c, c->io_device_weights);
3263
3264 return 0;
3265 }
3266
3267 n = strcspn(rvalue, WHITESPACE);
3268 weight = rvalue + n;
3269 weight += strspn(weight, WHITESPACE);
3270
3271 if (isempty(weight)) {
3272 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3273 return 0;
3274 }
3275
3276 path = strndup(rvalue, n);
3277 if (!path)
3278 return log_oom();
3279
3280 if (!path_startswith(path, "/dev")) {
3281 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3282 return 0;
3283 }
3284
3285 r = cg_weight_parse(weight, &u);
3286 if (r < 0) {
3287 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
3288 return 0;
3289 }
3290
3291 assert(u != CGROUP_WEIGHT_INVALID);
3292
3293 w = new0(CGroupIODeviceWeight, 1);
3294 if (!w)
3295 return log_oom();
3296
3297 w->path = path;
3298 path = NULL;
3299
3300 w->weight = u;
3301
3302 LIST_PREPEND(device_weights, c->io_device_weights, w);
3303 return 0;
3304}
3305
3306int config_parse_io_limit(
3307 const char *unit,
3308 const char *filename,
3309 unsigned line,
3310 const char *section,
3311 unsigned section_line,
3312 const char *lvalue,
3313 int ltype,
3314 const char *rvalue,
3315 void *data,
3316 void *userdata) {
3317
3318 _cleanup_free_ char *path = NULL;
3319 CGroupIODeviceLimit *l = NULL, *t;
3320 CGroupContext *c = data;
9be57249 3321 CGroupIOLimitType type;
13c31542
TH
3322 const char *limit;
3323 uint64_t num;
13c31542
TH
3324 size_t n;
3325 int r;
3326
3327 assert(filename);
3328 assert(lvalue);
3329 assert(rvalue);
3330
9be57249
TH
3331 type = cgroup_io_limit_type_from_string(lvalue);
3332 assert(type >= 0);
13c31542
TH
3333
3334 if (isempty(rvalue)) {
3335 LIST_FOREACH(device_limits, l, c->io_device_limits)
9be57249 3336 l->limits[type] = cgroup_io_limit_defaults[type];
13c31542
TH
3337 return 0;
3338 }
3339
3340 n = strcspn(rvalue, WHITESPACE);
3341 limit = rvalue + n;
3342 limit += strspn(limit, WHITESPACE);
3343
3344 if (!*limit) {
3345 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3346 return 0;
3347 }
3348
3349 path = strndup(rvalue, n);
3350 if (!path)
3351 return log_oom();
3352
3353 if (!path_startswith(path, "/dev")) {
3354 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3355 return 0;
3356 }
3357
e57c9ce1 3358 if (streq("infinity", limit)) {
13c31542
TH
3359 num = CGROUP_LIMIT_MAX;
3360 } else {
3361 r = parse_size(limit, 1000, &num);
3362 if (r < 0 || num <= 0) {
3363 log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
3364 return 0;
3365 }
3366 }
3367
3368 LIST_FOREACH(device_limits, t, c->io_device_limits) {
3369 if (path_equal(path, t->path)) {
3370 l = t;
3371 break;
3372 }
3373 }
3374
3375 if (!l) {
9be57249
TH
3376 CGroupIOLimitType ttype;
3377
13c31542
TH
3378 l = new0(CGroupIODeviceLimit, 1);
3379 if (!l)
3380 return log_oom();
3381
3382 l->path = path;
3383 path = NULL;
9be57249
TH
3384 for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
3385 l->limits[ttype] = cgroup_io_limit_defaults[ttype];
13c31542
TH
3386
3387 LIST_PREPEND(device_limits, c->io_device_limits, l);
3388 }
3389
9be57249 3390 l->limits[type] = num;
13c31542
TH
3391
3392 return 0;
3393}
3394
4ad49000
LP
3395int config_parse_blockio_weight(
3396 const char *unit,
3397 const char *filename,
3398 unsigned line,
3399 const char *section,
71a61510 3400 unsigned section_line,
4ad49000
LP
3401 const char *lvalue,
3402 int ltype,
3403 const char *rvalue,
3404 void *data,
3405 void *userdata) {
3406
d53d9474 3407 uint64_t *weight = data;
95ae05c0
WC
3408 int r;
3409
3410 assert(filename);
3411 assert(lvalue);
3412 assert(rvalue);
3413
d53d9474
LP
3414 r = cg_blkio_weight_parse(rvalue, weight);
3415 if (r < 0) {
3416 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
3417 return 0;
3418 }
3419
8e7076ca
LP
3420 return 0;
3421}
3422
3423int config_parse_blockio_device_weight(
3424 const char *unit,
3425 const char *filename,
3426 unsigned line,
3427 const char *section,
71a61510 3428 unsigned section_line,
8e7076ca
LP
3429 const char *lvalue,
3430 int ltype,
3431 const char *rvalue,
3432 void *data,
3433 void *userdata) {
3434
4ad49000 3435 _cleanup_free_ char *path = NULL;
8e7076ca 3436 CGroupBlockIODeviceWeight *w;
4ad49000 3437 CGroupContext *c = data;
4ad49000 3438 const char *weight;
d53d9474 3439 uint64_t u;
4ad49000
LP
3440 size_t n;
3441 int r;
3442
3443 assert(filename);
3444 assert(lvalue);
3445 assert(rvalue);
3446
3447 if (isempty(rvalue)) {
4ad49000
LP
3448 while (c->blockio_device_weights)
3449 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3450
3451 return 0;
3452 }
3453
3454 n = strcspn(rvalue, WHITESPACE);
3455 weight = rvalue + n;
d53d9474
LP
3456 weight += strspn(weight, WHITESPACE);
3457
3458 if (isempty(weight)) {
12ca818f 3459 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
8e7076ca
LP
3460 return 0;
3461 }
4ad49000 3462
8e7076ca
LP
3463 path = strndup(rvalue, n);
3464 if (!path)
3465 return log_oom();
4ad49000 3466
8e7076ca 3467 if (!path_startswith(path, "/dev")) {
12ca818f 3468 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
8e7076ca
LP
3469 return 0;
3470 }
4ad49000 3471
d53d9474
LP
3472 r = cg_blkio_weight_parse(weight, &u);
3473 if (r < 0) {
3474 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
4ad49000
LP
3475 return 0;
3476 }
3477
d53d9474
LP
3478 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3479
8e7076ca
LP
3480 w = new0(CGroupBlockIODeviceWeight, 1);
3481 if (!w)
3482 return log_oom();
4ad49000 3483
8e7076ca
LP
3484 w->path = path;
3485 path = NULL;
4ad49000 3486
d53d9474 3487 w->weight = u;
4ad49000 3488
71fda00f 3489 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
3490 return 0;
3491}
3492
3493int config_parse_blockio_bandwidth(
3494 const char *unit,
3495 const char *filename,
3496 unsigned line,
3497 const char *section,
71a61510 3498 unsigned section_line,
4ad49000
LP
3499 const char *lvalue,
3500 int ltype,
3501 const char *rvalue,
3502 void *data,
3503 void *userdata) {
3504
3505 _cleanup_free_ char *path = NULL;
979d0311 3506 CGroupBlockIODeviceBandwidth *b = NULL, *t;
4ad49000
LP
3507 CGroupContext *c = data;
3508 const char *bandwidth;
59f448cf 3509 uint64_t bytes;
47c0980d 3510 bool read;
4ad49000
LP
3511 size_t n;
3512 int r;
3513
3514 assert(filename);
3515 assert(lvalue);
3516 assert(rvalue);
3517
47c0980d
G
3518 read = streq("BlockIOReadBandwidth", lvalue);
3519
4ad49000 3520 if (isempty(rvalue)) {
979d0311
TH
3521 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
3522 b->rbps = CGROUP_LIMIT_MAX;
3523 b->wbps = CGROUP_LIMIT_MAX;
3524 }
4ad49000
LP
3525 return 0;
3526 }
3527
3528 n = strcspn(rvalue, WHITESPACE);
3529 bandwidth = rvalue + n;
3530 bandwidth += strspn(bandwidth, WHITESPACE);
3531
3532 if (!*bandwidth) {
12ca818f 3533 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
4ad49000
LP
3534 return 0;
3535 }
3536
3537 path = strndup(rvalue, n);
3538 if (!path)
3539 return log_oom();
3540
3541 if (!path_startswith(path, "/dev")) {
12ca818f 3542 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
3543 return 0;
3544 }
3545
5556b5fe 3546 r = parse_size(bandwidth, 1000, &bytes);
4ad49000 3547 if (r < 0 || bytes <= 0) {
12ca818f 3548 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
3549 return 0;
3550 }
3551
979d0311
TH
3552 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
3553 if (path_equal(path, t->path)) {
3554 b = t;
3555 break;
3556 }
3557 }
4ad49000 3558
979d0311
TH
3559 if (!t) {
3560 b = new0(CGroupBlockIODeviceBandwidth, 1);
3561 if (!b)
3562 return log_oom();
3563
3564 b->path = path;
3565 path = NULL;
3566 b->rbps = CGROUP_LIMIT_MAX;
3567 b->wbps = CGROUP_LIMIT_MAX;
3568
3569 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3570 }
4ad49000 3571
979d0311
TH
3572 if (read)
3573 b->rbps = bytes;
3574 else
3575 b->wbps = bytes;
4ad49000
LP
3576
3577 return 0;
3578}
3579
d420282b
LP
3580DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3581
3582int config_parse_job_mode_isolate(
3583 const char *unit,
3584 const char *filename,
3585 unsigned line,
3586 const char *section,
3587 unsigned section_line,
3588 const char *lvalue,
3589 int ltype,
3590 const char *rvalue,
3591 void *data,
3592 void *userdata) {
3593
3594 JobMode *m = data;
3595 int r;
3596
3597 assert(filename);
3598 assert(lvalue);
3599 assert(rvalue);
3600
3601 r = parse_boolean(rvalue);
3602 if (r < 0) {
12ca818f 3603 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
d420282b
LP
3604 return 0;
3605 }
3606
3607 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3608 return 0;
3609}
3610
e66cf1a3
LP
3611int config_parse_runtime_directory(
3612 const char *unit,
3613 const char *filename,
3614 unsigned line,
3615 const char *section,
3616 unsigned section_line,
3617 const char *lvalue,
3618 int ltype,
3619 const char *rvalue,
3620 void *data,
3621 void *userdata) {
3622
a2a5291b 3623 char***rt = data;
9b5864d9 3624 Unit *u = userdata;
a2a5291b 3625 const char *word, *state;
e66cf1a3
LP
3626 size_t l;
3627 int r;
3628
3629 assert(filename);
3630 assert(lvalue);
3631 assert(rvalue);
3632 assert(data);
3633
3634 if (isempty(rvalue)) {
3635 /* Empty assignment resets the list */
6796073e 3636 *rt = strv_free(*rt);
e66cf1a3
LP
3637 return 0;
3638 }
3639
a2a5291b 3640 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
9b5864d9 3641 _cleanup_free_ char *t = NULL, *n = NULL;
e66cf1a3 3642
9b5864d9
MG
3643 t = strndup(word, l);
3644 if (!t)
e66cf1a3
LP
3645 return log_oom();
3646
9b5864d9
MG
3647 r = unit_name_printf(u, t, &n);
3648 if (r < 0) {
12ca818f 3649 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
9b5864d9
MG
3650 continue;
3651 }
3652
ae6c3cc0 3653 if (!filename_is_valid(n)) {
12ca818f 3654 log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
e66cf1a3
LP
3655 continue;
3656 }
3657
3658 r = strv_push(rt, n);
3659 if (r < 0)
3660 return log_oom();
3661
3662 n = NULL;
3663 }
b2fadec6 3664 if (!isempty(state))
12ca818f 3665 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
e66cf1a3
LP
3666
3667 return 0;
3668}
3669
3af00fb8
LP
3670int config_parse_set_status(
3671 const char *unit,
3672 const char *filename,
3673 unsigned line,
3674 const char *section,
3675 unsigned section_line,
3676 const char *lvalue,
3677 int ltype,
3678 const char *rvalue,
3679 void *data,
3680 void *userdata) {
3681
3af00fb8 3682 size_t l;
a2a5291b 3683 const char *word, *state;
3af00fb8
LP
3684 int r;
3685 ExitStatusSet *status_set = data;
3686
3687 assert(filename);
3688 assert(lvalue);
3689 assert(rvalue);
3690 assert(data);
3691
3e2d435b 3692 /* Empty assignment resets the list */
3af00fb8 3693 if (isempty(rvalue)) {
3e2d435b 3694 exit_status_set_free(status_set);
3af00fb8
LP
3695 return 0;
3696 }
3697
a2a5291b 3698 FOREACH_WORD(word, l, rvalue, state) {
3af00fb8
LP
3699 _cleanup_free_ char *temp;
3700 int val;
61593865 3701 Set **set;
3af00fb8 3702
a2a5291b 3703 temp = strndup(word, l);
3af00fb8
LP
3704 if (!temp)
3705 return log_oom();
3706
3707 r = safe_atoi(temp, &val);
3708 if (r < 0) {
3709 val = signal_from_string_try_harder(temp);
3710
1e2fd62d 3711 if (val <= 0) {
12ca818f 3712 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
61593865 3713 continue;
3af00fb8 3714 }
61593865 3715 set = &status_set->signal;
3af00fb8 3716 } else {
1e2fd62d 3717 if (val < 0 || val > 255) {
12ca818f 3718 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
1e2fd62d 3719 continue;
3af00fb8 3720 }
61593865 3721 set = &status_set->status;
3af00fb8 3722 }
1e2fd62d 3723
61593865 3724 r = set_ensure_allocated(set, NULL);
1e2fd62d
ZJS
3725 if (r < 0)
3726 return log_oom();
3727
61593865 3728 r = set_put(*set, INT_TO_PTR(val));
1e2fd62d 3729 if (r < 0) {
12ca818f 3730 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
1e2fd62d
ZJS
3731 return r;
3732 }
3af00fb8 3733 }
b2fadec6 3734 if (!isempty(state))
12ca818f 3735 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3af00fb8
LP
3736
3737 return 0;
3738}
3739
94828d2d
LP
3740int config_parse_namespace_path_strv(
3741 const char *unit,
3742 const char *filename,
3743 unsigned line,
3744 const char *section,
3745 unsigned section_line,
3746 const char *lvalue,
3747 int ltype,
3748 const char *rvalue,
3749 void *data,
3750 void *userdata) {
3751
a2a5291b 3752 char*** sv = data;
727f76d7
EV
3753 const char *prev;
3754 const char *cur;
94828d2d
LP
3755 int r;
3756
3757 assert(filename);
3758 assert(lvalue);
3759 assert(rvalue);
3760 assert(data);
3761
3762 if (isempty(rvalue)) {
3763 /* Empty assignment resets the list */
6796073e 3764 *sv = strv_free(*sv);
94828d2d
LP
3765 return 0;
3766 }
3767
727f76d7
EV
3768 prev = cur = rvalue;
3769 for (;;) {
3770 _cleanup_free_ char *word = NULL;
94828d2d
LP
3771 int offset;
3772
727f76d7 3773 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
0293a7a8
EV
3774 if (r == 0)
3775 break;
3776 if (r == -ENOMEM)
3777 return log_oom();
727f76d7 3778 if (r < 0) {
0293a7a8 3779 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
727f76d7
EV
3780 return 0;
3781 }
94828d2d 3782
727f76d7
EV
3783 if (!utf8_is_valid(word)) {
3784 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3785 prev = cur;
94828d2d
LP
3786 continue;
3787 }
3788
727f76d7
EV
3789 offset = word[0] == '-';
3790 if (!path_is_absolute(word + offset)) {
3791 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
3792 prev = cur;
94828d2d
LP
3793 continue;
3794 }
3795
727f76d7 3796 path_kill_slashes(word + offset);
94828d2d 3797
727f76d7 3798 r = strv_push(sv, word);
94828d2d
LP
3799 if (r < 0)
3800 return log_oom();
3801
727f76d7
EV
3802 prev = cur;
3803 word = NULL;
94828d2d
LP
3804 }
3805
3806 return 0;
3807}
3808
f1721625 3809int config_parse_no_new_privileges(
760b9d7c
LP
3810 const char* unit,
3811 const char *filename,
3812 unsigned line,
3813 const char *section,
3814 unsigned section_line,
3815 const char *lvalue,
3816 int ltype,
3817 const char *rvalue,
3818 void *data,
3819 void *userdata) {
3820
3821 ExecContext *c = data;
3822 int k;
3823
3824 assert(filename);
3825 assert(lvalue);
3826 assert(rvalue);
3827 assert(data);
3828
3829 k = parse_boolean(rvalue);
3830 if (k < 0) {
12ca818f 3831 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
760b9d7c
LP
3832 return 0;
3833 }
3834
9b232d32 3835 c->no_new_privileges = k;
760b9d7c
LP
3836 c->no_new_privileges_set = true;
3837
3838 return 0;
3839}
3840
1b8689f9 3841int config_parse_protect_home(
417116f2
LP
3842 const char* unit,
3843 const char *filename,
3844 unsigned line,
3845 const char *section,
3846 unsigned section_line,
3847 const char *lvalue,
3848 int ltype,
3849 const char *rvalue,
3850 void *data,
3851 void *userdata) {
3852
3853 ExecContext *c = data;
3854 int k;
3855
3856 assert(filename);
3857 assert(lvalue);
3858 assert(rvalue);
3859 assert(data);
3860
3861 /* Our enum shall be a superset of booleans, hence first try
61233823 3862 * to parse as boolean, and then as enum */
417116f2
LP
3863
3864 k = parse_boolean(rvalue);
3865 if (k > 0)
1b8689f9 3866 c->protect_home = PROTECT_HOME_YES;
417116f2 3867 else if (k == 0)
1b8689f9 3868 c->protect_home = PROTECT_HOME_NO;
417116f2 3869 else {
1b8689f9 3870 ProtectHome h;
417116f2 3871
1b8689f9 3872 h = protect_home_from_string(rvalue);
9ed794a3 3873 if (h < 0) {
12ca818f 3874 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
3875 return 0;
3876 }
3877
1b8689f9
LP
3878 c->protect_home = h;
3879 }
3880
3881 return 0;
3882}
3883
3884int config_parse_protect_system(
3885 const char* unit,
3886 const char *filename,
3887 unsigned line,
3888 const char *section,
3889 unsigned section_line,
3890 const char *lvalue,
3891 int ltype,
3892 const char *rvalue,
3893 void *data,
3894 void *userdata) {
3895
3896 ExecContext *c = data;
3897 int k;
3898
3899 assert(filename);
3900 assert(lvalue);
3901 assert(rvalue);
3902 assert(data);
3903
3904 /* Our enum shall be a superset of booleans, hence first try
61233823 3905 * to parse as boolean, and then as enum */
1b8689f9
LP
3906
3907 k = parse_boolean(rvalue);
3908 if (k > 0)
3909 c->protect_system = PROTECT_SYSTEM_YES;
3910 else if (k == 0)
3911 c->protect_system = PROTECT_SYSTEM_NO;
3912 else {
3913 ProtectSystem s;
3914
3915 s = protect_system_from_string(rvalue);
9ed794a3 3916 if (s < 0) {
12ca818f 3917 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
1b8689f9
LP
3918 return 0;
3919 }
3920
3921 c->protect_system = s;
417116f2
LP
3922 }
3923
3924 return 0;
3925}
3926
071830ff 3927#define FOLLOW_MAX 8
87f0e418 3928
9e2f7c11 3929static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
a837f088 3930 char *id = NULL;
0301abf4 3931 unsigned c = 0;
87f0e418
LP
3932 int fd, r;
3933 FILE *f;
87f0e418
LP
3934
3935 assert(filename);
3936 assert(*filename);
3937 assert(_f);
3938 assert(names);
3939
0301abf4
LP
3940 /* This will update the filename pointer if the loaded file is
3941 * reached by a symlink. The old string will be freed. */
87f0e418 3942
0301abf4 3943 for (;;) {
2c7108c4 3944 char *target, *name;
87f0e418 3945
0301abf4
LP
3946 if (c++ >= FOLLOW_MAX)
3947 return -ELOOP;
3948
b08d03ff
LP
3949 path_kill_slashes(*filename);
3950
87f0e418 3951 /* Add the file name we are currently looking at to
8f05424d
LP
3952 * the names of this unit, but only if it is a valid
3953 * unit name. */
2b6bf07d 3954 name = basename(*filename);
7410616c 3955 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
8f05424d 3956
15e11d81
LP
3957 id = set_get(names, name);
3958 if (!id) {
3959 id = strdup(name);
3960 if (!id)
8f05424d 3961 return -ENOMEM;
87f0e418 3962
ef42202a
ZJS
3963 r = set_consume(names, id);
3964 if (r < 0)
8f05424d 3965 return r;
87f0e418 3966 }
87f0e418
LP
3967 }
3968
0301abf4 3969 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
3970 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3971 if (fd >= 0)
87f0e418
LP
3972 break;
3973
0301abf4
LP
3974 if (errno != ELOOP)
3975 return -errno;
3976
87f0e418 3977 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
3978 r = readlink_and_make_absolute(*filename, &target);
3979 if (r < 0)
0301abf4 3980 return r;
87f0e418 3981
0301abf4 3982 free(*filename);
2c7108c4 3983 *filename = target;
87f0e418
LP
3984 }
3985
9946996c
LP
3986 f = fdopen(fd, "re");
3987 if (!f) {
03e334a1 3988 safe_close(fd);
d4ad27a1 3989 return -errno;
87f0e418
LP
3990 }
3991
3992 *_f = f;
9e2f7c11 3993 *_final = id;
a837f088 3994
0301abf4 3995 return 0;
87f0e418
LP
3996}
3997
23a177ef
LP
3998static int merge_by_names(Unit **u, Set *names, const char *id) {
3999 char *k;
4000 int r;
4001
4002 assert(u);
4003 assert(*u);
4004 assert(names);
4005
4006 /* Let's try to add in all symlink names we found */
4007 while ((k = set_steal_first(names))) {
4008
4009 /* First try to merge in the other name into our
4010 * unit */
9946996c
LP
4011 r = unit_merge_by_name(*u, k);
4012 if (r < 0) {
23a177ef
LP
4013 Unit *other;
4014
4015 /* Hmm, we couldn't merge the other unit into
4016 * ours? Then let's try it the other way
4017 * round */
4018
7aad67e7
MS
4019 /* If the symlink name we are looking at is unit template, then
4020 we must search for instance of this template */
9d3e3406 4021 if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
7aad67e7
MS
4022 _cleanup_free_ char *instance = NULL;
4023
4024 r = unit_name_replace_instance(k, (*u)->instance, &instance);
4025 if (r < 0)
4026 return r;
4027
4028 other = manager_get_unit((*u)->manager, instance);
4029 } else
4030 other = manager_get_unit((*u)->manager, k);
4031
23a177ef
LP
4032 free(k);
4033
9946996c
LP
4034 if (other) {
4035 r = unit_merge(other, *u);
4036 if (r >= 0) {
23a177ef
LP
4037 *u = other;
4038 return merge_by_names(u, names, NULL);
4039 }
9946996c 4040 }
23a177ef
LP
4041
4042 return r;
4043 }
4044
4045 if (id == k)
4046 unit_choose_id(*u, id);
4047
4048 free(k);
4049 }
4050
4051 return 0;
4052}
4053
e537352b 4054static int load_from_path(Unit *u, const char *path) {
e48614c4
ZJS
4055 _cleanup_set_free_free_ Set *symlink_names = NULL;
4056 _cleanup_fclose_ FILE *f = NULL;
4057 _cleanup_free_ char *filename = NULL;
4058 char *id = NULL;
23a177ef 4059 Unit *merged;
45fb0699 4060 struct stat st;
a837f088 4061 int r;
23a177ef
LP
4062
4063 assert(u);
e537352b 4064 assert(path);
3efd4195 4065
d5099efc 4066 symlink_names = set_new(&string_hash_ops);
f975e971 4067 if (!symlink_names)
87f0e418 4068 return -ENOMEM;
3efd4195 4069
036643a2
LP
4070 if (path_is_absolute(path)) {
4071
9946996c 4072 filename = strdup(path);
e48614c4
ZJS
4073 if (!filename)
4074 return -ENOMEM;
036643a2 4075
9946996c
LP
4076 r = open_follow(&filename, &f, symlink_names, &id);
4077 if (r < 0) {
97b11eed 4078 filename = mfree(filename);
036643a2 4079 if (r != -ENOENT)
e48614c4 4080 return r;
036643a2
LP
4081 }
4082
4083 } else {
4084 char **p;
4085
a3c4eb07 4086 STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
036643a2
LP
4087
4088 /* Instead of opening the path right away, we manually
4089 * follow all symlinks and add their name to our unit
4090 * name set while doing so */
9946996c 4091 filename = path_make_absolute(path, *p);
e48614c4
ZJS
4092 if (!filename)
4093 return -ENOMEM;
036643a2 4094
ac155bb8
MS
4095 if (u->manager->unit_path_cache &&
4096 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
4097 r = -ENOENT;
4098 else
4099 r = open_follow(&filename, &f, symlink_names, &id);
a837f088
LP
4100 if (r >= 0)
4101 break;
4102 filename = mfree(filename);
a1feacf7
ZJS
4103
4104 /* ENOENT means that the file is missing or is a dangling symlink.
4105 * ENOTDIR means that one of paths we expect to be is a directory
4106 * is not a directory, we should just ignore that.
4107 * EACCES means that the directory or file permissions are wrong.
4108 */
4109 if (r == -EACCES)
4110 log_debug_errno(r, "Cannot access \"%s\": %m", filename);
4111 else if (!IN_SET(r, -ENOENT, -ENOTDIR))
a837f088 4112 return r;
fe51822e 4113
a837f088
LP
4114 /* Empty the symlink names for the next run */
4115 set_clear_free(symlink_names);
036643a2
LP
4116 }
4117 }
034c6ed7 4118
e48614c4 4119 if (!filename)
8f05424d 4120 /* Hmm, no suitable file found? */
e48614c4 4121 return 0;
87f0e418 4122
8a993b61 4123 if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
a837f088
LP
4124 log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
4125 return -ELOOP;
4126 }
4127
23a177ef 4128 merged = u;
9946996c
LP
4129 r = merge_by_names(&merged, symlink_names, id);
4130 if (r < 0)
e48614c4 4131 return r;
87f0e418 4132
23a177ef 4133 if (merged != u) {
ac155bb8 4134 u->load_state = UNIT_MERGED;
e48614c4 4135 return 0;
034c6ed7
LP
4136 }
4137
e48614c4
ZJS
4138 if (fstat(fileno(f), &st) < 0)
4139 return -errno;
45fb0699 4140
3a8db9fe 4141 if (null_or_empty(&st)) {
ac155bb8 4142 u->load_state = UNIT_MASKED;
3a8db9fe
ZJS
4143 u->fragment_mtime = 0;
4144 } else {
c2756a68 4145 u->load_state = UNIT_LOADED;
3a8db9fe 4146 u->fragment_mtime = timespec_load(&st.st_mtim);
c2756a68 4147
00dc5d76 4148 /* Now, parse the file contents */
36f822c4
ZJS
4149 r = config_parse(u->id, filename, f,
4150 UNIT_VTABLE(u)->sections,
4151 config_item_perf_lookup, load_fragment_gperf_lookup,
4152 false, true, false, u);
f975e971 4153 if (r < 0)
e48614c4 4154 return r;
00dc5d76 4155 }
b08d03ff 4156
ac155bb8
MS
4157 free(u->fragment_path);
4158 u->fragment_path = filename;
0301abf4 4159 filename = NULL;
87f0e418 4160
1b64d026
LP
4161 if (u->source_path) {
4162 if (stat(u->source_path, &st) >= 0)
4163 u->source_mtime = timespec_load(&st.st_mtim);
4164 else
4165 u->source_mtime = 0;
4166 }
4167
e48614c4 4168 return 0;
0301abf4
LP
4169}
4170
e537352b 4171int unit_load_fragment(Unit *u) {
23a177ef 4172 int r;
294d81f1
LP
4173 Iterator i;
4174 const char *t;
0301abf4
LP
4175
4176 assert(u);
ac155bb8
MS
4177 assert(u->load_state == UNIT_STUB);
4178 assert(u->id);
23a177ef 4179
3f5e8115
LP
4180 if (u->transient) {
4181 u->load_state = UNIT_LOADED;
4182 return 0;
4183 }
4184
294d81f1
LP
4185 /* First, try to find the unit under its id. We always look
4186 * for unit files in the default directories, to make it easy
4187 * to override things by placing things in /etc/systemd/system */
9946996c
LP
4188 r = load_from_path(u, u->id);
4189 if (r < 0)
294d81f1
LP
4190 return r;
4191
4192 /* Try to find an alias we can load this with */
abc08d4d 4193 if (u->load_state == UNIT_STUB) {
ac155bb8 4194 SET_FOREACH(t, u->names, i) {
294d81f1 4195
ac155bb8 4196 if (t == u->id)
294d81f1
LP
4197 continue;
4198
9946996c
LP
4199 r = load_from_path(u, t);
4200 if (r < 0)
294d81f1
LP
4201 return r;
4202
ac155bb8 4203 if (u->load_state != UNIT_STUB)
294d81f1
LP
4204 break;
4205 }
abc08d4d 4206 }
23a177ef 4207
294d81f1 4208 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 4209 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 4210
9946996c
LP
4211 r = load_from_path(u, u->fragment_path);
4212 if (r < 0)
23a177ef 4213 return r;
0301abf4 4214
ece174c5 4215 if (u->load_state == UNIT_STUB)
6ccb1b44
LP
4216 /* Hmm, this didn't work? Then let's get rid
4217 * of the fragment path stored for us, so that
4218 * we don't point to an invalid location. */
a1e58e8e 4219 u->fragment_path = mfree(u->fragment_path);
6ccb1b44
LP
4220 }
4221
294d81f1 4222 /* Look for a template */
ac155bb8 4223 if (u->load_state == UNIT_STUB && u->instance) {
7410616c 4224 _cleanup_free_ char *k = NULL;
294d81f1 4225
7410616c
LP
4226 r = unit_name_template(u->id, &k);
4227 if (r < 0)
4228 return r;
294d81f1
LP
4229
4230 r = load_from_path(u, k);
294d81f1 4231 if (r < 0)
9e2f7c11 4232 return r;
890f434c 4233
abc08d4d 4234 if (u->load_state == UNIT_STUB) {
ac155bb8 4235 SET_FOREACH(t, u->names, i) {
bc9fd78c 4236 _cleanup_free_ char *z = NULL;
87f0e418 4237
ac155bb8 4238 if (t == u->id)
23a177ef 4239 continue;
071830ff 4240
7410616c
LP
4241 r = unit_name_template(t, &z);
4242 if (r < 0)
4243 return r;
294d81f1 4244
bc9fd78c 4245 r = load_from_path(u, z);
294d81f1 4246 if (r < 0)
23a177ef 4247 return r;
890f434c 4248
ac155bb8 4249 if (u->load_state != UNIT_STUB)
23a177ef
LP
4250 break;
4251 }
abc08d4d 4252 }
071830ff
LP
4253 }
4254
23a177ef 4255 return 0;
3efd4195 4256}
e537352b
LP
4257
4258void unit_dump_config_items(FILE *f) {
f975e971
LP
4259 static const struct {
4260 const ConfigParserCallback callback;
4261 const char *rvalue;
4262 } table[] = {
7f8aa671 4263#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
4264 { config_parse_warn_compat, "NOTSUPPORTED" },
4265#endif
f975e971
LP
4266 { config_parse_int, "INTEGER" },
4267 { config_parse_unsigned, "UNSIGNED" },
5556b5fe 4268 { config_parse_iec_size, "SIZE" },
59f448cf 4269 { config_parse_iec_uint64, "SIZE" },
5556b5fe 4270 { config_parse_si_size, "SIZE" },
f975e971
LP
4271 { config_parse_bool, "BOOLEAN" },
4272 { config_parse_string, "STRING" },
4273 { config_parse_path, "PATH" },
4274 { config_parse_unit_path_printf, "PATH" },
4275 { config_parse_strv, "STRING [...]" },
4276 { config_parse_exec_nice, "NICE" },
4277 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4278 { config_parse_exec_io_class, "IOCLASS" },
4279 { config_parse_exec_io_priority, "IOPRIORITY" },
4280 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4281 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4282 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4283 { config_parse_mode, "MODE" },
4284 { config_parse_unit_env_file, "FILE" },
52c239d7
LB
4285 { config_parse_exec_output, "OUTPUT" },
4286 { config_parse_exec_input, "INPUT" },
ca37242e
LP
4287 { config_parse_log_facility, "FACILITY" },
4288 { config_parse_log_level, "LEVEL" },
f975e971 4289 { config_parse_exec_secure_bits, "SECUREBITS" },
a103496c 4290 { config_parse_capability_set, "BOUNDINGSET" },
f975e971 4291 { config_parse_limit, "LIMIT" },
f975e971 4292 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
4293 { config_parse_exec, "PATH [ARGUMENT [...]]" },
4294 { config_parse_service_type, "SERVICETYPE" },
4295 { config_parse_service_restart, "SERVICERESTART" },
4296#ifdef HAVE_SYSV_COMPAT
4297 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
4298#endif
4299 { config_parse_kill_mode, "KILLMODE" },
f757855e 4300 { config_parse_signal, "SIGNAL" },
f975e971
LP
4301 { config_parse_socket_listen, "SOCKET [...]" },
4302 { config_parse_socket_bind, "SOCKETBIND" },
4303 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 4304 { config_parse_sec, "SECONDS" },
d88a251b 4305 { config_parse_nsec, "NANOSECONDS" },
94828d2d 4306 { config_parse_namespace_path_strv, "PATH [...]" },
7c8fa05c 4307 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
4308 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4309 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 4310 { config_parse_trigger_unit, "UNIT" },
f975e971 4311 { config_parse_timer, "TIMER" },
f975e971 4312 { config_parse_path_spec, "PATH" },
f975e971
LP
4313 { config_parse_notify_access, "ACCESS" },
4314 { config_parse_ip_tos, "TOS" },
4315 { config_parse_unit_condition_path, "CONDITION" },
4316 { config_parse_unit_condition_string, "CONDITION" },
4317 { config_parse_unit_condition_null, "CONDITION" },
a016b922 4318 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
4319 { config_parse_documentation, "URL" },
4320 { config_parse_service_timeout, "SECONDS" },
87a47f99 4321 { config_parse_emergency_action, "ACTION" },
7f0386f6
LP
4322 { config_parse_set_status, "STATUS" },
4323 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 4324 { config_parse_environ, "ENVIRON" },
c0467cf3 4325#ifdef HAVE_SECCOMP
17df7223 4326 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 4327 { config_parse_syscall_archs, "ARCHS" },
17df7223 4328 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 4329 { config_parse_address_families, "FAMILIES" },
c0467cf3 4330#endif
7f0386f6 4331 { config_parse_cpu_shares, "SHARES" },
66ebf6c0 4332 { config_parse_cpu_weight, "WEIGHT" },
7f0386f6
LP
4333 { config_parse_memory_limit, "LIMIT" },
4334 { config_parse_device_allow, "DEVICE" },
4335 { config_parse_device_policy, "POLICY" },
13c31542
TH
4336 { config_parse_io_limit, "LIMIT" },
4337 { config_parse_io_weight, "WEIGHT" },
4338 { config_parse_io_device_weight, "DEVICEWEIGHT" },
7f0386f6
LP
4339 { config_parse_blockio_bandwidth, "BANDWIDTH" },
4340 { config_parse_blockio_weight, "WEIGHT" },
4341 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4342 { config_parse_long, "LONG" },
4343 { config_parse_socket_service, "SERVICE" },
6a6751fe
LP
4344#ifdef HAVE_SELINUX
4345 { config_parse_exec_selinux_context, "LABEL" },
4346#endif
4347 { config_parse_job_mode, "MODE" },
4348 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 4349 { config_parse_personality, "PERSONALITY" },
f975e971
LP
4350 };
4351
4352 const char *prev = NULL;
4353 const char *i;
4354
4355 assert(f);
e537352b 4356
f975e971
LP
4357 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4358 const char *rvalue = "OTHER", *lvalue;
4359 unsigned j;
4360 size_t prefix_len;
4361 const char *dot;
4362 const ConfigPerfItem *p;
4363
4364 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4365
4366 dot = strchr(i, '.');
4367 lvalue = dot ? dot + 1 : i;
4368 prefix_len = dot-i;
4369
4370 if (dot)
641906e9 4371 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
4372 if (prev)
4373 fputc('\n', f);
4374
4375 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
4376 }
4377
4378 for (j = 0; j < ELEMENTSOF(table); j++)
4379 if (p->parse == table[j].callback) {
4380 rvalue = table[j].rvalue;
4381 break;
4382 }
4383
4384 fprintf(f, "%s=%s\n", lvalue, rvalue);
4385 prev = i;
4386 }
e537352b 4387}