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