]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
unit: move unit_warn_if_dir_nonempty() and friend to unit.c
[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;
8d9803b8 1205 else if (streq(t, "private"))
c2c13f2d 1206 flags = MS_PRIVATE;
15ae422b 1207 else {
8d9803b8 1208 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
c0b34696 1209 return 0;
15ae422b
LP
1210 }
1211 }
b2fadec6 1212 if (!isempty(state))
8d9803b8 1213 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
15ae422b
LP
1214
1215 c->mount_flags = flags;
1216 return 0;
1217}
1218
5f8640fb
LP
1219int config_parse_exec_selinux_context(
1220 const char *unit,
1221 const char *filename,
1222 unsigned line,
1223 const char *section,
1224 unsigned section_line,
1225 const char *lvalue,
1226 int ltype,
1227 const char *rvalue,
1228 void *data,
1229 void *userdata) {
1230
1231 ExecContext *c = data;
1232 Unit *u = userdata;
1233 bool ignore;
1234 char *k;
1235 int r;
1236
1237 assert(filename);
1238 assert(lvalue);
1239 assert(rvalue);
1240 assert(data);
1241
1242 if (isempty(rvalue)) {
1243 free(c->selinux_context);
1244 c->selinux_context = NULL;
1245 c->selinux_context_ignore = false;
1246 return 0;
1247 }
1248
1249 if (rvalue[0] == '-') {
1250 ignore = true;
1251 rvalue++;
1252 } else
1253 ignore = false;
1254
1255 r = unit_name_printf(u, rvalue, &k);
1256 if (r < 0) {
1e2fd62d
ZJS
1257 log_syntax(unit, LOG_ERR, filename, line, -r,
1258 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
5f8640fb
LP
1259 return 0;
1260 }
1261
1262 free(c->selinux_context);
1263 c->selinux_context = k;
1264 c->selinux_context_ignore = ignore;
1265
1266 return 0;
1267}
1268
eef65bf3
MS
1269int config_parse_exec_apparmor_profile(
1270 const char *unit,
1271 const char *filename,
1272 unsigned line,
1273 const char *section,
1274 unsigned section_line,
1275 const char *lvalue,
1276 int ltype,
1277 const char *rvalue,
1278 void *data,
1279 void *userdata) {
1280
1281 ExecContext *c = data;
1282 Unit *u = userdata;
1283 bool ignore;
1284 char *k;
1285 int r;
1286
1287 assert(filename);
1288 assert(lvalue);
1289 assert(rvalue);
1290 assert(data);
1291
1292 if (isempty(rvalue)) {
1293 free(c->apparmor_profile);
1294 c->apparmor_profile = NULL;
1295 c->apparmor_profile_ignore = false;
1296 return 0;
1297 }
1298
1299 if (rvalue[0] == '-') {
1300 ignore = true;
1301 rvalue++;
1302 } else
1303 ignore = false;
1304
1305 r = unit_name_printf(u, rvalue, &k);
1306 if (r < 0) {
1e2fd62d
ZJS
1307 log_syntax(unit, LOG_ERR, filename, line, -r,
1308 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
eef65bf3
MS
1309 return 0;
1310 }
1311
1312 free(c->apparmor_profile);
1313 c->apparmor_profile = k;
1314 c->apparmor_profile_ignore = ignore;
1315
1316 return 0;
1317}
1318
2ca620c4
WC
1319int config_parse_exec_smack_process_label(
1320 const char *unit,
1321 const char *filename,
1322 unsigned line,
1323 const char *section,
1324 unsigned section_line,
1325 const char *lvalue,
1326 int ltype,
1327 const char *rvalue,
1328 void *data,
1329 void *userdata) {
1330
1331 ExecContext *c = data;
1332 Unit *u = userdata;
1333 bool ignore;
1334 char *k;
1335 int r;
1336
1337 assert(filename);
1338 assert(lvalue);
1339 assert(rvalue);
1340 assert(data);
1341
1342 if (isempty(rvalue)) {
1343 free(c->smack_process_label);
1344 c->smack_process_label = NULL;
1345 c->smack_process_label_ignore = false;
1346 return 0;
1347 }
1348
1349 if (rvalue[0] == '-') {
1350 ignore = true;
1351 rvalue++;
1352 } else
1353 ignore = false;
1354
1355 r = unit_name_printf(u, rvalue, &k);
1356 if (r < 0) {
1357 log_syntax(unit, LOG_ERR, filename, line, -r,
1358 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1359 return 0;
1360 }
1361
1362 free(c->smack_process_label);
1363 c->smack_process_label = k;
1364 c->smack_process_label_ignore = ignore;
1365
1366 return 0;
1367}
1368
e8e581bf
ZJS
1369int config_parse_timer(const char *unit,
1370 const char *filename,
1371 unsigned line,
1372 const char *section,
71a61510 1373 unsigned section_line,
e8e581bf
ZJS
1374 const char *lvalue,
1375 int ltype,
1376 const char *rvalue,
1377 void *data,
1378 void *userdata) {
871d7de4
LP
1379
1380 Timer *t = data;
36697dc0 1381 usec_t u = 0;
871d7de4
LP
1382 TimerValue *v;
1383 TimerBase b;
36697dc0 1384 CalendarSpec *c = NULL;
871d7de4
LP
1385
1386 assert(filename);
1387 assert(lvalue);
1388 assert(rvalue);
1389 assert(data);
1390
74051b9b
LP
1391 if (isempty(rvalue)) {
1392 /* Empty assignment resets list */
1393 timer_free_values(t);
1394 return 0;
1395 }
1396
36697dc0
LP
1397 b = timer_base_from_string(lvalue);
1398 if (b < 0) {
e8e581bf
ZJS
1399 log_syntax(unit, LOG_ERR, filename, line, -b,
1400 "Failed to parse timer base, ignoring: %s", lvalue);
c0b34696 1401 return 0;
871d7de4
LP
1402 }
1403
36697dc0
LP
1404 if (b == TIMER_CALENDAR) {
1405 if (calendar_spec_from_string(rvalue, &c) < 0) {
e8e581bf
ZJS
1406 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1407 "Failed to parse calendar specification, ignoring: %s",
1408 rvalue);
36697dc0
LP
1409 return 0;
1410 }
36697dc0 1411 } else {
7f602784 1412 if (parse_sec(rvalue, &u) < 0) {
e8e581bf
ZJS
1413 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1414 "Failed to parse timer value, ignoring: %s",
1415 rvalue);
36697dc0
LP
1416 return 0;
1417 }
871d7de4
LP
1418 }
1419
36697dc0 1420 v = new0(TimerValue, 1);
4d5e13a1 1421 if (!v) {
0b76b4d8 1422 calendar_spec_free(c);
74051b9b 1423 return log_oom();
4d5e13a1 1424 }
871d7de4
LP
1425
1426 v->base = b;
1427 v->value = u;
36697dc0 1428 v->calendar_spec = c;
871d7de4 1429
71fda00f 1430 LIST_PREPEND(value, t->values, v);
871d7de4
LP
1431
1432 return 0;
1433}
1434
3ecaa09b
LP
1435int config_parse_trigger_unit(
1436 const char *unit,
1437 const char *filename,
1438 unsigned line,
1439 const char *section,
71a61510 1440 unsigned section_line,
3ecaa09b
LP
1441 const char *lvalue,
1442 int ltype,
1443 const char *rvalue,
1444 void *data,
1445 void *userdata) {
871d7de4 1446
74051b9b 1447 _cleanup_free_ char *p = NULL;
3ecaa09b
LP
1448 Unit *u = data;
1449 UnitType type;
1450 int r;
398ef8ba
LP
1451
1452 assert(filename);
1453 assert(lvalue);
1454 assert(rvalue);
1455 assert(data);
1456
3ecaa09b
LP
1457 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1458 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1459 "Multiple units to trigger specified, ignoring: %s", rvalue);
1460 return 0;
1461 }
871d7de4 1462
19f6d710
LP
1463 r = unit_name_printf(u, rvalue, &p);
1464 if (r < 0)
1465 log_syntax(unit, LOG_ERR, filename, line, -r,
1466 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
74051b9b 1467
19f6d710 1468 type = unit_name_to_type(p ?: rvalue);
3ecaa09b 1469 if (type < 0) {
e8e581bf 1470 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3ecaa09b 1471 "Unit type not valid, ignoring: %s", rvalue);
c0b34696 1472 return 0;
871d7de4
LP
1473 }
1474
3ecaa09b
LP
1475 if (type == u->type) {
1476 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1477 "Trigger cannot be of same type, ignoring: %s", rvalue);
1478 return 0;
1479 }
1480
19f6d710 1481 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
57020a3a 1482 if (r < 0) {
e8e581bf 1483 log_syntax(unit, LOG_ERR, filename, line, -r,
19f6d710 1484 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
c0b34696 1485 return 0;
871d7de4
LP
1486 }
1487
1488 return 0;
1489}
1490
e8e581bf
ZJS
1491int config_parse_path_spec(const char *unit,
1492 const char *filename,
1493 unsigned line,
1494 const char *section,
71a61510 1495 unsigned section_line,
e8e581bf
ZJS
1496 const char *lvalue,
1497 int ltype,
1498 const char *rvalue,
1499 void *data,
1500 void *userdata) {
01f78473
LP
1501
1502 Path *p = data;
1503 PathSpec *s;
1504 PathType b;
7fd1b19b 1505 _cleanup_free_ char *k = NULL;
19f6d710 1506 int r;
01f78473
LP
1507
1508 assert(filename);
1509 assert(lvalue);
1510 assert(rvalue);
1511 assert(data);
1512
74051b9b
LP
1513 if (isempty(rvalue)) {
1514 /* Empty assignment clears list */
1515 path_free_specs(p);
1516 return 0;
1517 }
1518
93e4c84b
LP
1519 b = path_type_from_string(lvalue);
1520 if (b < 0) {
e8e581bf
ZJS
1521 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1522 "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 1523 return 0;
01f78473
LP
1524 }
1525
19f6d710
LP
1526 r = unit_full_printf(UNIT(p), rvalue, &k);
1527 if (r < 0) {
487060c2
LP
1528 k = strdup(rvalue);
1529 if (!k)
1530 return log_oom();
1531 else
19f6d710 1532 log_syntax(unit, LOG_ERR, filename, line, -r,
e8e581bf
ZJS
1533 "Failed to resolve unit specifiers on %s. Ignoring.",
1534 rvalue);
487060c2 1535 }
93e4c84b
LP
1536
1537 if (!path_is_absolute(k)) {
e8e581bf
ZJS
1538 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1539 "Path is not absolute, ignoring: %s", k);
c0b34696 1540 return 0;
01f78473
LP
1541 }
1542
93e4c84b 1543 s = new0(PathSpec, 1);
543295ad 1544 if (!s)
93e4c84b 1545 return log_oom();
01f78473 1546
718db961 1547 s->unit = UNIT(p);
93e4c84b 1548 s->path = path_kill_slashes(k);
543295ad 1549 k = NULL;
01f78473
LP
1550 s->type = b;
1551 s->inotify_fd = -1;
1552
71fda00f 1553 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
1554
1555 return 0;
1556}
1557
b02cb41c
LP
1558int config_parse_socket_service(
1559 const char *unit,
1560 const char *filename,
1561 unsigned line,
1562 const char *section,
1563 unsigned section_line,
1564 const char *lvalue,
1565 int ltype,
1566 const char *rvalue,
1567 void *data,
1568 void *userdata) {
d9ff321a 1569
718db961 1570 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d9ff321a
LP
1571 Socket *s = data;
1572 int r;
4ff77f66 1573 Unit *x;
74051b9b 1574 _cleanup_free_ char *p = NULL;
d9ff321a
LP
1575
1576 assert(filename);
1577 assert(lvalue);
1578 assert(rvalue);
1579 assert(data);
1580
19f6d710 1581 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 1582 if (r < 0) {
b02cb41c 1583 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
613b411c
LP
1584 return 0;
1585 }
74051b9b 1586
613b411c 1587 if (!endswith(p, ".service")) {
b02cb41c 1588 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
d9ff321a
LP
1589 return 0;
1590 }
1591
613b411c 1592 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 1593 if (r < 0) {
b02cb41c 1594 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
d9ff321a
LP
1595 return 0;
1596 }
1597
4ff77f66
LP
1598 unit_ref_set(&s->service, x);
1599
d9ff321a
LP
1600 return 0;
1601}
1602
b02cb41c
LP
1603int config_parse_service_sockets(
1604 const char *unit,
1605 const char *filename,
1606 unsigned line,
1607 const char *section,
1608 unsigned section_line,
1609 const char *lvalue,
1610 int ltype,
1611 const char *rvalue,
1612 void *data,
1613 void *userdata) {
f976f3f6
LP
1614
1615 Service *s = data;
a2a5291b 1616 const char *word, *state;
f976f3f6 1617 size_t l;
b02cb41c 1618 int r;
f976f3f6
LP
1619
1620 assert(filename);
1621 assert(lvalue);
1622 assert(rvalue);
1623 assert(data);
1624
a2a5291b 1625 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
7fd1b19b 1626 _cleanup_free_ char *t = NULL, *k = NULL;
f976f3f6 1627
a2a5291b 1628 t = strndup(word, l);
57020a3a 1629 if (!t)
74051b9b 1630 return log_oom();
f976f3f6 1631
19f6d710 1632 r = unit_name_printf(UNIT(s), t, &k);
b02cb41c
LP
1633 if (r < 0) {
1634 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1635 continue;
1636 }
57020a3a 1637
b02cb41c
LP
1638 if (!endswith(k, ".socket")) {
1639 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
f976f3f6
LP
1640 continue;
1641 }
1642
b02cb41c 1643 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
57020a3a 1644 if (r < 0)
b02cb41c 1645 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 1646
b02cb41c 1647 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
57020a3a 1648 if (r < 0)
b02cb41c 1649 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 1650 }
b2fadec6 1651 if (!isempty(state))
b02cb41c 1652 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
f976f3f6
LP
1653
1654 return 0;
1655}
1656
b02cb41c
LP
1657int config_parse_bus_name(
1658 const char *unit,
1659 const char *filename,
1660 unsigned line,
1661 const char *section,
1662 unsigned section_line,
1663 const char *lvalue,
1664 int ltype,
1665 const char *rvalue,
1666 void *data,
1667 void *userdata) {
1668
1669 _cleanup_free_ char *k = NULL;
1670 Unit *u = userdata;
1671 int r;
1672
1673 assert(filename);
1674 assert(lvalue);
1675 assert(rvalue);
1676 assert(u);
1677
1678 r = unit_full_printf(u, rvalue, &k);
1679 if (r < 0) {
1680 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1681 return 0;
1682 }
1683
1684 if (!service_name_is_valid(k)) {
1685 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
1686 return 0;
1687 }
1688
1689 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1690}
1691
e8e581bf
ZJS
1692int config_parse_service_timeout(const char *unit,
1693 const char *filename,
1694 unsigned line,
1695 const char *section,
71a61510 1696 unsigned section_line,
e8e581bf
ZJS
1697 const char *lvalue,
1698 int ltype,
1699 const char *rvalue,
1700 void *data,
1701 void *userdata) {
98709151
LN
1702
1703 Service *s = userdata;
1704 int r;
1705
1706 assert(filename);
1707 assert(lvalue);
1708 assert(rvalue);
1709 assert(s);
1710
71a61510 1711 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 1712 rvalue, data, userdata);
74051b9b 1713 if (r < 0)
d568a335 1714 return r;
98709151 1715
d568a335
MS
1716 if (streq(lvalue, "TimeoutSec")) {
1717 s->start_timeout_defined = true;
1718 s->timeout_stop_usec = s->timeout_start_usec;
1719 } else if (streq(lvalue, "TimeoutStartSec"))
1720 s->start_timeout_defined = true;
1721
1722 return 0;
98709151
LN
1723}
1724
e821075a
LP
1725int config_parse_busname_service(
1726 const char *unit,
1727 const char *filename,
1728 unsigned line,
1729 const char *section,
1730 unsigned section_line,
1731 const char *lvalue,
1732 int ltype,
1733 const char *rvalue,
1734 void *data,
1735 void *userdata) {
1736
1737 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1738 BusName *n = data;
1739 int r;
1740 Unit *x;
1741 _cleanup_free_ char *p = NULL;
1742
1743 assert(filename);
1744 assert(lvalue);
1745 assert(rvalue);
1746 assert(data);
1747
1748 r = unit_name_printf(UNIT(n), rvalue, &p);
1749 if (r < 0) {
1e2fd62d
ZJS
1750 log_syntax(unit, LOG_ERR, filename, line, -r,
1751 "Failed to resolve specifiers, ignoring: %s", rvalue);
e821075a
LP
1752 return 0;
1753 }
1754
1755 if (!endswith(p, ".service")) {
1e2fd62d
ZJS
1756 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1757 "Unit must be of type service, ignoring: %s", rvalue);
e821075a
LP
1758 return 0;
1759 }
1760
1761 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1762 if (r < 0) {
1e2fd62d
ZJS
1763 log_syntax(unit, LOG_ERR, filename, line, -r,
1764 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
e821075a
LP
1765 return 0;
1766 }
1767
1768 unit_ref_set(&n->service, x);
1769
1770 return 0;
1771}
1772
5369c77d 1773DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
a4152e3f 1774
54d76c92
DM
1775int config_parse_bus_policy(
1776 const char *unit,
1777 const char *filename,
1778 unsigned line,
1779 const char *section,
1780 unsigned section_line,
1781 const char *lvalue,
1782 int ltype,
1783 const char *rvalue,
1784 void *data,
1785 void *userdata) {
1786
1787 _cleanup_free_ BusNamePolicy *p = NULL;
1788 _cleanup_free_ char *id_str = NULL;
1789 BusName *busname = data;
1790 char *access_str;
54d76c92
DM
1791
1792 assert(filename);
1793 assert(lvalue);
1794 assert(rvalue);
1795 assert(data);
1796
1797 p = new0(BusNamePolicy, 1);
1798 if (!p)
1799 return log_oom();
1800
1801 if (streq(lvalue, "AllowUser"))
1802 p->type = BUSNAME_POLICY_TYPE_USER;
1803 else if (streq(lvalue, "AllowGroup"))
1804 p->type = BUSNAME_POLICY_TYPE_GROUP;
54d76c92
DM
1805 else
1806 assert_not_reached("Unknown lvalue");
1807
1808 id_str = strdup(rvalue);
1809 if (!id_str)
1810 return log_oom();
1811
a4152e3f
LP
1812 access_str = strpbrk(id_str, WHITESPACE);
1813 if (!access_str) {
1e2fd62d
ZJS
1814 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1815 "Invalid busname policy value '%s'", rvalue);
a4152e3f 1816 return 0;
54d76c92
DM
1817 }
1818
a4152e3f
LP
1819 *access_str = '\0';
1820 access_str++;
1821 access_str += strspn(access_str, WHITESPACE);
1822
5369c77d 1823 p->access = bus_policy_access_from_string(access_str);
54d76c92 1824 if (p->access < 0) {
1e2fd62d
ZJS
1825 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1826 "Invalid busname policy access type '%s'", access_str);
54d76c92
DM
1827 return 0;
1828 }
1829
a4152e3f
LP
1830 p->name = id_str;
1831 id_str = NULL;
1832
54d76c92
DM
1833 LIST_PREPEND(policy, busname->policy, p);
1834 p = NULL;
1835
1836 return 0;
1837}
1838
50199623
DM
1839int config_parse_bus_endpoint_policy(
1840 const char *unit,
1841 const char *filename,
1842 unsigned line,
1843 const char *section,
1844 unsigned section_line,
1845 const char *lvalue,
1846 int ltype,
1847 const char *rvalue,
1848 void *data,
1849 void *userdata) {
1850
1851 _cleanup_free_ char *name = NULL;
1852 BusPolicyAccess access;
1853 ExecContext *c = data;
1854 char *access_str;
1855 int r;
1856
1857 assert(filename);
1858 assert(lvalue);
1859 assert(rvalue);
1860 assert(data);
1861
1862 name = strdup(rvalue);
1863 if (!name)
1864 return log_oom();
1865
1866 access_str = strpbrk(name, WHITESPACE);
1867 if (!access_str) {
1868 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1869 "Invalid endpoint policy value '%s'", rvalue);
1870 return 0;
1871 }
1872
1873 *access_str = '\0';
1874 access_str++;
1875 access_str += strspn(access_str, WHITESPACE);
1876
1877 access = bus_policy_access_from_string(access_str);
1878 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1879 access >= _BUS_POLICY_ACCESS_MAX) {
1880 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1881 "Invalid endpoint policy access type '%s'", access_str);
1882 return 0;
1883 }
1884
1885 if (!c->bus_endpoint) {
1886 r = bus_endpoint_new(&c->bus_endpoint);
1887
1888 if (r < 0)
1889 return r;
1890 }
1891
1892 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1893}
1894
e8e581bf
ZJS
1895int config_parse_unit_env_file(const char *unit,
1896 const char *filename,
1897 unsigned line,
1898 const char *section,
71a61510 1899 unsigned section_line,
e8e581bf
ZJS
1900 const char *lvalue,
1901 int ltype,
1902 const char *rvalue,
1903 void *data,
1904 void *userdata) {
ddb26e18 1905
853b8397 1906 char ***env = data;
8fef7659 1907 Unit *u = userdata;
19f6d710
LP
1908 _cleanup_free_ char *n = NULL;
1909 const char *s;
853b8397 1910 int r;
ddb26e18
LP
1911
1912 assert(filename);
1913 assert(lvalue);
1914 assert(rvalue);
1915 assert(data);
1916
74051b9b
LP
1917 if (isempty(rvalue)) {
1918 /* Empty assignment frees the list */
74051b9b
LP
1919 strv_free(*env);
1920 *env = NULL;
1921 return 0;
1922 }
1923
19f6d710
LP
1924 r = unit_full_printf(u, rvalue, &n);
1925 if (r < 0)
1e2fd62d 1926 log_syntax(unit, LOG_ERR, filename, line, -r,
19f6d710 1927 "Failed to resolve specifiers, ignoring: %s", rvalue);
8fef7659 1928
19f6d710 1929 s = n ?: rvalue;
8fef7659 1930 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
e8e581bf
ZJS
1931 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1932 "Path '%s' is not absolute, ignoring.", s);
afe4bfe2
LP
1933 return 0;
1934 }
1935
853b8397
LP
1936 r = strv_extend(env, s);
1937 if (r < 0)
1938 return log_oom();
1939
1940 return 0;
1941}
1942
e8e581bf
ZJS
1943int config_parse_environ(const char *unit,
1944 const char *filename,
1945 unsigned line,
1946 const char *section,
71a61510 1947 unsigned section_line,
e8e581bf
ZJS
1948 const char *lvalue,
1949 int ltype,
1950 const char *rvalue,
1951 void *data,
1952 void *userdata) {
853b8397
LP
1953
1954 Unit *u = userdata;
a2a5291b
ZJS
1955 char*** env = data;
1956 const char *word, *state;
853b8397
LP
1957 size_t l;
1958 _cleanup_free_ char *k = NULL;
19f6d710 1959 int r;
853b8397
LP
1960
1961 assert(filename);
1962 assert(lvalue);
1963 assert(rvalue);
97d0e5f8 1964 assert(data);
853b8397
LP
1965
1966 if (isempty(rvalue)) {
1967 /* Empty assignment resets the list */
1968 strv_free(*env);
1969 *env = NULL;
1970 return 0;
1971 }
1972
19f6d710
LP
1973 if (u) {
1974 r = unit_full_printf(u, rvalue, &k);
1975 if (r < 0)
527b7a42 1976 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
19f6d710 1977 }
97d0e5f8 1978
19f6d710
LP
1979 if (!k)
1980 k = strdup(rvalue);
8fef7659 1981 if (!k)
74051b9b 1982 return log_oom();
ddb26e18 1983
a2a5291b 1984 FOREACH_WORD_QUOTED(word, l, k, state) {
853b8397
LP
1985 _cleanup_free_ char *n;
1986 char **x;
1987
527b7a42
LP
1988 r = cunescape_length(word, l, 0, &n);
1989 if (r < 0) {
1990 log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
1991 continue;
1992 }
853b8397
LP
1993
1994 if (!env_assignment_is_valid(n)) {
527b7a42 1995 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue);
853b8397
LP
1996 continue;
1997 }
1998
1999 x = strv_env_set(*env, n);
2000 if (!x)
2001 return log_oom();
2002
2003 strv_free(*env);
2004 *env = x;
2005 }
b2fadec6
ZJS
2006 if (!isempty(state))
2007 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2008 "Trailing garbage, ignoring.");
ddb26e18 2009
8c7be95e 2010 return 0;
ddb26e18
LP
2011}
2012
e8e581bf
ZJS
2013int config_parse_ip_tos(const char *unit,
2014 const char *filename,
2015 unsigned line,
2016 const char *section,
71a61510 2017 unsigned section_line,
e8e581bf
ZJS
2018 const char *lvalue,
2019 int ltype,
2020 const char *rvalue,
2021 void *data,
2022 void *userdata) {
4fd5948e
LP
2023
2024 int *ip_tos = data, x;
4fd5948e
LP
2025
2026 assert(filename);
2027 assert(lvalue);
2028 assert(rvalue);
2029 assert(data);
2030
f8b69d1d
MS
2031 x = ip_tos_from_string(rvalue);
2032 if (x < 0) {
e8e581bf
ZJS
2033 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2034 "Failed to parse IP TOS value, ignoring: %s", rvalue);
f8b69d1d
MS
2035 return 0;
2036 }
4fd5948e
LP
2037
2038 *ip_tos = x;
2039 return 0;
2040}
2041
59fccdc5
LP
2042int config_parse_unit_condition_path(
2043 const char *unit,
2044 const char *filename,
2045 unsigned line,
2046 const char *section,
2047 unsigned section_line,
2048 const char *lvalue,
2049 int ltype,
2050 const char *rvalue,
2051 void *data,
2052 void *userdata) {
52661efd 2053
2fbe635a 2054 _cleanup_free_ char *p = NULL;
59fccdc5
LP
2055 Condition **list = data, *c;
2056 ConditionType t = ltype;
2057 bool trigger, negate;
2058 Unit *u = userdata;
19f6d710 2059 int r;
52661efd
LP
2060
2061 assert(filename);
2062 assert(lvalue);
2063 assert(rvalue);
2064 assert(data);
2065
74051b9b
LP
2066 if (isempty(rvalue)) {
2067 /* Empty assignment resets the list */
447021aa 2068 *list = condition_free_list(*list);
74051b9b
LP
2069 return 0;
2070 }
2071
ab7f148f
LP
2072 trigger = rvalue[0] == '|';
2073 if (trigger)
267632f0
LP
2074 rvalue++;
2075
ab7f148f
LP
2076 negate = rvalue[0] == '!';
2077 if (negate)
52661efd
LP
2078 rvalue++;
2079
19f6d710 2080 r = unit_full_printf(u, rvalue, &p);
59fccdc5
LP
2081 if (r < 0) {
2082 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2083 return 0;
19f6d710 2084 }
095b2d7a
AK
2085
2086 if (!path_is_absolute(p)) {
59fccdc5 2087 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
52661efd
LP
2088 return 0;
2089 }
2090
59fccdc5 2091 c = condition_new(t, p, trigger, negate);
ab7f148f 2092 if (!c)
74051b9b 2093 return log_oom();
52661efd 2094
59fccdc5 2095 LIST_PREPEND(conditions, *list, c);
52661efd
LP
2096 return 0;
2097}
2098
59fccdc5
LP
2099int config_parse_unit_condition_string(
2100 const char *unit,
2101 const char *filename,
2102 unsigned line,
2103 const char *section,
2104 unsigned section_line,
2105 const char *lvalue,
2106 int ltype,
2107 const char *rvalue,
2108 void *data,
2109 void *userdata) {
039655a4 2110
2fbe635a 2111 _cleanup_free_ char *s = NULL;
59fccdc5
LP
2112 Condition **list = data, *c;
2113 ConditionType t = ltype;
2114 bool trigger, negate;
2115 Unit *u = userdata;
19f6d710 2116 int r;
039655a4
LP
2117
2118 assert(filename);
2119 assert(lvalue);
2120 assert(rvalue);
2121 assert(data);
2122
74051b9b
LP
2123 if (isempty(rvalue)) {
2124 /* Empty assignment resets the list */
447021aa 2125 *list = condition_free_list(*list);
74051b9b
LP
2126 return 0;
2127 }
2128
c0d6e764
LP
2129 trigger = rvalue[0] == '|';
2130 if (trigger)
267632f0
LP
2131 rvalue++;
2132
c0d6e764
LP
2133 negate = rvalue[0] == '!';
2134 if (negate)
039655a4
LP
2135 rvalue++;
2136
19f6d710 2137 r = unit_full_printf(u, rvalue, &s);
59fccdc5
LP
2138 if (r < 0) {
2139 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2140 return 0;
19f6d710 2141 }
095b2d7a 2142
59fccdc5 2143 c = condition_new(t, s, trigger, negate);
c0d6e764
LP
2144 if (!c)
2145 return log_oom();
039655a4 2146
59fccdc5 2147 LIST_PREPEND(conditions, *list, c);
039655a4
LP
2148 return 0;
2149}
2150
59fccdc5
LP
2151int config_parse_unit_condition_null(
2152 const char *unit,
2153 const char *filename,
2154 unsigned line,
2155 const char *section,
2156 unsigned section_line,
2157 const char *lvalue,
2158 int ltype,
2159 const char *rvalue,
2160 void *data,
2161 void *userdata) {
d257ddef 2162
59fccdc5 2163 Condition **list = data, *c;
267632f0 2164 bool trigger, negate;
d257ddef
LP
2165 int b;
2166
2167 assert(filename);
2168 assert(lvalue);
2169 assert(rvalue);
2170 assert(data);
2171
74051b9b
LP
2172 if (isempty(rvalue)) {
2173 /* Empty assignment resets the list */
447021aa 2174 *list = condition_free_list(*list);
74051b9b
LP
2175 return 0;
2176 }
2177
2178 trigger = rvalue[0] == '|';
2179 if (trigger)
267632f0
LP
2180 rvalue++;
2181
74051b9b
LP
2182 negate = rvalue[0] == '!';
2183 if (negate)
d257ddef
LP
2184 rvalue++;
2185
74051b9b
LP
2186 b = parse_boolean(rvalue);
2187 if (b < 0) {
59fccdc5 2188 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
d257ddef
LP
2189 return 0;
2190 }
2191
2192 if (!b)
2193 negate = !negate;
2194
74051b9b
LP
2195 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2196 if (!c)
2197 return log_oom();
d257ddef 2198
59fccdc5 2199 LIST_PREPEND(conditions, *list, c);
d257ddef
LP
2200 return 0;
2201}
2202
f975e971 2203DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
bf500566 2204DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
c952c6ec 2205
a57f7e2c
LP
2206int config_parse_unit_requires_mounts_for(
2207 const char *unit,
2208 const char *filename,
2209 unsigned line,
2210 const char *section,
71a61510 2211 unsigned section_line,
a57f7e2c
LP
2212 const char *lvalue,
2213 int ltype,
2214 const char *rvalue,
2215 void *data,
2216 void *userdata) {
7c8fa05c
LP
2217
2218 Unit *u = userdata;
a2a5291b 2219 const char *word, *state;
a57f7e2c 2220 size_t l;
7c8fa05c
LP
2221
2222 assert(filename);
2223 assert(lvalue);
2224 assert(rvalue);
2225 assert(data);
2226
a2a5291b 2227 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
8a7935a2 2228 int r;
a57f7e2c
LP
2229 _cleanup_free_ char *n;
2230
a2a5291b 2231 n = strndup(word, l);
a57f7e2c
LP
2232 if (!n)
2233 return log_oom();
7c8fa05c 2234
a57f7e2c 2235 if (!utf8_is_valid(n)) {
b5d74213 2236 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
a57f7e2c
LP
2237 continue;
2238 }
7c8fa05c 2239
a57f7e2c
LP
2240 r = unit_require_mounts_for(u, n);
2241 if (r < 0) {
1e2fd62d 2242 log_syntax(unit, LOG_ERR, filename, line, -r,
a57f7e2c
LP
2243 "Failed to add required mount for, ignoring: %s", rvalue);
2244 continue;
2245 }
2246 }
b2fadec6
ZJS
2247 if (!isempty(state))
2248 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2249 "Trailing garbage, ignoring.");
7c8fa05c 2250
8a7935a2 2251 return 0;
7c8fa05c 2252}
9e372868 2253
e8e581bf
ZJS
2254int config_parse_documentation(const char *unit,
2255 const char *filename,
2256 unsigned line,
2257 const char *section,
71a61510 2258 unsigned section_line,
e8e581bf
ZJS
2259 const char *lvalue,
2260 int ltype,
2261 const char *rvalue,
2262 void *data,
2263 void *userdata) {
49dbfa7b
LP
2264
2265 Unit *u = userdata;
2266 int r;
2267 char **a, **b;
2268
2269 assert(filename);
2270 assert(lvalue);
2271 assert(rvalue);
2272 assert(u);
2273
74051b9b
LP
2274 if (isempty(rvalue)) {
2275 /* Empty assignment resets the list */
2276 strv_free(u->documentation);
2277 u->documentation = NULL;
2278 return 0;
2279 }
2280
71a61510 2281 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 2282 rvalue, data, userdata);
49dbfa7b
LP
2283 if (r < 0)
2284 return r;
2285
2286 for (a = b = u->documentation; a && *a; a++) {
2287
a2e03378 2288 if (documentation_url_is_valid(*a))
49dbfa7b
LP
2289 *(b++) = *a;
2290 else {
e8e581bf
ZJS
2291 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2292 "Invalid URL, ignoring: %s", *a);
49dbfa7b
LP
2293 free(*a);
2294 }
2295 }
f6d2d421
ZJS
2296 if (b)
2297 *b = NULL;
49dbfa7b
LP
2298
2299 return r;
2300}
2301
c0467cf3 2302#ifdef HAVE_SECCOMP
17df7223
LP
2303int config_parse_syscall_filter(
2304 const char *unit,
2305 const char *filename,
2306 unsigned line,
2307 const char *section,
2308 unsigned section_line,
2309 const char *lvalue,
2310 int ltype,
2311 const char *rvalue,
2312 void *data,
2313 void *userdata) {
2314
2315 static const char default_syscalls[] =
2316 "execve\0"
2317 "exit\0"
2318 "exit_group\0"
2319 "rt_sigreturn\0"
2320 "sigreturn\0";
2321
8351ceae
LP
2322 ExecContext *c = data;
2323 Unit *u = userdata;
b5fb3789 2324 bool invert = false;
a2a5291b 2325 const char *word, *state;
8351ceae 2326 size_t l;
17df7223 2327 int r;
8351ceae
LP
2328
2329 assert(filename);
2330 assert(lvalue);
2331 assert(rvalue);
2332 assert(u);
2333
74051b9b
LP
2334 if (isempty(rvalue)) {
2335 /* Empty assignment resets the list */
17df7223
LP
2336 set_free(c->syscall_filter);
2337 c->syscall_filter = NULL;
2338 c->syscall_whitelist = false;
74051b9b
LP
2339 return 0;
2340 }
2341
8351ceae
LP
2342 if (rvalue[0] == '~') {
2343 invert = true;
2344 rvalue++;
2345 }
2346
17df7223 2347 if (!c->syscall_filter) {
d5099efc 2348 c->syscall_filter = set_new(NULL);
17df7223
LP
2349 if (!c->syscall_filter)
2350 return log_oom();
2351
c0467cf3 2352 if (invert)
17df7223
LP
2353 /* Allow everything but the ones listed */
2354 c->syscall_whitelist = false;
c0467cf3 2355 else {
17df7223
LP
2356 const char *i;
2357
2358 /* Allow nothing but the ones listed */
2359 c->syscall_whitelist = true;
8351ceae 2360
17df7223
LP
2361 /* Accept default syscalls if we are on a whitelist */
2362 NULSTR_FOREACH(i, default_syscalls) {
2363 int id;
8351ceae 2364
17df7223 2365 id = seccomp_syscall_resolve_name(i);
c0467cf3
RC
2366 if (id < 0)
2367 continue;
8351ceae 2368
17df7223 2369 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
756c09e6 2370 if (r == 0)
17df7223
LP
2371 continue;
2372 if (r < 0)
2373 return log_oom();
c0467cf3
RC
2374 }
2375 }
8351ceae
LP
2376 }
2377
a2a5291b 2378 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
7fd1b19b 2379 _cleanup_free_ char *t = NULL;
17df7223 2380 int id;
8351ceae 2381
a2a5291b 2382 t = strndup(word, l);
8351ceae 2383 if (!t)
74051b9b 2384 return log_oom();
8351ceae 2385
c0467cf3 2386 id = seccomp_syscall_resolve_name(t);
8351ceae 2387 if (id < 0) {
1e2fd62d
ZJS
2388 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2389 "Failed to parse system call, ignoring: %s", t);
8351ceae
LP
2390 continue;
2391 }
2392
17df7223
LP
2393 /* If we previously wanted to forbid a syscall and now
2394 * we want to allow it, then remove it from the list
c0467cf3 2395 */
17df7223
LP
2396 if (!invert == c->syscall_whitelist) {
2397 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
756c09e6 2398 if (r == 0)
17df7223
LP
2399 continue;
2400 if (r < 0)
2401 return log_oom();
2402 } else
2403 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
c0467cf3 2404 }
b2fadec6
ZJS
2405 if (!isempty(state))
2406 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2407 "Trailing garbage, ignoring.");
c0467cf3 2408
760b9d7c
LP
2409 /* Turn on NNP, but only if it wasn't configured explicitly
2410 * before, and only if we are in user mode. */
2411 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2412 c->no_new_privileges = true;
17df7223
LP
2413
2414 return 0;
2415}
2416
57183d11
LP
2417int config_parse_syscall_archs(
2418 const char *unit,
2419 const char *filename,
2420 unsigned line,
2421 const char *section,
2422 unsigned section_line,
2423 const char *lvalue,
2424 int ltype,
2425 const char *rvalue,
2426 void *data,
2427 void *userdata) {
2428
d3b1c508 2429 Set **archs = data;
a2a5291b 2430 const char *word, *state;
57183d11
LP
2431 size_t l;
2432 int r;
2433
2434 if (isempty(rvalue)) {
d3b1c508
LP
2435 set_free(*archs);
2436 *archs = NULL;
57183d11
LP
2437 return 0;
2438 }
2439
d5099efc 2440 r = set_ensure_allocated(archs, NULL);
57183d11
LP
2441 if (r < 0)
2442 return log_oom();
2443
a2a5291b 2444 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
57183d11
LP
2445 _cleanup_free_ char *t = NULL;
2446 uint32_t a;
2447
a2a5291b 2448 t = strndup(word, l);
57183d11
LP
2449 if (!t)
2450 return log_oom();
2451
2452 r = seccomp_arch_from_string(t, &a);
2453 if (r < 0) {
1e2fd62d
ZJS
2454 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2455 "Failed to parse system call architecture, ignoring: %s", t);
57183d11
LP
2456 continue;
2457 }
2458
d3b1c508 2459 r = set_put(*archs, UINT32_TO_PTR(a + 1));
756c09e6 2460 if (r == 0)
57183d11
LP
2461 continue;
2462 if (r < 0)
2463 return log_oom();
2464 }
b2fadec6
ZJS
2465 if (!isempty(state))
2466 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2467 "Trailing garbage, ignoring.");
57183d11
LP
2468
2469 return 0;
2470}
2471
17df7223
LP
2472int config_parse_syscall_errno(
2473 const char *unit,
2474 const char *filename,
2475 unsigned line,
2476 const char *section,
2477 unsigned section_line,
2478 const char *lvalue,
2479 int ltype,
2480 const char *rvalue,
2481 void *data,
2482 void *userdata) {
2483
2484 ExecContext *c = data;
2485 int e;
2486
2487 assert(filename);
2488 assert(lvalue);
2489 assert(rvalue);
2490
2491 if (isempty(rvalue)) {
2492 /* Empty assignment resets to KILL */
2493 c->syscall_errno = 0;
2494 return 0;
8351ceae
LP
2495 }
2496
17df7223
LP
2497 e = errno_from_name(rvalue);
2498 if (e < 0) {
1e2fd62d
ZJS
2499 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2500 "Failed to parse error number, ignoring: %s", rvalue);
17df7223
LP
2501 return 0;
2502 }
8351ceae 2503
17df7223 2504 c->syscall_errno = e;
8351ceae
LP
2505 return 0;
2506}
4298d0b5
LP
2507
2508int config_parse_address_families(
2509 const char *unit,
2510 const char *filename,
2511 unsigned line,
2512 const char *section,
2513 unsigned section_line,
2514 const char *lvalue,
2515 int ltype,
2516 const char *rvalue,
2517 void *data,
2518 void *userdata) {
2519
2520 ExecContext *c = data;
4298d0b5 2521 bool invert = false;
a2a5291b 2522 const char *word, *state;
4298d0b5
LP
2523 size_t l;
2524 int r;
2525
2526 assert(filename);
2527 assert(lvalue);
2528 assert(rvalue);
4298d0b5
LP
2529
2530 if (isempty(rvalue)) {
2531 /* Empty assignment resets the list */
2532 set_free(c->address_families);
2533 c->address_families = NULL;
2534 c->address_families_whitelist = false;
2535 return 0;
2536 }
2537
2538 if (rvalue[0] == '~') {
2539 invert = true;
2540 rvalue++;
2541 }
2542
2543 if (!c->address_families) {
d5099efc 2544 c->address_families = set_new(NULL);
4298d0b5
LP
2545 if (!c->address_families)
2546 return log_oom();
2547
2548 c->address_families_whitelist = !invert;
2549 }
2550
a2a5291b 2551 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
4298d0b5
LP
2552 _cleanup_free_ char *t = NULL;
2553 int af;
2554
a2a5291b 2555 t = strndup(word, l);
4298d0b5
LP
2556 if (!t)
2557 return log_oom();
2558
2559 af = af_from_name(t);
2560 if (af <= 0) {
1e2fd62d
ZJS
2561 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2562 "Failed to parse address family, ignoring: %s", t);
4298d0b5
LP
2563 continue;
2564 }
2565
2566 /* If we previously wanted to forbid an address family and now
2567 * we want to allow it, then remove it from the list
2568 */
2569 if (!invert == c->address_families_whitelist) {
2570 r = set_put(c->address_families, INT_TO_PTR(af));
756c09e6 2571 if (r == 0)
4298d0b5
LP
2572 continue;
2573 if (r < 0)
2574 return log_oom();
2575 } else
2576 set_remove(c->address_families, INT_TO_PTR(af));
2577 }
b2fadec6
ZJS
2578 if (!isempty(state))
2579 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2580 "Trailing garbage, ignoring.");
4298d0b5
LP
2581
2582 return 0;
2583}
c0467cf3 2584#endif
8351ceae 2585
a016b922
LP
2586int config_parse_unit_slice(
2587 const char *unit,
2588 const char *filename,
2589 unsigned line,
2590 const char *section,
71a61510 2591 unsigned section_line,
a016b922
LP
2592 const char *lvalue,
2593 int ltype,
2594 const char *rvalue,
2595 void *data,
2596 void *userdata) {
2597
2598 _cleanup_free_ char *k = NULL;
2599 Unit *u = userdata, *slice;
2600 int r;
2601
2602 assert(filename);
2603 assert(lvalue);
2604 assert(rvalue);
2605 assert(u);
2606
19f6d710
LP
2607 r = unit_name_printf(u, rvalue, &k);
2608 if (r < 0)
2609 log_syntax(unit, LOG_ERR, filename, line, -r,
a016b922 2610 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
19f6d710
LP
2611 if (!k) {
2612 k = strdup(rvalue);
2613 if (!k)
2614 return log_oom();
2615 }
a016b922 2616
19f6d710 2617 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
a016b922
LP
2618 if (r < 0) {
2619 log_syntax(unit, LOG_ERR, filename, line, -r,
19f6d710 2620 "Failed to load slice unit %s. Ignoring.", k);
a016b922
LP
2621 return 0;
2622 }
2623
2624 if (slice->type != UNIT_SLICE) {
2625 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
19f6d710 2626 "Slice unit %s is not a slice. Ignoring.", k);
a016b922
LP
2627 return 0;
2628 }
2629
2630 unit_ref_set(&u->slice, slice);
2631 return 0;
2632}
2633
4ad49000
LP
2634DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2635
2636int config_parse_cpu_shares(
2637 const char *unit,
2638 const char *filename,
2639 unsigned line,
2640 const char *section,
71a61510 2641 unsigned section_line,
4ad49000
LP
2642 const char *lvalue,
2643 int ltype,
2644 const char *rvalue,
2645 void *data,
2646 void *userdata) {
2647
db785129 2648 unsigned long *shares = data, lu;
95ae05c0
WC
2649 int r;
2650
2651 assert(filename);
2652 assert(lvalue);
2653 assert(rvalue);
2654
2655 if (isempty(rvalue)) {
db785129 2656 *shares = (unsigned long) -1;
95ae05c0
WC
2657 return 0;
2658 }
2659
2660 r = safe_atolu(rvalue, &lu);
2661 if (r < 0 || lu <= 0) {
1e2fd62d
ZJS
2662 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2663 "CPU shares '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
2664 return 0;
2665 }
2666
db785129 2667 *shares = lu;
4ad49000
LP
2668 return 0;
2669}
2670
b2f8b02e
LP
2671int config_parse_cpu_quota(
2672 const char *unit,
2673 const char *filename,
2674 unsigned line,
2675 const char *section,
2676 unsigned section_line,
2677 const char *lvalue,
2678 int ltype,
2679 const char *rvalue,
2680 void *data,
2681 void *userdata) {
2682
2683 CGroupContext *c = data;
9a054909 2684 double percent;
b2f8b02e
LP
2685
2686 assert(filename);
2687 assert(lvalue);
2688 assert(rvalue);
2689
2690 if (isempty(rvalue)) {
3a43da28 2691 c->cpu_quota_per_sec_usec = USEC_INFINITY;
b2f8b02e
LP
2692 return 0;
2693 }
2694
9a054909 2695 if (!endswith(rvalue, "%")) {
b2f8b02e 2696
1e2fd62d
ZJS
2697 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2698 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
9a054909
LP
2699 return 0;
2700 }
b2f8b02e 2701
9a054909 2702 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
1e2fd62d
ZJS
2703 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2704 "CPU quota '%s' invalid. Ignoring.", rvalue);
9a054909 2705 return 0;
b2f8b02e
LP
2706 }
2707
9a054909
LP
2708 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2709
b2f8b02e
LP
2710 return 0;
2711}
2712
4ad49000
LP
2713int config_parse_memory_limit(
2714 const char *unit,
2715 const char *filename,
2716 unsigned line,
2717 const char *section,
71a61510 2718 unsigned section_line,
4ad49000
LP
2719 const char *lvalue,
2720 int ltype,
2721 const char *rvalue,
2722 void *data,
2723 void *userdata) {
2724
2725 CGroupContext *c = data;
4ad49000
LP
2726 off_t bytes;
2727 int r;
2728
4ad49000 2729 if (isempty(rvalue)) {
ddca82ac 2730 c->memory_limit = (uint64_t) -1;
4ad49000
LP
2731 return 0;
2732 }
2733
2734 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2735
5556b5fe 2736 r = parse_size(rvalue, 1024, &bytes);
4ad49000 2737 if (r < 0) {
1e2fd62d
ZJS
2738 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2739 "Memory limit '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
2740 return 0;
2741 }
2742
ddca82ac 2743 c->memory_limit = (uint64_t) bytes;
4ad49000
LP
2744 return 0;
2745}
2746
2747int config_parse_device_allow(
2748 const char *unit,
2749 const char *filename,
2750 unsigned line,
2751 const char *section,
71a61510 2752 unsigned section_line,
4ad49000
LP
2753 const char *lvalue,
2754 int ltype,
2755 const char *rvalue,
2756 void *data,
2757 void *userdata) {
2758
2759 _cleanup_free_ char *path = NULL;
2760 CGroupContext *c = data;
2761 CGroupDeviceAllow *a;
2762 const char *m;
2763 size_t n;
2764
2765 if (isempty(rvalue)) {
2766 while (c->device_allow)
2767 cgroup_context_free_device_allow(c, c->device_allow);
2768
2769 return 0;
2770 }
2771
2772 n = strcspn(rvalue, WHITESPACE);
2773 path = strndup(rvalue, n);
2774 if (!path)
2775 return log_oom();
2776
90060676
LP
2777 if (!startswith(path, "/dev/") &&
2778 !startswith(path, "block-") &&
2779 !startswith(path, "char-")) {
1e2fd62d
ZJS
2780 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2781 "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
2782 return 0;
2783 }
2784
2785 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2786 if (isempty(m))
2787 m = "rwm";
2788
2789 if (!in_charset(m, "rwm")) {
1e2fd62d
ZJS
2790 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2791 "Invalid device rights '%s'. Ignoring.", m);
4ad49000
LP
2792 return 0;
2793 }
2794
2795 a = new0(CGroupDeviceAllow, 1);
2796 if (!a)
2797 return log_oom();
2798
2799 a->path = path;
2800 path = NULL;
2801 a->r = !!strchr(m, 'r');
2802 a->w = !!strchr(m, 'w');
2803 a->m = !!strchr(m, 'm');
2804
71fda00f 2805 LIST_PREPEND(device_allow, c->device_allow, a);
4ad49000
LP
2806 return 0;
2807}
2808
2809int config_parse_blockio_weight(
2810 const char *unit,
2811 const char *filename,
2812 unsigned line,
2813 const char *section,
71a61510 2814 unsigned section_line,
4ad49000
LP
2815 const char *lvalue,
2816 int ltype,
2817 const char *rvalue,
2818 void *data,
2819 void *userdata) {
2820
db785129 2821 unsigned long *weight = data, lu;
95ae05c0
WC
2822 int r;
2823
2824 assert(filename);
2825 assert(lvalue);
2826 assert(rvalue);
2827
2828 if (isempty(rvalue)) {
db785129 2829 *weight = (unsigned long) -1;
95ae05c0
WC
2830 return 0;
2831 }
2832
2833 r = safe_atolu(rvalue, &lu);
2834 if (r < 0 || lu < 10 || lu > 1000) {
1e2fd62d
ZJS
2835 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2836 "Block IO weight '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
2837 return 0;
2838 }
2839
db785129 2840 *weight = lu;
8e7076ca
LP
2841 return 0;
2842}
2843
2844int config_parse_blockio_device_weight(
2845 const char *unit,
2846 const char *filename,
2847 unsigned line,
2848 const char *section,
71a61510 2849 unsigned section_line,
8e7076ca
LP
2850 const char *lvalue,
2851 int ltype,
2852 const char *rvalue,
2853 void *data,
2854 void *userdata) {
2855
4ad49000 2856 _cleanup_free_ char *path = NULL;
8e7076ca 2857 CGroupBlockIODeviceWeight *w;
4ad49000
LP
2858 CGroupContext *c = data;
2859 unsigned long lu;
2860 const char *weight;
2861 size_t n;
2862 int r;
2863
2864 assert(filename);
2865 assert(lvalue);
2866 assert(rvalue);
2867
2868 if (isempty(rvalue)) {
4ad49000
LP
2869 while (c->blockio_device_weights)
2870 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2871
2872 return 0;
2873 }
2874
2875 n = strcspn(rvalue, WHITESPACE);
2876 weight = rvalue + n;
8e7076ca 2877 if (!*weight) {
1e2fd62d
ZJS
2878 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2879 "Expected block device and device weight. Ignoring.");
8e7076ca
LP
2880 return 0;
2881 }
4ad49000 2882
8e7076ca
LP
2883 path = strndup(rvalue, n);
2884 if (!path)
2885 return log_oom();
4ad49000 2886
8e7076ca 2887 if (!path_startswith(path, "/dev")) {
1e2fd62d
ZJS
2888 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2889 "Invalid device node path '%s'. Ignoring.", path);
8e7076ca
LP
2890 return 0;
2891 }
4ad49000 2892
8e7076ca 2893 weight += strspn(weight, WHITESPACE);
4ad49000
LP
2894 r = safe_atolu(weight, &lu);
2895 if (r < 0 || lu < 10 || lu > 1000) {
1e2fd62d
ZJS
2896 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2897 "Block IO weight '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
2898 return 0;
2899 }
2900
8e7076ca
LP
2901 w = new0(CGroupBlockIODeviceWeight, 1);
2902 if (!w)
2903 return log_oom();
4ad49000 2904
8e7076ca
LP
2905 w->path = path;
2906 path = NULL;
4ad49000 2907
8e7076ca 2908 w->weight = lu;
4ad49000 2909
71fda00f 2910 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
2911 return 0;
2912}
2913
2914int config_parse_blockio_bandwidth(
2915 const char *unit,
2916 const char *filename,
2917 unsigned line,
2918 const char *section,
71a61510 2919 unsigned section_line,
4ad49000
LP
2920 const char *lvalue,
2921 int ltype,
2922 const char *rvalue,
2923 void *data,
2924 void *userdata) {
2925
2926 _cleanup_free_ char *path = NULL;
2927 CGroupBlockIODeviceBandwidth *b;
2928 CGroupContext *c = data;
2929 const char *bandwidth;
2930 off_t bytes;
47c0980d 2931 bool read;
4ad49000
LP
2932 size_t n;
2933 int r;
2934
2935 assert(filename);
2936 assert(lvalue);
2937 assert(rvalue);
2938
47c0980d
G
2939 read = streq("BlockIOReadBandwidth", lvalue);
2940
4ad49000 2941 if (isempty(rvalue)) {
47c0980d
G
2942 CGroupBlockIODeviceBandwidth *next;
2943
2944 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2945 if (b->read == read)
2946 cgroup_context_free_blockio_device_bandwidth(c, b);
4ad49000
LP
2947
2948 return 0;
2949 }
2950
2951 n = strcspn(rvalue, WHITESPACE);
2952 bandwidth = rvalue + n;
2953 bandwidth += strspn(bandwidth, WHITESPACE);
2954
2955 if (!*bandwidth) {
2956 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2957 "Expected space separated pair of device node and bandwidth. Ignoring.");
2958 return 0;
2959 }
2960
2961 path = strndup(rvalue, n);
2962 if (!path)
2963 return log_oom();
2964
2965 if (!path_startswith(path, "/dev")) {
2966 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2967 "Invalid device node path '%s'. Ignoring.", path);
2968 return 0;
2969 }
2970
5556b5fe 2971 r = parse_size(bandwidth, 1000, &bytes);
4ad49000 2972 if (r < 0 || bytes <= 0) {
1e2fd62d
ZJS
2973 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2974 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
2975 return 0;
2976 }
2977
2978 b = new0(CGroupBlockIODeviceBandwidth, 1);
2979 if (!b)
2980 return log_oom();
2981
2982 b->path = path;
2983 path = NULL;
2984 b->bandwidth = (uint64_t) bytes;
47c0980d 2985 b->read = read;
4ad49000 2986
71fda00f 2987 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
4ad49000
LP
2988
2989 return 0;
2990}
2991
d420282b
LP
2992DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2993
2994int config_parse_job_mode_isolate(
2995 const char *unit,
2996 const char *filename,
2997 unsigned line,
2998 const char *section,
2999 unsigned section_line,
3000 const char *lvalue,
3001 int ltype,
3002 const char *rvalue,
3003 void *data,
3004 void *userdata) {
3005
3006 JobMode *m = data;
3007 int r;
3008
3009 assert(filename);
3010 assert(lvalue);
3011 assert(rvalue);
3012
3013 r = parse_boolean(rvalue);
3014 if (r < 0) {
1e2fd62d
ZJS
3015 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3016 "Failed to parse boolean, ignoring: %s", rvalue);
d420282b
LP
3017 return 0;
3018 }
3019
3020 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3021 return 0;
3022}
3023
ac45f971
LP
3024int config_parse_personality(
3025 const char *unit,
3026 const char *filename,
3027 unsigned line,
3028 const char *section,
3029 unsigned section_line,
3030 const char *lvalue,
3031 int ltype,
3032 const char *rvalue,
3033 void *data,
3034 void *userdata) {
3035
3036 unsigned long *personality = data, p;
3037
3038 assert(filename);
3039 assert(lvalue);
3040 assert(rvalue);
3041 assert(personality);
3042
3043 p = personality_from_string(rvalue);
3044 if (p == 0xffffffffUL) {
3045 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3046 "Failed to parse personality, ignoring: %s", rvalue);
3047 return 0;
3048 }
3049
3050 *personality = p;
3051 return 0;
3052}
3053
e66cf1a3
LP
3054int config_parse_runtime_directory(
3055 const char *unit,
3056 const char *filename,
3057 unsigned line,
3058 const char *section,
3059 unsigned section_line,
3060 const char *lvalue,
3061 int ltype,
3062 const char *rvalue,
3063 void *data,
3064 void *userdata) {
3065
a2a5291b
ZJS
3066 char***rt = data;
3067 const char *word, *state;
e66cf1a3
LP
3068 size_t l;
3069 int r;
3070
3071 assert(filename);
3072 assert(lvalue);
3073 assert(rvalue);
3074 assert(data);
3075
3076 if (isempty(rvalue)) {
3077 /* Empty assignment resets the list */
3078 strv_free(*rt);
3079 *rt = NULL;
3080 return 0;
3081 }
3082
a2a5291b 3083 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
e66cf1a3
LP
3084 _cleanup_free_ char *n;
3085
a2a5291b 3086 n = strndup(word, l);
e66cf1a3
LP
3087 if (!n)
3088 return log_oom();
3089
ae6c3cc0 3090 if (!filename_is_valid(n)) {
1e2fd62d
ZJS
3091 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3092 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
e66cf1a3
LP
3093 continue;
3094 }
3095
3096 r = strv_push(rt, n);
3097 if (r < 0)
3098 return log_oom();
3099
3100 n = NULL;
3101 }
b2fadec6
ZJS
3102 if (!isempty(state))
3103 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3104 "Trailing garbage, ignoring.");
e66cf1a3
LP
3105
3106 return 0;
3107}
3108
3af00fb8
LP
3109int config_parse_set_status(
3110 const char *unit,
3111 const char *filename,
3112 unsigned line,
3113 const char *section,
3114 unsigned section_line,
3115 const char *lvalue,
3116 int ltype,
3117 const char *rvalue,
3118 void *data,
3119 void *userdata) {
3120
3af00fb8 3121 size_t l;
a2a5291b 3122 const char *word, *state;
3af00fb8
LP
3123 int r;
3124 ExitStatusSet *status_set = data;
3125
3126 assert(filename);
3127 assert(lvalue);
3128 assert(rvalue);
3129 assert(data);
3130
3e2d435b 3131 /* Empty assignment resets the list */
3af00fb8 3132 if (isempty(rvalue)) {
3e2d435b 3133 exit_status_set_free(status_set);
3af00fb8
LP
3134 return 0;
3135 }
3136
a2a5291b 3137 FOREACH_WORD(word, l, rvalue, state) {
3af00fb8
LP
3138 _cleanup_free_ char *temp;
3139 int val;
61593865 3140 Set **set;
3af00fb8 3141
a2a5291b 3142 temp = strndup(word, l);
3af00fb8
LP
3143 if (!temp)
3144 return log_oom();
3145
3146 r = safe_atoi(temp, &val);
3147 if (r < 0) {
3148 val = signal_from_string_try_harder(temp);
3149
1e2fd62d
ZJS
3150 if (val <= 0) {
3151 log_syntax(unit, LOG_ERR, filename, line, -val,
3152 "Failed to parse value, ignoring: %s", word);
61593865 3153 continue;
3af00fb8 3154 }
61593865 3155 set = &status_set->signal;
3af00fb8 3156 } else {
1e2fd62d
ZJS
3157 if (val < 0 || val > 255) {
3158 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3159 "Value %d is outside range 0-255, ignoring", val);
3160 continue;
3af00fb8 3161 }
61593865 3162 set = &status_set->status;
3af00fb8 3163 }
1e2fd62d 3164
61593865 3165 r = set_ensure_allocated(set, NULL);
1e2fd62d
ZJS
3166 if (r < 0)
3167 return log_oom();
3168
61593865 3169 r = set_put(*set, INT_TO_PTR(val));
1e2fd62d
ZJS
3170 if (r < 0) {
3171 log_syntax(unit, LOG_ERR, filename, line, -r,
3172 "Unable to store: %s", word);
3173 return r;
3174 }
3af00fb8 3175 }
b2fadec6
ZJS
3176 if (!isempty(state))
3177 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3178 "Trailing garbage, ignoring.");
3af00fb8
LP
3179
3180 return 0;
3181}
3182
94828d2d
LP
3183int config_parse_namespace_path_strv(
3184 const char *unit,
3185 const char *filename,
3186 unsigned line,
3187 const char *section,
3188 unsigned section_line,
3189 const char *lvalue,
3190 int ltype,
3191 const char *rvalue,
3192 void *data,
3193 void *userdata) {
3194
a2a5291b
ZJS
3195 char*** sv = data;
3196 const char *word, *state;
94828d2d
LP
3197 size_t l;
3198 int r;
3199
3200 assert(filename);
3201 assert(lvalue);
3202 assert(rvalue);
3203 assert(data);
3204
3205 if (isempty(rvalue)) {
3206 /* Empty assignment resets the list */
3207 strv_free(*sv);
3208 *sv = NULL;
3209 return 0;
3210 }
3211
a2a5291b 3212 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
94828d2d
LP
3213 _cleanup_free_ char *n;
3214 int offset;
3215
a2a5291b 3216 n = strndup(word, l);
94828d2d
LP
3217 if (!n)
3218 return log_oom();
3219
3220 if (!utf8_is_valid(n)) {
b5d74213 3221 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
94828d2d
LP
3222 continue;
3223 }
3224
3225 offset = n[0] == '-';
3226 if (!path_is_absolute(n + offset)) {
1e2fd62d
ZJS
3227 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3228 "Not an absolute path, ignoring: %s", rvalue);
94828d2d
LP
3229 continue;
3230 }
3231
3232 path_kill_slashes(n);
3233
3234 r = strv_push(sv, n);
3235 if (r < 0)
3236 return log_oom();
3237
3238 n = NULL;
3239 }
b2fadec6
ZJS
3240 if (!isempty(state))
3241 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3242 "Trailing garbage, ignoring.");
94828d2d
LP
3243
3244 return 0;
3245}
3246
f1721625 3247int config_parse_no_new_privileges(
760b9d7c
LP
3248 const char* unit,
3249 const char *filename,
3250 unsigned line,
3251 const char *section,
3252 unsigned section_line,
3253 const char *lvalue,
3254 int ltype,
3255 const char *rvalue,
3256 void *data,
3257 void *userdata) {
3258
3259 ExecContext *c = data;
3260 int k;
3261
3262 assert(filename);
3263 assert(lvalue);
3264 assert(rvalue);
3265 assert(data);
3266
3267 k = parse_boolean(rvalue);
3268 if (k < 0) {
1e2fd62d
ZJS
3269 log_syntax(unit, LOG_ERR, filename, line, -k,
3270 "Failed to parse boolean value, ignoring: %s", rvalue);
760b9d7c
LP
3271 return 0;
3272 }
3273
3274 c->no_new_privileges = !!k;
3275 c->no_new_privileges_set = true;
3276
3277 return 0;
3278}
3279
1b8689f9 3280int config_parse_protect_home(
417116f2
LP
3281 const char* unit,
3282 const char *filename,
3283 unsigned line,
3284 const char *section,
3285 unsigned section_line,
3286 const char *lvalue,
3287 int ltype,
3288 const char *rvalue,
3289 void *data,
3290 void *userdata) {
3291
3292 ExecContext *c = data;
3293 int k;
3294
3295 assert(filename);
3296 assert(lvalue);
3297 assert(rvalue);
3298 assert(data);
3299
3300 /* Our enum shall be a superset of booleans, hence first try
3301 * to parse as as boolean, and then as enum */
3302
3303 k = parse_boolean(rvalue);
3304 if (k > 0)
1b8689f9 3305 c->protect_home = PROTECT_HOME_YES;
417116f2 3306 else if (k == 0)
1b8689f9 3307 c->protect_home = PROTECT_HOME_NO;
417116f2 3308 else {
1b8689f9 3309 ProtectHome h;
417116f2 3310
1b8689f9 3311 h = protect_home_from_string(rvalue);
417116f2 3312 if (h < 0){
1e2fd62d
ZJS
3313 log_syntax(unit, LOG_ERR, filename, line, -h,
3314 "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
3315 return 0;
3316 }
3317
1b8689f9
LP
3318 c->protect_home = h;
3319 }
3320
3321 return 0;
3322}
3323
3324int config_parse_protect_system(
3325 const char* unit,
3326 const char *filename,
3327 unsigned line,
3328 const char *section,
3329 unsigned section_line,
3330 const char *lvalue,
3331 int ltype,
3332 const char *rvalue,
3333 void *data,
3334 void *userdata) {
3335
3336 ExecContext *c = data;
3337 int k;
3338
3339 assert(filename);
3340 assert(lvalue);
3341 assert(rvalue);
3342 assert(data);
3343
3344 /* Our enum shall be a superset of booleans, hence first try
3345 * to parse as as boolean, and then as enum */
3346
3347 k = parse_boolean(rvalue);
3348 if (k > 0)
3349 c->protect_system = PROTECT_SYSTEM_YES;
3350 else if (k == 0)
3351 c->protect_system = PROTECT_SYSTEM_NO;
3352 else {
3353 ProtectSystem s;
3354
3355 s = protect_system_from_string(rvalue);
3356 if (s < 0){
1e2fd62d
ZJS
3357 log_syntax(unit, LOG_ERR, filename, line, -s,
3358 "Failed to parse protect system value, ignoring: %s", rvalue);
1b8689f9
LP
3359 return 0;
3360 }
3361
3362 c->protect_system = s;
417116f2
LP
3363 }
3364
3365 return 0;
3366}
3367
071830ff 3368#define FOLLOW_MAX 8
87f0e418 3369
9e2f7c11 3370static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
0301abf4 3371 unsigned c = 0;
87f0e418
LP
3372 int fd, r;
3373 FILE *f;
0301abf4 3374 char *id = NULL;
87f0e418
LP
3375
3376 assert(filename);
3377 assert(*filename);
3378 assert(_f);
3379 assert(names);
3380
0301abf4
LP
3381 /* This will update the filename pointer if the loaded file is
3382 * reached by a symlink. The old string will be freed. */
87f0e418 3383
0301abf4 3384 for (;;) {
2c7108c4 3385 char *target, *name;
87f0e418 3386
0301abf4
LP
3387 if (c++ >= FOLLOW_MAX)
3388 return -ELOOP;
3389
b08d03ff
LP
3390 path_kill_slashes(*filename);
3391
87f0e418 3392 /* Add the file name we are currently looking at to
8f05424d
LP
3393 * the names of this unit, but only if it is a valid
3394 * unit name. */
2b6bf07d 3395 name = basename(*filename);
87f0e418 3396
7410616c 3397 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
8f05424d 3398
15e11d81
LP
3399 id = set_get(names, name);
3400 if (!id) {
3401 id = strdup(name);
3402 if (!id)
8f05424d 3403 return -ENOMEM;
87f0e418 3404
ef42202a
ZJS
3405 r = set_consume(names, id);
3406 if (r < 0)
8f05424d 3407 return r;
87f0e418 3408 }
87f0e418
LP
3409 }
3410
0301abf4 3411 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
3412 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3413 if (fd >= 0)
87f0e418
LP
3414 break;
3415
0301abf4
LP
3416 if (errno != ELOOP)
3417 return -errno;
3418
87f0e418 3419 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
3420 r = readlink_and_make_absolute(*filename, &target);
3421 if (r < 0)
0301abf4 3422 return r;
87f0e418 3423
0301abf4 3424 free(*filename);
2c7108c4 3425 *filename = target;
87f0e418
LP
3426 }
3427
9946996c
LP
3428 f = fdopen(fd, "re");
3429 if (!f) {
03e334a1 3430 safe_close(fd);
d4ad27a1 3431 return -errno;
87f0e418
LP
3432 }
3433
3434 *_f = f;
9e2f7c11 3435 *_final = id;
0301abf4 3436 return 0;
87f0e418
LP
3437}
3438
23a177ef
LP
3439static int merge_by_names(Unit **u, Set *names, const char *id) {
3440 char *k;
3441 int r;
3442
3443 assert(u);
3444 assert(*u);
3445 assert(names);
3446
3447 /* Let's try to add in all symlink names we found */
3448 while ((k = set_steal_first(names))) {
3449
3450 /* First try to merge in the other name into our
3451 * unit */
9946996c
LP
3452 r = unit_merge_by_name(*u, k);
3453 if (r < 0) {
23a177ef
LP
3454 Unit *other;
3455
3456 /* Hmm, we couldn't merge the other unit into
3457 * ours? Then let's try it the other way
3458 * round */
3459
ac155bb8 3460 other = manager_get_unit((*u)->manager, k);
23a177ef
LP
3461 free(k);
3462
9946996c
LP
3463 if (other) {
3464 r = unit_merge(other, *u);
3465 if (r >= 0) {
23a177ef
LP
3466 *u = other;
3467 return merge_by_names(u, names, NULL);
3468 }
9946996c 3469 }
23a177ef
LP
3470
3471 return r;
3472 }
3473
3474 if (id == k)
3475 unit_choose_id(*u, id);
3476
3477 free(k);
3478 }
3479
3480 return 0;
3481}
3482
e537352b 3483static int load_from_path(Unit *u, const char *path) {
0301abf4 3484 int r;
e48614c4
ZJS
3485 _cleanup_set_free_free_ Set *symlink_names = NULL;
3486 _cleanup_fclose_ FILE *f = NULL;
3487 _cleanup_free_ char *filename = NULL;
3488 char *id = NULL;
23a177ef 3489 Unit *merged;
45fb0699 3490 struct stat st;
23a177ef
LP
3491
3492 assert(u);
e537352b 3493 assert(path);
3efd4195 3494
d5099efc 3495 symlink_names = set_new(&string_hash_ops);
f975e971 3496 if (!symlink_names)
87f0e418 3497 return -ENOMEM;
3efd4195 3498
036643a2
LP
3499 if (path_is_absolute(path)) {
3500
9946996c 3501 filename = strdup(path);
e48614c4
ZJS
3502 if (!filename)
3503 return -ENOMEM;
036643a2 3504
9946996c
LP
3505 r = open_follow(&filename, &f, symlink_names, &id);
3506 if (r < 0) {
036643a2
LP
3507 free(filename);
3508 filename = NULL;
3509
3510 if (r != -ENOENT)
e48614c4 3511 return r;
036643a2
LP
3512 }
3513
3514 } else {
3515 char **p;
3516
ac155bb8 3517 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
036643a2
LP
3518
3519 /* Instead of opening the path right away, we manually
3520 * follow all symlinks and add their name to our unit
3521 * name set while doing so */
9946996c 3522 filename = path_make_absolute(path, *p);
e48614c4
ZJS
3523 if (!filename)
3524 return -ENOMEM;
036643a2 3525
ac155bb8
MS
3526 if (u->manager->unit_path_cache &&
3527 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
3528 r = -ENOENT;
3529 else
3530 r = open_follow(&filename, &f, symlink_names, &id);
3531
3532 if (r < 0) {
036643a2
LP
3533 free(filename);
3534 filename = NULL;
3535
3536 if (r != -ENOENT)
e48614c4 3537 return r;
036643a2
LP
3538
3539 /* Empty the symlink names for the next run */
9946996c 3540 set_clear_free(symlink_names);
036643a2
LP
3541 continue;
3542 }
3543
3544 break;
3545 }
3546 }
034c6ed7 3547
e48614c4 3548 if (!filename)
8f05424d 3549 /* Hmm, no suitable file found? */
e48614c4 3550 return 0;
87f0e418 3551
23a177ef 3552 merged = u;
9946996c
LP
3553 r = merge_by_names(&merged, symlink_names, id);
3554 if (r < 0)
e48614c4 3555 return r;
87f0e418 3556
23a177ef 3557 if (merged != u) {
ac155bb8 3558 u->load_state = UNIT_MERGED;
e48614c4 3559 return 0;
034c6ed7
LP
3560 }
3561
e48614c4
ZJS
3562 if (fstat(fileno(f), &st) < 0)
3563 return -errno;
45fb0699 3564
00dc5d76 3565 if (null_or_empty(&st))
ac155bb8 3566 u->load_state = UNIT_MASKED;
00dc5d76 3567 else {
c2756a68
LP
3568 u->load_state = UNIT_LOADED;
3569
00dc5d76 3570 /* Now, parse the file contents */
36f822c4
ZJS
3571 r = config_parse(u->id, filename, f,
3572 UNIT_VTABLE(u)->sections,
3573 config_item_perf_lookup, load_fragment_gperf_lookup,
3574 false, true, false, u);
f975e971 3575 if (r < 0)
e48614c4 3576 return r;
00dc5d76 3577 }
b08d03ff 3578
ac155bb8
MS
3579 free(u->fragment_path);
3580 u->fragment_path = filename;
0301abf4 3581 filename = NULL;
87f0e418 3582
ac155bb8 3583 u->fragment_mtime = timespec_load(&st.st_mtim);
45fb0699 3584
1b64d026
LP
3585 if (u->source_path) {
3586 if (stat(u->source_path, &st) >= 0)
3587 u->source_mtime = timespec_load(&st.st_mtim);
3588 else
3589 u->source_mtime = 0;
3590 }
3591
e48614c4 3592 return 0;
0301abf4
LP
3593}
3594
e537352b 3595int unit_load_fragment(Unit *u) {
23a177ef 3596 int r;
294d81f1
LP
3597 Iterator i;
3598 const char *t;
0301abf4
LP
3599
3600 assert(u);
ac155bb8
MS
3601 assert(u->load_state == UNIT_STUB);
3602 assert(u->id);
23a177ef 3603
294d81f1
LP
3604 /* First, try to find the unit under its id. We always look
3605 * for unit files in the default directories, to make it easy
3606 * to override things by placing things in /etc/systemd/system */
9946996c
LP
3607 r = load_from_path(u, u->id);
3608 if (r < 0)
294d81f1
LP
3609 return r;
3610
3611 /* Try to find an alias we can load this with */
abc08d4d 3612 if (u->load_state == UNIT_STUB) {
ac155bb8 3613 SET_FOREACH(t, u->names, i) {
294d81f1 3614
ac155bb8 3615 if (t == u->id)
294d81f1
LP
3616 continue;
3617
9946996c
LP
3618 r = load_from_path(u, t);
3619 if (r < 0)
294d81f1
LP
3620 return r;
3621
ac155bb8 3622 if (u->load_state != UNIT_STUB)
294d81f1
LP
3623 break;
3624 }
abc08d4d 3625 }
23a177ef 3626
294d81f1 3627 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 3628 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 3629
9946996c
LP
3630 r = load_from_path(u, u->fragment_path);
3631 if (r < 0)
23a177ef 3632 return r;
0301abf4 3633
ac155bb8 3634 if (u->load_state == UNIT_STUB) {
6ccb1b44
LP
3635 /* Hmm, this didn't work? Then let's get rid
3636 * of the fragment path stored for us, so that
3637 * we don't point to an invalid location. */
ac155bb8
MS
3638 free(u->fragment_path);
3639 u->fragment_path = NULL;
6ccb1b44
LP
3640 }
3641 }
3642
294d81f1 3643 /* Look for a template */
ac155bb8 3644 if (u->load_state == UNIT_STUB && u->instance) {
7410616c 3645 _cleanup_free_ char *k = NULL;
294d81f1 3646
7410616c
LP
3647 r = unit_name_template(u->id, &k);
3648 if (r < 0)
3649 return r;
294d81f1
LP
3650
3651 r = load_from_path(u, k);
294d81f1 3652 if (r < 0)
9e2f7c11 3653 return r;
890f434c 3654
abc08d4d 3655 if (u->load_state == UNIT_STUB) {
ac155bb8 3656 SET_FOREACH(t, u->names, i) {
bc9fd78c 3657 _cleanup_free_ char *z = NULL;
87f0e418 3658
ac155bb8 3659 if (t == u->id)
23a177ef 3660 continue;
071830ff 3661
7410616c
LP
3662 r = unit_name_template(t, &z);
3663 if (r < 0)
3664 return r;
294d81f1 3665
bc9fd78c 3666 r = load_from_path(u, z);
294d81f1 3667 if (r < 0)
23a177ef 3668 return r;
890f434c 3669
ac155bb8 3670 if (u->load_state != UNIT_STUB)
23a177ef
LP
3671 break;
3672 }
abc08d4d 3673 }
071830ff
LP
3674 }
3675
23a177ef 3676 return 0;
3efd4195 3677}
e537352b
LP
3678
3679void unit_dump_config_items(FILE *f) {
f975e971
LP
3680 static const struct {
3681 const ConfigParserCallback callback;
3682 const char *rvalue;
3683 } table[] = {
7f8aa671 3684#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
3685 { config_parse_warn_compat, "NOTSUPPORTED" },
3686#endif
f975e971
LP
3687 { config_parse_int, "INTEGER" },
3688 { config_parse_unsigned, "UNSIGNED" },
5556b5fe
LP
3689 { config_parse_iec_size, "SIZE" },
3690 { config_parse_iec_off, "SIZE" },
3691 { config_parse_si_size, "SIZE" },
f975e971
LP
3692 { config_parse_bool, "BOOLEAN" },
3693 { config_parse_string, "STRING" },
3694 { config_parse_path, "PATH" },
3695 { config_parse_unit_path_printf, "PATH" },
3696 { config_parse_strv, "STRING [...]" },
3697 { config_parse_exec_nice, "NICE" },
3698 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3699 { config_parse_exec_io_class, "IOCLASS" },
3700 { config_parse_exec_io_priority, "IOPRIORITY" },
3701 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3702 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3703 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3704 { config_parse_mode, "MODE" },
3705 { config_parse_unit_env_file, "FILE" },
3706 { config_parse_output, "OUTPUT" },
3707 { config_parse_input, "INPUT" },
ca37242e
LP
3708 { config_parse_log_facility, "FACILITY" },
3709 { config_parse_log_level, "LEVEL" },
f975e971
LP
3710 { config_parse_exec_capabilities, "CAPABILITIES" },
3711 { config_parse_exec_secure_bits, "SECUREBITS" },
ec8927ca 3712 { config_parse_bounding_set, "BOUNDINGSET" },
f975e971 3713 { config_parse_limit, "LIMIT" },
f975e971 3714 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
3715 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3716 { config_parse_service_type, "SERVICETYPE" },
3717 { config_parse_service_restart, "SERVICERESTART" },
3718#ifdef HAVE_SYSV_COMPAT
3719 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
3720#endif
3721 { config_parse_kill_mode, "KILLMODE" },
3722 { config_parse_kill_signal, "SIGNAL" },
3723 { config_parse_socket_listen, "SOCKET [...]" },
3724 { config_parse_socket_bind, "SOCKETBIND" },
3725 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 3726 { config_parse_sec, "SECONDS" },
d88a251b 3727 { config_parse_nsec, "NANOSECONDS" },
94828d2d 3728 { config_parse_namespace_path_strv, "PATH [...]" },
7c8fa05c 3729 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
3730 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3731 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 3732 { config_parse_trigger_unit, "UNIT" },
f975e971 3733 { config_parse_timer, "TIMER" },
f975e971 3734 { config_parse_path_spec, "PATH" },
f975e971
LP
3735 { config_parse_notify_access, "ACCESS" },
3736 { config_parse_ip_tos, "TOS" },
3737 { config_parse_unit_condition_path, "CONDITION" },
3738 { config_parse_unit_condition_string, "CONDITION" },
3739 { config_parse_unit_condition_null, "CONDITION" },
a016b922 3740 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
3741 { config_parse_documentation, "URL" },
3742 { config_parse_service_timeout, "SECONDS" },
bf500566 3743 { config_parse_failure_action, "ACTION" },
7f0386f6
LP
3744 { config_parse_set_status, "STATUS" },
3745 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 3746 { config_parse_environ, "ENVIRON" },
c0467cf3 3747#ifdef HAVE_SECCOMP
17df7223 3748 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 3749 { config_parse_syscall_archs, "ARCHS" },
17df7223 3750 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 3751 { config_parse_address_families, "FAMILIES" },
c0467cf3 3752#endif
7f0386f6
LP
3753 { config_parse_cpu_shares, "SHARES" },
3754 { config_parse_memory_limit, "LIMIT" },
3755 { config_parse_device_allow, "DEVICE" },
3756 { config_parse_device_policy, "POLICY" },
3757 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3758 { config_parse_blockio_weight, "WEIGHT" },
3759 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3760 { config_parse_long, "LONG" },
3761 { config_parse_socket_service, "SERVICE" },
6a6751fe
LP
3762#ifdef HAVE_SELINUX
3763 { config_parse_exec_selinux_context, "LABEL" },
3764#endif
3765 { config_parse_job_mode, "MODE" },
3766 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 3767 { config_parse_personality, "PERSONALITY" },
f975e971
LP
3768 };
3769
3770 const char *prev = NULL;
3771 const char *i;
3772
3773 assert(f);
e537352b 3774
f975e971
LP
3775 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3776 const char *rvalue = "OTHER", *lvalue;
3777 unsigned j;
3778 size_t prefix_len;
3779 const char *dot;
3780 const ConfigPerfItem *p;
3781
3782 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3783
3784 dot = strchr(i, '.');
3785 lvalue = dot ? dot + 1 : i;
3786 prefix_len = dot-i;
3787
3788 if (dot)
641906e9 3789 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
3790 if (prev)
3791 fputc('\n', f);
3792
3793 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3794 }
3795
3796 for (j = 0; j < ELEMENTSOF(table); j++)
3797 if (p->parse == table[j].callback) {
3798 rvalue = table[j].rvalue;
3799 break;
3800 }
3801
3802 fprintf(f, "%s=%s\n", lvalue, rvalue);
3803 prev = i;
3804 }
e537352b 3805}