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