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