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