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