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