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