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