]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
util: split out extract_first_word() and related calls into extract-word.[ch]
[thirdparty/systemd.git] / src / core / load-fragment.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3efd4195 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
bb112710 7 Copyright 2012 Holger Hans Peter Freyther
a7334b09
LP
8
9 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 17 Lesser General Public License for more details.
a7334b09 18
5430f7f2 19 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
3efd4195 23#include <errno.h>
87f0e418 24#include <fcntl.h>
25e870b5 25#include <linux/fs.h>
5f5d8eab 26#include <linux/oom.h>
618234a5
LP
27#ifdef HAVE_SECCOMP
28#include <seccomp.h>
29#endif
5f5d8eab
LP
30#include <sched.h>
31#include <string.h>
3d57c6ab 32#include <sys/resource.h>
5f5d8eab 33#include <sys/stat.h>
3efd4195 34
5f5d8eab
LP
35#include "af-list.h"
36#include "bus-error.h"
37#include "bus-internal.h"
38#include "bus-util.h"
39#include "cap-list.h"
40#include "cgroup.h"
3efd4195 41#include "conf-parser.h"
618234a5 42#include "cpu-set-util.h"
5f5d8eab
LP
43#include "env-util.h"
44#include "errno-list.h"
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 3195 char*** sv = data;
727f76d7
EV
3196 const char *prev;
3197 const char *cur;
94828d2d
LP
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
727f76d7
EV
3211 prev = cur = rvalue;
3212 for (;;) {
3213 _cleanup_free_ char *word = NULL;
94828d2d
LP
3214 int offset;
3215
727f76d7
EV
3216 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
3217 if (r < 0) {
3218 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring: %s", prev);
3219 return 0;
3220 }
3221 if (r == 0)
3222 break;
94828d2d 3223
727f76d7
EV
3224 if (!utf8_is_valid(word)) {
3225 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3226 prev = cur;
94828d2d
LP
3227 continue;
3228 }
3229
727f76d7
EV
3230 offset = word[0] == '-';
3231 if (!path_is_absolute(word + offset)) {
3232 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
3233 prev = cur;
94828d2d
LP
3234 continue;
3235 }
3236
727f76d7 3237 path_kill_slashes(word + offset);
94828d2d 3238
727f76d7 3239 r = strv_push(sv, word);
94828d2d
LP
3240 if (r < 0)
3241 return log_oom();
3242
727f76d7
EV
3243 prev = cur;
3244 word = NULL;
94828d2d
LP
3245 }
3246
3247 return 0;
3248}
3249
f1721625 3250int config_parse_no_new_privileges(
760b9d7c
LP
3251 const char* unit,
3252 const char *filename,
3253 unsigned line,
3254 const char *section,
3255 unsigned section_line,
3256 const char *lvalue,
3257 int ltype,
3258 const char *rvalue,
3259 void *data,
3260 void *userdata) {
3261
3262 ExecContext *c = data;
3263 int k;
3264
3265 assert(filename);
3266 assert(lvalue);
3267 assert(rvalue);
3268 assert(data);
3269
3270 k = parse_boolean(rvalue);
3271 if (k < 0) {
12ca818f 3272 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
760b9d7c
LP
3273 return 0;
3274 }
3275
3276 c->no_new_privileges = !!k;
3277 c->no_new_privileges_set = true;
3278
3279 return 0;
3280}
3281
1b8689f9 3282int config_parse_protect_home(
417116f2
LP
3283 const char* unit,
3284 const char *filename,
3285 unsigned line,
3286 const char *section,
3287 unsigned section_line,
3288 const char *lvalue,
3289 int ltype,
3290 const char *rvalue,
3291 void *data,
3292 void *userdata) {
3293
3294 ExecContext *c = data;
3295 int k;
3296
3297 assert(filename);
3298 assert(lvalue);
3299 assert(rvalue);
3300 assert(data);
3301
3302 /* Our enum shall be a superset of booleans, hence first try
3303 * to parse as as boolean, and then as enum */
3304
3305 k = parse_boolean(rvalue);
3306 if (k > 0)
1b8689f9 3307 c->protect_home = PROTECT_HOME_YES;
417116f2 3308 else if (k == 0)
1b8689f9 3309 c->protect_home = PROTECT_HOME_NO;
417116f2 3310 else {
1b8689f9 3311 ProtectHome h;
417116f2 3312
1b8689f9 3313 h = protect_home_from_string(rvalue);
417116f2 3314 if (h < 0){
12ca818f 3315 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
3316 return 0;
3317 }
3318
1b8689f9
LP
3319 c->protect_home = h;
3320 }
3321
3322 return 0;
3323}
3324
3325int config_parse_protect_system(
3326 const char* unit,
3327 const char *filename,
3328 unsigned line,
3329 const char *section,
3330 unsigned section_line,
3331 const char *lvalue,
3332 int ltype,
3333 const char *rvalue,
3334 void *data,
3335 void *userdata) {
3336
3337 ExecContext *c = data;
3338 int k;
3339
3340 assert(filename);
3341 assert(lvalue);
3342 assert(rvalue);
3343 assert(data);
3344
3345 /* Our enum shall be a superset of booleans, hence first try
3346 * to parse as as boolean, and then as enum */
3347
3348 k = parse_boolean(rvalue);
3349 if (k > 0)
3350 c->protect_system = PROTECT_SYSTEM_YES;
3351 else if (k == 0)
3352 c->protect_system = PROTECT_SYSTEM_NO;
3353 else {
3354 ProtectSystem s;
3355
3356 s = protect_system_from_string(rvalue);
3357 if (s < 0){
12ca818f 3358 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
1b8689f9
LP
3359 return 0;
3360 }
3361
3362 c->protect_system = s;
417116f2
LP
3363 }
3364
3365 return 0;
3366}
3367
071830ff 3368#define FOLLOW_MAX 8
87f0e418 3369
9e2f7c11 3370static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
0301abf4 3371 unsigned c = 0;
87f0e418
LP
3372 int fd, r;
3373 FILE *f;
0301abf4 3374 char *id = NULL;
87f0e418
LP
3375
3376 assert(filename);
3377 assert(*filename);
3378 assert(_f);
3379 assert(names);
3380
0301abf4
LP
3381 /* This will update the filename pointer if the loaded file is
3382 * reached by a symlink. The old string will be freed. */
87f0e418 3383
0301abf4 3384 for (;;) {
2c7108c4 3385 char *target, *name;
87f0e418 3386
0301abf4
LP
3387 if (c++ >= FOLLOW_MAX)
3388 return -ELOOP;
3389
b08d03ff
LP
3390 path_kill_slashes(*filename);
3391
87f0e418 3392 /* Add the file name we are currently looking at to
8f05424d
LP
3393 * the names of this unit, but only if it is a valid
3394 * unit name. */
2b6bf07d 3395 name = basename(*filename);
87f0e418 3396
7410616c 3397 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
8f05424d 3398
15e11d81
LP
3399 id = set_get(names, name);
3400 if (!id) {
3401 id = strdup(name);
3402 if (!id)
8f05424d 3403 return -ENOMEM;
87f0e418 3404
ef42202a
ZJS
3405 r = set_consume(names, id);
3406 if (r < 0)
8f05424d 3407 return r;
87f0e418 3408 }
87f0e418
LP
3409 }
3410
0301abf4 3411 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
3412 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3413 if (fd >= 0)
87f0e418
LP
3414 break;
3415
0301abf4
LP
3416 if (errno != ELOOP)
3417 return -errno;
3418
87f0e418 3419 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
3420 r = readlink_and_make_absolute(*filename, &target);
3421 if (r < 0)
0301abf4 3422 return r;
87f0e418 3423
0301abf4 3424 free(*filename);
2c7108c4 3425 *filename = target;
87f0e418
LP
3426 }
3427
9946996c
LP
3428 f = fdopen(fd, "re");
3429 if (!f) {
03e334a1 3430 safe_close(fd);
d4ad27a1 3431 return -errno;
87f0e418
LP
3432 }
3433
3434 *_f = f;
9e2f7c11 3435 *_final = id;
0301abf4 3436 return 0;
87f0e418
LP
3437}
3438
23a177ef
LP
3439static int merge_by_names(Unit **u, Set *names, const char *id) {
3440 char *k;
3441 int r;
3442
3443 assert(u);
3444 assert(*u);
3445 assert(names);
3446
3447 /* Let's try to add in all symlink names we found */
3448 while ((k = set_steal_first(names))) {
3449
3450 /* First try to merge in the other name into our
3451 * unit */
9946996c
LP
3452 r = unit_merge_by_name(*u, k);
3453 if (r < 0) {
23a177ef
LP
3454 Unit *other;
3455
3456 /* Hmm, we couldn't merge the other unit into
3457 * ours? Then let's try it the other way
3458 * round */
3459
ac155bb8 3460 other = manager_get_unit((*u)->manager, k);
23a177ef
LP
3461 free(k);
3462
9946996c
LP
3463 if (other) {
3464 r = unit_merge(other, *u);
3465 if (r >= 0) {
23a177ef
LP
3466 *u = other;
3467 return merge_by_names(u, names, NULL);
3468 }
9946996c 3469 }
23a177ef
LP
3470
3471 return r;
3472 }
3473
3474 if (id == k)
3475 unit_choose_id(*u, id);
3476
3477 free(k);
3478 }
3479
3480 return 0;
3481}
3482
e537352b 3483static int load_from_path(Unit *u, const char *path) {
0301abf4 3484 int r;
e48614c4
ZJS
3485 _cleanup_set_free_free_ Set *symlink_names = NULL;
3486 _cleanup_fclose_ FILE *f = NULL;
3487 _cleanup_free_ char *filename = NULL;
3488 char *id = NULL;
23a177ef 3489 Unit *merged;
45fb0699 3490 struct stat st;
23a177ef
LP
3491
3492 assert(u);
e537352b 3493 assert(path);
3efd4195 3494
d5099efc 3495 symlink_names = set_new(&string_hash_ops);
f975e971 3496 if (!symlink_names)
87f0e418 3497 return -ENOMEM;
3efd4195 3498
036643a2
LP
3499 if (path_is_absolute(path)) {
3500
9946996c 3501 filename = strdup(path);
e48614c4
ZJS
3502 if (!filename)
3503 return -ENOMEM;
036643a2 3504
9946996c
LP
3505 r = open_follow(&filename, &f, symlink_names, &id);
3506 if (r < 0) {
97b11eed 3507 filename = mfree(filename);
036643a2 3508 if (r != -ENOENT)
e48614c4 3509 return r;
036643a2
LP
3510 }
3511
3512 } else {
3513 char **p;
3514
ac155bb8 3515 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
036643a2
LP
3516
3517 /* Instead of opening the path right away, we manually
3518 * follow all symlinks and add their name to our unit
3519 * name set while doing so */
9946996c 3520 filename = path_make_absolute(path, *p);
e48614c4
ZJS
3521 if (!filename)
3522 return -ENOMEM;
036643a2 3523
ac155bb8
MS
3524 if (u->manager->unit_path_cache &&
3525 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
3526 r = -ENOENT;
3527 else
3528 r = open_follow(&filename, &f, symlink_names, &id);
3529
3530 if (r < 0) {
97b11eed 3531 filename = mfree(filename);
036643a2 3532 if (r != -ENOENT)
e48614c4 3533 return r;
036643a2
LP
3534
3535 /* Empty the symlink names for the next run */
9946996c 3536 set_clear_free(symlink_names);
036643a2
LP
3537 continue;
3538 }
3539
3540 break;
3541 }
3542 }
034c6ed7 3543
e48614c4 3544 if (!filename)
8f05424d 3545 /* Hmm, no suitable file found? */
e48614c4 3546 return 0;
87f0e418 3547
23a177ef 3548 merged = u;
9946996c
LP
3549 r = merge_by_names(&merged, symlink_names, id);
3550 if (r < 0)
e48614c4 3551 return r;
87f0e418 3552
23a177ef 3553 if (merged != u) {
ac155bb8 3554 u->load_state = UNIT_MERGED;
e48614c4 3555 return 0;
034c6ed7
LP
3556 }
3557
e48614c4
ZJS
3558 if (fstat(fileno(f), &st) < 0)
3559 return -errno;
45fb0699 3560
00dc5d76 3561 if (null_or_empty(&st))
ac155bb8 3562 u->load_state = UNIT_MASKED;
00dc5d76 3563 else {
c2756a68
LP
3564 u->load_state = UNIT_LOADED;
3565
00dc5d76 3566 /* Now, parse the file contents */
36f822c4
ZJS
3567 r = config_parse(u->id, filename, f,
3568 UNIT_VTABLE(u)->sections,
3569 config_item_perf_lookup, load_fragment_gperf_lookup,
3570 false, true, false, u);
f975e971 3571 if (r < 0)
e48614c4 3572 return r;
00dc5d76 3573 }
b08d03ff 3574
ac155bb8
MS
3575 free(u->fragment_path);
3576 u->fragment_path = filename;
0301abf4 3577 filename = NULL;
87f0e418 3578
ac155bb8 3579 u->fragment_mtime = timespec_load(&st.st_mtim);
45fb0699 3580
1b64d026
LP
3581 if (u->source_path) {
3582 if (stat(u->source_path, &st) >= 0)
3583 u->source_mtime = timespec_load(&st.st_mtim);
3584 else
3585 u->source_mtime = 0;
3586 }
3587
e48614c4 3588 return 0;
0301abf4
LP
3589}
3590
e537352b 3591int unit_load_fragment(Unit *u) {
23a177ef 3592 int r;
294d81f1
LP
3593 Iterator i;
3594 const char *t;
0301abf4
LP
3595
3596 assert(u);
ac155bb8
MS
3597 assert(u->load_state == UNIT_STUB);
3598 assert(u->id);
23a177ef 3599
3f5e8115
LP
3600 if (u->transient) {
3601 u->load_state = UNIT_LOADED;
3602 return 0;
3603 }
3604
294d81f1
LP
3605 /* First, try to find the unit under its id. We always look
3606 * for unit files in the default directories, to make it easy
3607 * to override things by placing things in /etc/systemd/system */
9946996c
LP
3608 r = load_from_path(u, u->id);
3609 if (r < 0)
294d81f1
LP
3610 return r;
3611
3612 /* Try to find an alias we can load this with */
abc08d4d 3613 if (u->load_state == UNIT_STUB) {
ac155bb8 3614 SET_FOREACH(t, u->names, i) {
294d81f1 3615
ac155bb8 3616 if (t == u->id)
294d81f1
LP
3617 continue;
3618
9946996c
LP
3619 r = load_from_path(u, t);
3620 if (r < 0)
294d81f1
LP
3621 return r;
3622
ac155bb8 3623 if (u->load_state != UNIT_STUB)
294d81f1
LP
3624 break;
3625 }
abc08d4d 3626 }
23a177ef 3627
294d81f1 3628 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 3629 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 3630
9946996c
LP
3631 r = load_from_path(u, u->fragment_path);
3632 if (r < 0)
23a177ef 3633 return r;
0301abf4 3634
ece174c5 3635 if (u->load_state == UNIT_STUB)
6ccb1b44
LP
3636 /* Hmm, this didn't work? Then let's get rid
3637 * of the fragment path stored for us, so that
3638 * we don't point to an invalid location. */
a1e58e8e 3639 u->fragment_path = mfree(u->fragment_path);
6ccb1b44
LP
3640 }
3641
294d81f1 3642 /* Look for a template */
ac155bb8 3643 if (u->load_state == UNIT_STUB && u->instance) {
7410616c 3644 _cleanup_free_ char *k = NULL;
294d81f1 3645
7410616c
LP
3646 r = unit_name_template(u->id, &k);
3647 if (r < 0)
3648 return r;
294d81f1
LP
3649
3650 r = load_from_path(u, k);
294d81f1 3651 if (r < 0)
9e2f7c11 3652 return r;
890f434c 3653
abc08d4d 3654 if (u->load_state == UNIT_STUB) {
ac155bb8 3655 SET_FOREACH(t, u->names, i) {
bc9fd78c 3656 _cleanup_free_ char *z = NULL;
87f0e418 3657
ac155bb8 3658 if (t == u->id)
23a177ef 3659 continue;
071830ff 3660
7410616c
LP
3661 r = unit_name_template(t, &z);
3662 if (r < 0)
3663 return r;
294d81f1 3664
bc9fd78c 3665 r = load_from_path(u, z);
294d81f1 3666 if (r < 0)
23a177ef 3667 return r;
890f434c 3668
ac155bb8 3669 if (u->load_state != UNIT_STUB)
23a177ef
LP
3670 break;
3671 }
abc08d4d 3672 }
071830ff
LP
3673 }
3674
23a177ef 3675 return 0;
3efd4195 3676}
e537352b
LP
3677
3678void unit_dump_config_items(FILE *f) {
f975e971
LP
3679 static const struct {
3680 const ConfigParserCallback callback;
3681 const char *rvalue;
3682 } table[] = {
7f8aa671 3683#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
3684 { config_parse_warn_compat, "NOTSUPPORTED" },
3685#endif
f975e971
LP
3686 { config_parse_int, "INTEGER" },
3687 { config_parse_unsigned, "UNSIGNED" },
5556b5fe 3688 { config_parse_iec_size, "SIZE" },
59f448cf 3689 { config_parse_iec_uint64, "SIZE" },
5556b5fe 3690 { config_parse_si_size, "SIZE" },
f975e971
LP
3691 { config_parse_bool, "BOOLEAN" },
3692 { config_parse_string, "STRING" },
3693 { config_parse_path, "PATH" },
3694 { config_parse_unit_path_printf, "PATH" },
3695 { config_parse_strv, "STRING [...]" },
3696 { config_parse_exec_nice, "NICE" },
3697 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3698 { config_parse_exec_io_class, "IOCLASS" },
3699 { config_parse_exec_io_priority, "IOPRIORITY" },
3700 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3701 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3702 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3703 { config_parse_mode, "MODE" },
3704 { config_parse_unit_env_file, "FILE" },
3705 { config_parse_output, "OUTPUT" },
3706 { config_parse_input, "INPUT" },
ca37242e
LP
3707 { config_parse_log_facility, "FACILITY" },
3708 { config_parse_log_level, "LEVEL" },
f975e971
LP
3709 { config_parse_exec_capabilities, "CAPABILITIES" },
3710 { config_parse_exec_secure_bits, "SECUREBITS" },
ec8927ca 3711 { config_parse_bounding_set, "BOUNDINGSET" },
f975e971 3712 { config_parse_limit, "LIMIT" },
f975e971 3713 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
3714 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3715 { config_parse_service_type, "SERVICETYPE" },
3716 { config_parse_service_restart, "SERVICERESTART" },
3717#ifdef HAVE_SYSV_COMPAT
3718 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
3719#endif
3720 { config_parse_kill_mode, "KILLMODE" },
f757855e 3721 { config_parse_signal, "SIGNAL" },
f975e971
LP
3722 { config_parse_socket_listen, "SOCKET [...]" },
3723 { config_parse_socket_bind, "SOCKETBIND" },
3724 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 3725 { config_parse_sec, "SECONDS" },
d88a251b 3726 { config_parse_nsec, "NANOSECONDS" },
94828d2d 3727 { config_parse_namespace_path_strv, "PATH [...]" },
7c8fa05c 3728 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
3729 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3730 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 3731 { config_parse_trigger_unit, "UNIT" },
f975e971 3732 { config_parse_timer, "TIMER" },
f975e971 3733 { config_parse_path_spec, "PATH" },
f975e971
LP
3734 { config_parse_notify_access, "ACCESS" },
3735 { config_parse_ip_tos, "TOS" },
3736 { config_parse_unit_condition_path, "CONDITION" },
3737 { config_parse_unit_condition_string, "CONDITION" },
3738 { config_parse_unit_condition_null, "CONDITION" },
a016b922 3739 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
3740 { config_parse_documentation, "URL" },
3741 { config_parse_service_timeout, "SECONDS" },
bf500566 3742 { config_parse_failure_action, "ACTION" },
7f0386f6
LP
3743 { config_parse_set_status, "STATUS" },
3744 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 3745 { config_parse_environ, "ENVIRON" },
c0467cf3 3746#ifdef HAVE_SECCOMP
17df7223 3747 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 3748 { config_parse_syscall_archs, "ARCHS" },
17df7223 3749 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 3750 { config_parse_address_families, "FAMILIES" },
c0467cf3 3751#endif
7f0386f6
LP
3752 { config_parse_cpu_shares, "SHARES" },
3753 { config_parse_memory_limit, "LIMIT" },
3754 { config_parse_device_allow, "DEVICE" },
3755 { config_parse_device_policy, "POLICY" },
3756 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3757 { config_parse_blockio_weight, "WEIGHT" },
3758 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3759 { config_parse_long, "LONG" },
3760 { config_parse_socket_service, "SERVICE" },
6a6751fe
LP
3761#ifdef HAVE_SELINUX
3762 { config_parse_exec_selinux_context, "LABEL" },
3763#endif
3764 { config_parse_job_mode, "MODE" },
3765 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 3766 { config_parse_personality, "PERSONALITY" },
f975e971
LP
3767 };
3768
3769 const char *prev = NULL;
3770 const char *i;
3771
3772 assert(f);
e537352b 3773
f975e971
LP
3774 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3775 const char *rvalue = "OTHER", *lvalue;
3776 unsigned j;
3777 size_t prefix_len;
3778 const char *dot;
3779 const ConfigPerfItem *p;
3780
3781 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3782
3783 dot = strchr(i, '.');
3784 lvalue = dot ? dot + 1 : i;
3785 prefix_len = dot-i;
3786
3787 if (dot)
641906e9 3788 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
3789 if (prev)
3790 fputc('\n', f);
3791
3792 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3793 }
3794
3795 for (j = 0; j < ELEMENTSOF(table); j++)
3796 if (p->parse == table[j].callback) {
3797 rvalue = table[j].rvalue;
3798 break;
3799 }
3800
3801 fprintf(f, "%s=%s\n", lvalue, rvalue);
3802 prev = i;
3803 }
e537352b 3804}