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