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