]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
tree-wide: use cpu_set_mfree()
[thirdparty/systemd.git] / src / core / load-fragment.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a7334b09
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
bb112710 6 Copyright 2012 Holger Hans Peter Freyther
a7334b09
LP
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
3efd4195 22#include <errno.h>
87f0e418 23#include <fcntl.h>
25e870b5 24#include <linux/fs.h>
5f5d8eab 25#include <linux/oom.h>
349cc4a5 26#if HAVE_SECCOMP
618234a5
LP
27#include <seccomp.h>
28#endif
5f5d8eab
LP
29#include <sched.h>
30#include <string.h>
3d57c6ab 31#include <sys/resource.h>
5f5d8eab 32#include <sys/stat.h>
3efd4195 33
5f5d8eab 34#include "af-list.h"
cf0fbc49 35#include "alloc-util.h"
5f5d8eab
LP
36#include "bus-error.h"
37#include "bus-internal.h"
38#include "bus-util.h"
39#include "cap-list.h"
a103496c 40#include "capability-util.h"
5f5d8eab 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"
08f3be7a 49#include "hexdecoct.h"
d3070fbd 50#include "io-util.h"
9eba9da4 51#include "ioprio.h"
d3070fbd 52#include "journal-util.h"
3ffd4af2 53#include "load-fragment.h"
5f5d8eab 54#include "log.h"
94f04347 55#include "missing.h"
83555251 56#include "mount-util.h"
6bedfcbb 57#include "parse-util.h"
9eb977db 58#include "path-util.h"
7b3e062c 59#include "process-util.h"
d0a7c5f6 60#include "rlimit-util.h"
349cc4a5 61#if HAVE_SECCOMP
57183d11
LP
62#include "seccomp-util.h"
63#endif
5f5d8eab 64#include "securebits.h"
07d46372 65#include "securebits-util.h"
5f5d8eab 66#include "signal-util.h"
8fcde012 67#include "stat-util.h"
07630cea 68#include "string-util.h"
5f5d8eab
LP
69#include "strv.h"
70#include "unit-name.h"
71#include "unit-printf.h"
72#include "unit.h"
66dccd8d 73#include "user-util.h"
5f5d8eab 74#include "utf8.h"
49cf4170 75#include "web-util.h"
57183d11 76
17df7223
LP
77int config_parse_warn_compat(
78 const char *unit,
79 const char *filename,
80 unsigned line,
81 const char *section,
82 unsigned section_line,
83 const char *lvalue,
84 int ltype,
85 const char *rvalue,
86 void *data,
87 void *userdata) {
a2c0e528
ZJS
88 Disabled reason = ltype;
89
90 switch(reason) {
91 case DISABLED_CONFIGURATION:
12ca818f 92 log_syntax(unit, LOG_DEBUG, filename, line, 0,
a2c0e528
ZJS
93 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
94 break;
9e37c954 95 case DISABLED_LEGACY:
12ca818f 96 log_syntax(unit, LOG_INFO, filename, line, 0,
9e37c954
ZJS
97 "Support for option %s= has been removed and it is ignored", lvalue);
98 break;
a2c0e528 99 case DISABLED_EXPERIMENTAL:
12ca818f 100 log_syntax(unit, LOG_INFO, filename, line, 0,
a2c0e528
ZJS
101 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
102 break;
103 };
e8e581bf 104
07459bb6
FF
105 return 0;
106}
07459bb6 107
5afe510c
LP
108DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode");
109
f32b43bd
LP
110int config_parse_unit_deps(
111 const char *unit,
112 const char *filename,
113 unsigned line,
114 const char *section,
115 unsigned section_line,
116 const char *lvalue,
117 int ltype,
118 const char *rvalue,
119 void *data,
120 void *userdata) {
3efd4195 121
f975e971 122 UnitDependency d = ltype;
87f0e418 123 Unit *u = userdata;
3d793d29 124 const char *p;
3efd4195
LP
125
126 assert(filename);
127 assert(lvalue);
128 assert(rvalue);
3efd4195 129
3d793d29 130 p = rvalue;
9ed794a3 131 for (;;) {
3d793d29 132 _cleanup_free_ char *word = NULL, *k = NULL;
3efd4195 133 int r;
3efd4195 134
c89f52ac 135 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
3d793d29
SS
136 if (r == 0)
137 break;
138 if (r == -ENOMEM)
74051b9b 139 return log_oom();
3d793d29
SS
140 if (r < 0) {
141 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
142 break;
143 }
3efd4195 144
3d793d29 145 r = unit_name_printf(u, word, &k);
19f6d710 146 if (r < 0) {
12ca818f 147 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
19f6d710
LP
148 continue;
149 }
9e2f7c11 150
eef85c4a 151 r = unit_add_dependency_by_name(u, d, k, NULL, true, UNIT_DEPENDENCY_FILE);
57020a3a 152 if (r < 0)
12ca818f 153 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
3efd4195
LP
154 }
155
156 return 0;
157}
158
f32b43bd
LP
159int config_parse_obsolete_unit_deps(
160 const char *unit,
161 const char *filename,
162 unsigned line,
163 const char *section,
164 unsigned section_line,
165 const char *lvalue,
166 int ltype,
167 const char *rvalue,
168 void *data,
169 void *userdata) {
170
171 log_syntax(unit, LOG_WARNING, filename, line, 0,
172 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
173
174 return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
175}
176
b02cb41c
LP
177int config_parse_unit_string_printf(
178 const char *unit,
179 const char *filename,
180 unsigned line,
181 const char *section,
182 unsigned section_line,
183 const char *lvalue,
184 int ltype,
185 const char *rvalue,
186 void *data,
187 void *userdata) {
932921b5 188
74051b9b 189 _cleanup_free_ char *k = NULL;
b02cb41c 190 Unit *u = userdata;
19f6d710 191 int r;
932921b5
LP
192
193 assert(filename);
194 assert(lvalue);
195 assert(rvalue);
f2d3769a 196 assert(u);
932921b5 197
19f6d710 198 r = unit_full_printf(u, rvalue, &k);
b02cb41c
LP
199 if (r < 0) {
200 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
201 return 0;
202 }
932921b5 203
b02cb41c 204 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
932921b5
LP
205}
206
12ca818f
LP
207int config_parse_unit_strv_printf(
208 const char *unit,
209 const char *filename,
210 unsigned line,
211 const char *section,
212 unsigned section_line,
213 const char *lvalue,
214 int ltype,
215 const char *rvalue,
216 void *data,
217 void *userdata) {
8fef7659
LP
218
219 Unit *u = userdata;
74051b9b 220 _cleanup_free_ char *k = NULL;
19f6d710 221 int r;
8fef7659
LP
222
223 assert(filename);
224 assert(lvalue);
225 assert(rvalue);
226 assert(u);
227
19f6d710 228 r = unit_full_printf(u, rvalue, &k);
12ca818f
LP
229 if (r < 0) {
230 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
231 return 0;
232 }
8fef7659 233
12ca818f 234 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
8fef7659
LP
235}
236
5f5d8eab
LP
237int config_parse_unit_path_printf(
238 const char *unit,
239 const char *filename,
240 unsigned line,
241 const char *section,
242 unsigned section_line,
243 const char *lvalue,
244 int ltype,
245 const char *rvalue,
246 void *data,
247 void *userdata) {
6ea832a2 248
74051b9b 249 _cleanup_free_ char *k = NULL;
811ba7a0 250 Unit *u = userdata;
19f6d710 251 int r;
2c75fb73 252 bool fatal = ltype;
6ea832a2
LP
253
254 assert(filename);
255 assert(lvalue);
256 assert(rvalue);
6ea832a2
LP
257 assert(u);
258
19f6d710 259 r = unit_full_printf(u, rvalue, &k);
811ba7a0 260 if (r < 0) {
2c75fb73
ZJS
261 log_syntax(unit, LOG_ERR, filename, line, r,
262 "Failed to resolve unit specifiers on %s%s: %m",
263 fatal ? "" : ", ignoring", rvalue);
264 return fatal ? -ENOEXEC : 0;
811ba7a0 265 }
6ea832a2 266
811ba7a0
LP
267 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
268}
269
270int config_parse_unit_path_strv_printf(
271 const char *unit,
272 const char *filename,
273 unsigned line,
274 const char *section,
275 unsigned section_line,
276 const char *lvalue,
277 int ltype,
278 const char *rvalue,
279 void *data,
280 void *userdata) {
281
a2a5291b 282 char ***x = data;
811ba7a0 283 Unit *u = userdata;
811ba7a0 284 int r;
035fe294 285 const char *p;
811ba7a0
LP
286
287 assert(filename);
288 assert(lvalue);
289 assert(rvalue);
290 assert(u);
291
499295fb 292 if (isempty(rvalue)) {
9f2d41a6 293 *x = strv_free(*x);
499295fb
YW
294 return 0;
295 }
296
035fe294
ZJS
297 for (p = rvalue;;) {
298 _cleanup_free_ char *word = NULL, *k = NULL;
811ba7a0 299
035fe294
ZJS
300 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
301 if (r == 0)
302 return 0;
303 if (r == -ENOMEM)
304 return log_oom();
305 if (r < 0) {
306 log_syntax(unit, LOG_WARNING, filename, line, r,
307 "Invalid syntax, ignoring: %s", rvalue);
308 return 0;
309 }
811ba7a0 310
035fe294 311 r = unit_full_printf(u, word, &k);
811ba7a0 312 if (r < 0) {
035fe294
ZJS
313 log_syntax(unit, LOG_ERR, filename, line, r,
314 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word);
811ba7a0
LP
315 return 0;
316 }
317
318 if (!utf8_is_valid(k)) {
0e05ee04 319 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
811ba7a0
LP
320 return 0;
321 }
322
323 if (!path_is_absolute(k)) {
035fe294
ZJS
324 log_syntax(unit, LOG_ERR, filename, line, 0,
325 "Symlink path is not absolute: %s", k);
811ba7a0
LP
326 return 0;
327 }
328
329 path_kill_slashes(k);
330
331 r = strv_push(x, k);
332 if (r < 0)
333 return log_oom();
811ba7a0
LP
334 k = NULL;
335 }
6ea832a2
LP
336}
337
e8e581bf
ZJS
338int config_parse_socket_listen(const char *unit,
339 const char *filename,
340 unsigned line,
341 const char *section,
71a61510 342 unsigned section_line,
e8e581bf
ZJS
343 const char *lvalue,
344 int ltype,
345 const char *rvalue,
346 void *data,
347 void *userdata) {
42f4e3c4 348
b1389b0d
ZJS
349 _cleanup_free_ SocketPort *p = NULL;
350 SocketPort *tail;
542563ba 351 Socket *s;
19f6d710 352 int r;
16354eff 353
42f4e3c4
LP
354 assert(filename);
355 assert(lvalue);
356 assert(rvalue);
357 assert(data);
358
595ed347 359 s = SOCKET(data);
542563ba 360
74051b9b
LP
361 if (isempty(rvalue)) {
362 /* An empty assignment removes all ports */
363 socket_free_ports(s);
364 return 0;
365 }
366
7f110ff9
LP
367 p = new0(SocketPort, 1);
368 if (!p)
74051b9b 369 return log_oom();
916abb21 370
74051b9b 371 if (ltype != SOCKET_SOCKET) {
916abb21 372
74051b9b 373 p->type = ltype;
19f6d710
LP
374 r = unit_full_printf(UNIT(s), rvalue, &p->path);
375 if (r < 0) {
12ca818f
LP
376 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
377 return 0;
916abb21
LP
378 }
379
380 path_kill_slashes(p->path);
381
7a22745a 382 } else if (streq(lvalue, "ListenNetlink")) {
74051b9b 383 _cleanup_free_ char *k = NULL;
1fd45a90 384
7a22745a 385 p->type = SOCKET_SOCKET;
19f6d710 386 r = unit_full_printf(UNIT(s), rvalue, &k);
12ca818f
LP
387 if (r < 0) {
388 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
389 return 0;
390 }
7a22745a 391
12ca818f 392 r = socket_address_parse_netlink(&p->address, k);
1fd45a90 393 if (r < 0) {
12ca818f 394 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
7a22745a
LP
395 return 0;
396 }
397
542563ba 398 } else {
74051b9b 399 _cleanup_free_ char *k = NULL;
1fd45a90 400
542563ba 401 p->type = SOCKET_SOCKET;
19f6d710 402 r = unit_full_printf(UNIT(s), rvalue, &k);
12ca818f
LP
403 if (r < 0) {
404 log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
405 return 0;
406 }
542563ba 407
12ca818f 408 r = socket_address_parse_and_warn(&p->address, k);
1fd45a90 409 if (r < 0) {
f847b8b7
MS
410 if (r != -EAFNOSUPPORT)
411 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
412
c0b34696 413 return 0;
542563ba
LP
414 }
415
416 if (streq(lvalue, "ListenStream"))
417 p->address.type = SOCK_STREAM;
418 else if (streq(lvalue, "ListenDatagram"))
419 p->address.type = SOCK_DGRAM;
420 else {
421 assert(streq(lvalue, "ListenSequentialPacket"));
422 p->address.type = SOCK_SEQPACKET;
423 }
424
425 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
12ca818f 426 log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
c0b34696 427 return 0;
542563ba 428 }
16354eff
LP
429 }
430
542563ba 431 p->fd = -1;
15087cdb
PS
432 p->auxiliary_fds = NULL;
433 p->n_auxiliary_fds = 0;
2e41a51e 434 p->socket = s;
49f91047
LP
435
436 if (s->ports) {
71fda00f
LP
437 LIST_FIND_TAIL(port, s->ports, tail);
438 LIST_INSERT_AFTER(port, s->ports, tail, p);
49f91047 439 } else
71fda00f 440 LIST_PREPEND(port, s->ports, p);
b1389b0d 441 p = NULL;
542563ba 442
16354eff 443 return 0;
42f4e3c4
LP
444}
445
74bb646e
SS
446int config_parse_socket_protocol(const char *unit,
447 const char *filename,
448 unsigned line,
449 const char *section,
450 unsigned section_line,
451 const char *lvalue,
452 int ltype,
453 const char *rvalue,
454 void *data,
455 void *userdata) {
456 Socket *s;
457
458 assert(filename);
459 assert(lvalue);
460 assert(rvalue);
461 assert(data);
462
463 s = SOCKET(data);
464
465 if (streq(rvalue, "udplite"))
466 s->socket_protocol = IPPROTO_UDPLITE;
467 else if (streq(rvalue, "sctp"))
468 s->socket_protocol = IPPROTO_SCTP;
469 else {
470 log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
471 return 0;
472 }
473
474 return 0;
475}
476
e8e581bf
ZJS
477int config_parse_socket_bind(const char *unit,
478 const char *filename,
479 unsigned line,
480 const char *section,
71a61510 481 unsigned section_line,
e8e581bf
ZJS
482 const char *lvalue,
483 int ltype,
484 const char *rvalue,
485 void *data,
486 void *userdata) {
42f4e3c4 487
542563ba 488 Socket *s;
c0120d99 489 SocketAddressBindIPv6Only b;
42f4e3c4
LP
490
491 assert(filename);
492 assert(lvalue);
493 assert(rvalue);
494 assert(data);
495
595ed347 496 s = SOCKET(data);
542563ba 497
5198dabc
LP
498 b = socket_address_bind_ipv6_only_from_string(rvalue);
499 if (b < 0) {
c0120d99
LP
500 int r;
501
5198dabc
LP
502 r = parse_boolean(rvalue);
503 if (r < 0) {
12ca818f 504 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
c0b34696 505 return 0;
c0120d99 506 }
42f4e3c4 507
c0120d99
LP
508 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
509 } else
510 s->bind_ipv6_only = b;
542563ba 511
42f4e3c4
LP
512 return 0;
513}
514
41bf0590
LP
515int config_parse_exec_nice(
516 const char *unit,
517 const char *filename,
518 unsigned line,
519 const char *section,
520 unsigned section_line,
521 const char *lvalue,
522 int ltype,
523 const char *rvalue,
524 void *data,
525 void *userdata) {
034c6ed7 526
fb33a393 527 ExecContext *c = data;
e8e581bf 528 int priority, r;
034c6ed7
LP
529
530 assert(filename);
531 assert(lvalue);
532 assert(rvalue);
533 assert(data);
534
41bf0590 535 r = parse_nice(rvalue, &priority);
e8e581bf 536 if (r < 0) {
41bf0590
LP
537 if (r == -ERANGE)
538 log_syntax(unit, LOG_ERR, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
539 else
540 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
034c6ed7 541
c0b34696 542 return 0;
034c6ed7
LP
543 }
544
fb33a393 545 c->nice = priority;
71155933 546 c->nice_set = true;
fb33a393 547
034c6ed7
LP
548 return 0;
549}
550
e8e581bf
ZJS
551int config_parse_exec_oom_score_adjust(const char* unit,
552 const char *filename,
553 unsigned line,
554 const char *section,
71a61510 555 unsigned section_line,
e8e581bf
ZJS
556 const char *lvalue,
557 int ltype,
558 const char *rvalue,
559 void *data,
560 void *userdata) {
034c6ed7 561
fb33a393 562 ExecContext *c = data;
e8e581bf 563 int oa, r;
034c6ed7
LP
564
565 assert(filename);
566 assert(lvalue);
567 assert(rvalue);
568 assert(data);
569
e8e581bf
ZJS
570 r = safe_atoi(rvalue, &oa);
571 if (r < 0) {
12ca818f 572 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
c0b34696 573 return 0;
034c6ed7
LP
574 }
575
dd6c17b1 576 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
12ca818f 577 log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
c0b34696 578 return 0;
034c6ed7
LP
579 }
580
dd6c17b1
LP
581 c->oom_score_adjust = oa;
582 c->oom_score_adjust_set = true;
fb33a393 583
034c6ed7
LP
584 return 0;
585}
586
527b7a42
LP
587int config_parse_exec(
588 const char *unit,
589 const char *filename,
590 unsigned line,
591 const char *section,
592 unsigned section_line,
593 const char *lvalue,
594 int ltype,
595 const char *rvalue,
596 void *data,
597 void *userdata) {
034c6ed7 598
46a0d98a 599 ExecCommand **e = data;
5125e762 600 Unit *u = userdata;
46a0d98a
FB
601 const char *p;
602 bool semicolon;
7f110ff9 603 int r;
034c6ed7
LP
604
605 assert(filename);
606 assert(lvalue);
607 assert(rvalue);
61e5d8ed 608 assert(e);
034c6ed7 609
74051b9b 610 e += ltype;
c83f1f30 611 rvalue += strspn(rvalue, WHITESPACE);
c83f1f30 612
74051b9b
LP
613 if (isempty(rvalue)) {
614 /* An empty assignment resets the list */
f1acf85a 615 *e = exec_command_free_list(*e);
74051b9b
LP
616 return 0;
617 }
618
bd1b973f 619 p = rvalue;
46a0d98a 620 do {
dea7b6b0 621 _cleanup_free_ char *path = NULL, *firstword = NULL;
165a31c0
LP
622 ExecCommandFlags flags = 0;
623 bool ignore = false, separate_argv0 = false;
dea7b6b0 624 _cleanup_free_ ExecCommand *nce = NULL;
46a0d98a
FB
625 _cleanup_strv_free_ char **n = NULL;
626 size_t nlen = 0, nbufsize = 0;
5125e762 627 const char *f;
6c666e26 628
46a0d98a
FB
629 semicolon = false;
630
9a82ab95 631 r = extract_first_word_and_warn(&p, &firstword, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
632 if (r <= 0)
633 return 0;
6c666e26 634
46a0d98a 635 f = firstword;
007f48bb 636 for (;;) {
165a31c0
LP
637 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
638 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
639 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
640 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
641 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
642 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
643 * other sandboxing, with some special exceptions for changing UID.
644 *
645 * The idea is that '!!' may be used to write services that can take benefit of systemd's
646 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
647 * privilege dropping within the daemon if the kernel does not offer that. */
648
649 if (*f == '-' && !(flags & EXEC_COMMAND_IGNORE_FAILURE)) {
650 flags |= EXEC_COMMAND_IGNORE_FAILURE;
46a0d98a 651 ignore = true;
165a31c0 652 } else if (*f == '@' && !separate_argv0)
46a0d98a 653 separate_argv0 = true;
165a31c0
LP
654 else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
655 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
656 else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
657 flags |= EXEC_COMMAND_NO_SETUID;
658 else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))) {
659 flags &= ~EXEC_COMMAND_NO_SETUID;
660 flags |= EXEC_COMMAND_AMBIENT_MAGIC;
661 } else
46a0d98a 662 break;
313cefa1 663 f++;
61e5d8ed 664 }
46a0d98a 665
5125e762
LP
666 r = unit_full_printf(u, f, &path);
667 if (r < 0) {
bb28e684
ZJS
668 log_syntax(unit, LOG_ERR, filename, line, r,
669 "Failed to resolve unit specifiers on %s%s: %m",
670 f, ignore ? ", ignoring" : "");
671 return ignore ? 0 : -ENOEXEC;
5125e762
LP
672 }
673
674 if (isempty(path)) {
46a0d98a 675 /* First word is either "-" or "@" with no command. */
bb28e684
ZJS
676 log_syntax(unit, LOG_ERR, filename, line, 0,
677 "Empty path in command line%s: \"%s\"",
678 ignore ? ", ignoring" : "", rvalue);
679 return ignore ? 0 : -ENOEXEC;
b2fadec6 680 }
5125e762 681 if (!string_is_safe(path)) {
bb28e684
ZJS
682 log_syntax(unit, LOG_ERR, filename, line, 0,
683 "Executable path contains special characters%s: %s",
684 ignore ? ", ignoring" : "", rvalue);
685 return ignore ? 0 : -ENOEXEC;
46a0d98a 686 }
5125e762 687 if (!path_is_absolute(path)) {
bb28e684
ZJS
688 log_syntax(unit, LOG_ERR, filename, line, 0,
689 "Executable path is not absolute%s: %s",
690 ignore ? ", ignoring" : "", rvalue);
691 return ignore ? 0 : -ENOEXEC;
46a0d98a 692 }
5125e762 693 if (endswith(path, "/")) {
bb28e684
ZJS
694 log_syntax(unit, LOG_ERR, filename, line, 0,
695 "Executable path specifies a directory%s: %s",
696 ignore ? ", ignoring" : "", rvalue);
697 return ignore ? 0 : -ENOEXEC;
46a0d98a 698 }
61e5d8ed 699
46a0d98a 700 if (!separate_argv0) {
5125e762
LP
701 char *w = NULL;
702
46a0d98a
FB
703 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
704 return log_oom();
5125e762
LP
705
706 w = strdup(path);
707 if (!w)
46a0d98a 708 return log_oom();
5125e762 709 n[nlen++] = w;
46a0d98a
FB
710 n[nlen] = NULL;
711 }
7f110ff9 712
46a0d98a
FB
713 path_kill_slashes(path);
714
4b1c1753 715 while (!isempty(p)) {
5125e762 716 _cleanup_free_ char *word = NULL, *resolved = NULL;
46a0d98a
FB
717
718 /* Check explicitly for an unquoted semicolon as
719 * command separator token. */
720 if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
313cefa1 721 p++;
46a0d98a
FB
722 p += strspn(p, WHITESPACE);
723 semicolon = true;
724 break;
c8539536 725 }
7f110ff9 726
5125e762
LP
727 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
728 * extract_first_word() would return the same for all of those. */
46a0d98a 729 if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
5125e762
LP
730 char *w;
731
46a0d98a
FB
732 p += 2;
733 p += strspn(p, WHITESPACE);
5125e762 734
46a0d98a
FB
735 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
736 return log_oom();
5125e762
LP
737
738 w = strdup(";");
739 if (!w)
46a0d98a 740 return log_oom();
5125e762 741 n[nlen++] = w;
46a0d98a
FB
742 n[nlen] = NULL;
743 continue;
61e5d8ed 744 }
c8539536 745
9a82ab95 746 r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
46a0d98a
FB
747 if (r == 0)
748 break;
5125e762 749 if (r < 0)
bb28e684 750 return ignore ? 0 : -ENOEXEC;
5125e762
LP
751
752 r = unit_full_printf(u, word, &resolved);
753 if (r < 0) {
bb28e684
ZJS
754 log_syntax(unit, LOG_ERR, filename, line, r,
755 "Failed to resolve unit specifiers on %s%s: %m",
756 word, ignore ? ", ignoring" : "");
757 return ignore ? 0 : -ENOEXEC;
5125e762 758 }
46a0d98a
FB
759
760 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
761 return log_oom();
5125e762 762 n[nlen++] = resolved;
46a0d98a 763 n[nlen] = NULL;
5125e762 764 resolved = NULL;
61e5d8ed
LP
765 }
766
46a0d98a 767 if (!n || !n[0]) {
bb28e684
ZJS
768 log_syntax(unit, LOG_ERR, filename, line, 0,
769 "Empty executable name or zeroeth argument%s: %s",
770 ignore ? ", ignoring" : "", rvalue);
771 return ignore ? 0 : -ENOEXEC;
7f110ff9 772 }
6c666e26 773
7f110ff9 774 nce = new0(ExecCommand, 1);
46a0d98a
FB
775 if (!nce)
776 return log_oom();
61e5d8ed
LP
777
778 nce->argv = n;
779 nce->path = path;
165a31c0 780 nce->flags = flags;
034c6ed7 781
61e5d8ed 782 exec_command_append_list(e, nce);
01f78473 783
46a0d98a
FB
784 /* Do not _cleanup_free_ these. */
785 n = NULL;
786 path = NULL;
787 nce = NULL;
034c6ed7 788
46a0d98a
FB
789 rvalue = p;
790 } while (semicolon);
034c6ed7 791
46a0d98a 792 return 0;
034c6ed7
LP
793}
794
f975e971
LP
795DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
796DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
034c6ed7 797
d31645ad
LP
798int config_parse_socket_bindtodevice(
799 const char* unit,
800 const char *filename,
801 unsigned line,
802 const char *section,
803 unsigned section_line,
804 const char *lvalue,
805 int ltype,
806 const char *rvalue,
807 void *data,
808 void *userdata) {
acbb0225
LP
809
810 Socket *s = data;
811 char *n;
812
813 assert(filename);
814 assert(lvalue);
815 assert(rvalue);
816 assert(data);
817
818 if (rvalue[0] && !streq(rvalue, "*")) {
d31645ad
LP
819 if (!ifname_valid(rvalue)) {
820 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue);
821 return 0;
822 }
823
74051b9b
LP
824 n = strdup(rvalue);
825 if (!n)
826 return log_oom();
acbb0225
LP
827 } else
828 n = NULL;
829
830 free(s->bind_to_device);
831 s->bind_to_device = n;
832
833 return 0;
834}
835
9bd6a50e
LP
836int config_parse_exec_input(
837 const char *unit,
838 const char *filename,
839 unsigned line,
840 const char *section,
841 unsigned section_line,
842 const char *lvalue,
843 int ltype,
844 const char *rvalue,
845 void *data,
846 void *userdata) {
52c239d7 847
52c239d7 848 ExecContext *c = data;
2038c3f5
LP
849 Unit *u = userdata;
850 const char *n;
851 ExecInput ei;
52c239d7
LB
852 int r;
853
854 assert(data);
855 assert(filename);
856 assert(line);
857 assert(rvalue);
858
2038c3f5
LP
859 n = startswith(rvalue, "fd:");
860 if (n) {
861 _cleanup_free_ char *resolved = NULL;
862
863 r = unit_full_printf(u, n, &resolved);
864 if (r < 0)
865 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
866
867 if (isempty(resolved))
868 resolved = mfree(resolved);
869 else if (!fdname_is_valid(resolved)) {
870 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
871 return -EINVAL;
52c239d7 872 }
9bd6a50e 873
2038c3f5
LP
874 free_and_replace(c->stdio_fdname[STDIN_FILENO], resolved);
875
876 ei = EXEC_INPUT_NAMED_FD;
877
878 } else if ((n = startswith(rvalue, "file:"))) {
879 _cleanup_free_ char *resolved = NULL;
880
881 r = unit_full_printf(u, n, &resolved);
52c239d7 882 if (r < 0)
2038c3f5 883 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
9bd6a50e 884
2038c3f5
LP
885 if (!path_is_absolute(resolved)) {
886 log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires an absolute path name: %s", resolved);
887 return -EINVAL;
888 }
889
99be45a4 890 if (!path_is_normalized(resolved)) {
2038c3f5
LP
891 log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires a normalized path name: %s", resolved);
892 return -EINVAL;
893 }
894
895 free_and_replace(c->stdio_file[STDIN_FILENO], resolved);
896
897 ei = EXEC_INPUT_FILE;
9bd6a50e 898
52c239d7 899 } else {
9bd6a50e
LP
900 ei = exec_input_from_string(rvalue);
901 if (ei < 0) {
52c239d7 902 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue);
9bd6a50e
LP
903 return 0;
904 }
52c239d7 905 }
9bd6a50e 906
2038c3f5 907 c->std_input = ei;
9bd6a50e 908 return 0;
52c239d7
LB
909}
910
08f3be7a
LP
911int config_parse_exec_input_text(
912 const char *unit,
913 const char *filename,
914 unsigned line,
915 const char *section,
916 unsigned section_line,
917 const char *lvalue,
918 int ltype,
919 const char *rvalue,
920 void *data,
921 void *userdata) {
922
923 _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
924 ExecContext *c = data;
925 Unit *u = userdata;
926 size_t sz;
927 void *p;
928 int r;
929
930 assert(data);
931 assert(filename);
932 assert(line);
933 assert(rvalue);
934
935 if (isempty(rvalue)) {
936 /* Reset if the empty string is assigned */
937 c->stdin_data = mfree(c->stdin_data);
938 c->stdin_data_size = 0;
52c239d7
LB
939 return 0;
940 }
08f3be7a
LP
941
942 r = cunescape(rvalue, 0, &unescaped);
2038c3f5
LP
943 if (r < 0)
944 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode C escaped text: %s", rvalue);
08f3be7a
LP
945
946 r = unit_full_printf(u, unescaped, &resolved);
2038c3f5
LP
947 if (r < 0)
948 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers: %s", unescaped);
08f3be7a
LP
949
950 sz = strlen(resolved);
951 if (c->stdin_data_size + sz + 1 < c->stdin_data_size || /* check for overflow */
952 c->stdin_data_size + sz + 1 > EXEC_STDIN_DATA_MAX) {
2038c3f5
LP
953 log_syntax(unit, LOG_ERR, filename, line, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c->stdin_data_size + sz, (size_t) EXEC_STDIN_DATA_MAX);
954 return -E2BIG;
08f3be7a
LP
955 }
956
957 p = realloc(c->stdin_data, c->stdin_data_size + sz + 1);
958 if (!p)
959 return log_oom();
960
961 *((char*) mempcpy((char*) p + c->stdin_data_size, resolved, sz)) = '\n';
962
963 c->stdin_data = p;
964 c->stdin_data_size += sz + 1;
965
966 return 0;
52c239d7
LB
967}
968
08f3be7a
LP
969int config_parse_exec_input_data(
970 const char *unit,
971 const char *filename,
972 unsigned line,
973 const char *section,
974 unsigned section_line,
975 const char *lvalue,
976 int ltype,
977 const char *rvalue,
978 void *data,
979 void *userdata) {
980
08f3be7a
LP
981 _cleanup_free_ void *p = NULL;
982 ExecContext *c = data;
983 size_t sz;
984 void *q;
985 int r;
986
987 assert(data);
988 assert(filename);
989 assert(line);
990 assert(rvalue);
991
992 if (isempty(rvalue)) {
993 /* Reset if the empty string is assigned */
994 c->stdin_data = mfree(c->stdin_data);
995 c->stdin_data_size = 0;
996 return 0;
997 }
998
081f36d8 999 r = unbase64mem(rvalue, (size_t) -1, &p, &sz);
2038c3f5 1000 if (r < 0)
081f36d8 1001 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode base64 data, ignoring: %s", rvalue);
08f3be7a
LP
1002
1003 assert(sz > 0);
1004
1005 if (c->stdin_data_size + sz < c->stdin_data_size || /* check for overflow */
1006 c->stdin_data_size + sz > EXEC_STDIN_DATA_MAX) {
2038c3f5
LP
1007 log_syntax(unit, LOG_ERR, filename, line, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c->stdin_data_size + sz, (size_t) EXEC_STDIN_DATA_MAX);
1008 return -E2BIG;
08f3be7a
LP
1009 }
1010
1011 q = realloc(c->stdin_data, c->stdin_data_size + sz);
1012 if (!q)
1013 return log_oom();
1014
1015 memcpy((uint8_t*) q + c->stdin_data_size, p, sz);
1016
1017 c->stdin_data = q;
1018 c->stdin_data_size += sz;
1019
1020 return 0;
1021}
1022
2038c3f5
LP
1023int config_parse_exec_output(
1024 const char *unit,
1025 const char *filename,
1026 unsigned line,
1027 const char *section,
1028 unsigned section_line,
1029 const char *lvalue,
1030 int ltype,
1031 const char *rvalue,
1032 void *data,
1033 void *userdata) {
1034
1035 _cleanup_free_ char *resolved = NULL;
1036 const char *n;
52c239d7 1037 ExecContext *c = data;
2038c3f5 1038 Unit *u = userdata;
52c239d7 1039 ExecOutput eo;
52c239d7
LB
1040 int r;
1041
1042 assert(data);
1043 assert(filename);
1044 assert(line);
1045 assert(lvalue);
1046 assert(rvalue);
1047
2038c3f5
LP
1048 n = startswith(rvalue, "fd:");
1049 if (n) {
1050 r = unit_full_printf(u, n, &resolved);
1051 if (r < 0)
1052 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
1053
1054 if (isempty(resolved))
1055 resolved = mfree(resolved);
1056 else if (!fdname_is_valid(resolved)) {
1057 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
1058 return -EINVAL;
52c239d7 1059 }
2038c3f5 1060
52c239d7 1061 eo = EXEC_OUTPUT_NAMED_FD;
2038c3f5
LP
1062
1063 } else if ((n = startswith(rvalue, "file:"))) {
1064
1065 r = unit_full_printf(u, n, &resolved);
1066 if (r < 0)
1067 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s: %m", n);
1068
1069 if (!path_is_absolute(resolved)) {
1070 log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires an absolute path name: %s", resolved);
1071 return -EINVAL;
1072 }
1073
99be45a4 1074 if (!path_is_normalized(resolved)) {
2038c3f5
LP
1075 log_syntax(unit, LOG_ERR, filename, line, 0, "file: requires a normalized path name, ignoring: %s", resolved);
1076 return -EINVAL;
1077 }
1078
1079 eo = EXEC_OUTPUT_FILE;
1080
52c239d7
LB
1081 } else {
1082 eo = exec_output_from_string(rvalue);
2038c3f5 1083 if (eo < 0) {
52c239d7
LB
1084 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue);
1085 return 0;
1086 }
1087 }
1088
1089 if (streq(lvalue, "StandardOutput")) {
2038c3f5
LP
1090 if (eo == EXEC_OUTPUT_NAMED_FD)
1091 free_and_replace(c->stdio_fdname[STDOUT_FILENO], resolved);
1092 else
1093 free_and_replace(c->stdio_file[STDOUT_FILENO], resolved);
1094
52c239d7 1095 c->std_output = eo;
2038c3f5 1096
52c239d7 1097 } else {
2038c3f5
LP
1098 assert(streq(lvalue, "StandardError"));
1099
1100 if (eo == EXEC_OUTPUT_NAMED_FD)
1101 free_and_replace(c->stdio_fdname[STDERR_FILENO], resolved);
1102 else
1103 free_and_replace(c->stdio_file[STDERR_FILENO], resolved);
1104
1105 c->std_error = eo;
52c239d7 1106 }
2038c3f5
LP
1107
1108 return 0;
52c239d7 1109}
87f0e418 1110
e8e581bf
ZJS
1111int config_parse_exec_io_class(const char *unit,
1112 const char *filename,
1113 unsigned line,
1114 const char *section,
71a61510 1115 unsigned section_line,
e8e581bf
ZJS
1116 const char *lvalue,
1117 int ltype,
1118 const char *rvalue,
1119 void *data,
1120 void *userdata) {
94f04347
LP
1121
1122 ExecContext *c = data;
1123 int x;
1124
1125 assert(filename);
1126 assert(lvalue);
1127 assert(rvalue);
1128 assert(data);
1129
f8b69d1d
MS
1130 x = ioprio_class_from_string(rvalue);
1131 if (x < 0) {
12ca818f 1132 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
c0b34696 1133 return 0;
0d87eb42 1134 }
94f04347
LP
1135
1136 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
1137 c->ioprio_set = true;
1138
1139 return 0;
1140}
1141
e8e581bf
ZJS
1142int config_parse_exec_io_priority(const char *unit,
1143 const char *filename,
1144 unsigned line,
1145 const char *section,
71a61510 1146 unsigned section_line,
e8e581bf
ZJS
1147 const char *lvalue,
1148 int ltype,
1149 const char *rvalue,
1150 void *data,
1151 void *userdata) {
94f04347
LP
1152
1153 ExecContext *c = data;
e8e581bf 1154 int i, r;
94f04347
LP
1155
1156 assert(filename);
1157 assert(lvalue);
1158 assert(rvalue);
1159 assert(data);
1160
7f452159
LP
1161 r = ioprio_parse_priority(rvalue, &i);
1162 if (r < 0) {
12ca818f 1163 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
c0b34696 1164 return 0;
071830ff
LP
1165 }
1166
94f04347
LP
1167 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
1168 c->ioprio_set = true;
1169
071830ff
LP
1170 return 0;
1171}
1172
e8e581bf
ZJS
1173int config_parse_exec_cpu_sched_policy(const char *unit,
1174 const char *filename,
1175 unsigned line,
1176 const char *section,
71a61510 1177 unsigned section_line,
e8e581bf
ZJS
1178 const char *lvalue,
1179 int ltype,
1180 const char *rvalue,
1181 void *data,
1182 void *userdata) {
9eba9da4 1183
94f04347
LP
1184
1185 ExecContext *c = data;
1186 int x;
1187
1188 assert(filename);
1189 assert(lvalue);
1190 assert(rvalue);
1191 assert(data);
1192
f8b69d1d
MS
1193 x = sched_policy_from_string(rvalue);
1194 if (x < 0) {
12ca818f 1195 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 1196 return 0;
0d87eb42 1197 }
94f04347
LP
1198
1199 c->cpu_sched_policy = x;
bb112710
HHPF
1200 /* Moving to or from real-time policy? We need to adjust the priority */
1201 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
94f04347
LP
1202 c->cpu_sched_set = true;
1203
1204 return 0;
1205}
1206
e8e581bf
ZJS
1207int config_parse_exec_cpu_sched_prio(const char *unit,
1208 const char *filename,
1209 unsigned line,
1210 const char *section,
71a61510 1211 unsigned section_line,
e8e581bf
ZJS
1212 const char *lvalue,
1213 int ltype,
1214 const char *rvalue,
1215 void *data,
1216 void *userdata) {
9eba9da4
LP
1217
1218 ExecContext *c = data;
e8e581bf 1219 int i, min, max, r;
9eba9da4
LP
1220
1221 assert(filename);
1222 assert(lvalue);
1223 assert(rvalue);
1224 assert(data);
1225
e8e581bf
ZJS
1226 r = safe_atoi(rvalue, &i);
1227 if (r < 0) {
12ca818f 1228 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 1229 return 0;
94f04347 1230 }
9eba9da4 1231
bb112710
HHPF
1232 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1233 min = sched_get_priority_min(c->cpu_sched_policy);
1234 max = sched_get_priority_max(c->cpu_sched_policy);
1235
1236 if (i < min || i > max) {
12ca818f 1237 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
bb112710
HHPF
1238 return 0;
1239 }
1240
94f04347
LP
1241 c->cpu_sched_priority = i;
1242 c->cpu_sched_set = true;
1243
1244 return 0;
1245}
1246
e8e581bf
ZJS
1247int config_parse_exec_cpu_affinity(const char *unit,
1248 const char *filename,
1249 unsigned line,
1250 const char *section,
71a61510 1251 unsigned section_line,
e8e581bf
ZJS
1252 const char *lvalue,
1253 int ltype,
1254 const char *rvalue,
1255 void *data,
1256 void *userdata) {
94f04347
LP
1257
1258 ExecContext *c = data;
9d5ca7f8
FB
1259 _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
1260 int ncpus;
94f04347
LP
1261
1262 assert(filename);
1263 assert(lvalue);
1264 assert(rvalue);
1265 assert(data);
1266
765d143b 1267 ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
9d5ca7f8
FB
1268 if (ncpus < 0)
1269 return ncpus;
487393e9 1270
9d5ca7f8
FB
1271 if (c->cpuset)
1272 CPU_FREE(c->cpuset);
82c121a4 1273
9d5ca7f8
FB
1274 if (ncpus == 0)
1275 /* An empty assignment resets the CPU list */
1276 c->cpuset = NULL;
1277 else {
1278 c->cpuset = cpuset;
1279 cpuset = NULL;
9eba9da4 1280 }
9d5ca7f8 1281 c->cpuset_ncpus = ncpus;
9eba9da4 1282
94f04347
LP
1283 return 0;
1284}
1285
e8e581bf
ZJS
1286int config_parse_exec_secure_bits(const char *unit,
1287 const char *filename,
1288 unsigned line,
1289 const char *section,
71a61510 1290 unsigned section_line,
e8e581bf
ZJS
1291 const char *lvalue,
1292 int ltype,
1293 const char *rvalue,
1294 void *data,
1295 void *userdata) {
94f04347
LP
1296
1297 ExecContext *c = data;
035fe294 1298 int r;
94f04347
LP
1299
1300 assert(filename);
1301 assert(lvalue);
1302 assert(rvalue);
1303 assert(data);
1304
74051b9b
LP
1305 if (isempty(rvalue)) {
1306 /* An empty assignment resets the field */
1307 c->secure_bits = 0;
1308 return 0;
1309 }
1310
07d46372
YW
1311 r = secure_bits_from_string(rvalue);
1312 if (r == -ENOMEM)
1313 return log_oom();
1314 if (r < 0) {
1315 log_syntax(unit, LOG_WARNING, filename, line, r,
1316 "Invalid syntax, ignoring: %s", rvalue);
1317 return 0;
1318 }
035fe294 1319
07d46372 1320 c->secure_bits = r;
035fe294 1321
07d46372 1322 return 0;
94f04347
LP
1323}
1324
a103496c 1325int config_parse_capability_set(
65dce264
LP
1326 const char *unit,
1327 const char *filename,
1328 unsigned line,
1329 const char *section,
1330 unsigned section_line,
1331 const char *lvalue,
1332 int ltype,
1333 const char *rvalue,
1334 void *data,
1335 void *userdata) {
94f04347 1336
a103496c
IP
1337 uint64_t *capability_set = data;
1338 uint64_t sum = 0, initial = 0;
260abb78 1339 bool invert = false;
dd1f5bd0 1340 int r;
94f04347
LP
1341
1342 assert(filename);
1343 assert(lvalue);
1344 assert(rvalue);
1345 assert(data);
1346
260abb78
LP
1347 if (rvalue[0] == '~') {
1348 invert = true;
1349 rvalue++;
1350 }
1351
70d54d90 1352 if (streq(lvalue, "CapabilityBoundingSet"))
a103496c 1353 initial = CAP_ALL; /* initialized to all bits on */
755d4b67 1354 /* else "AmbientCapabilities" initialized to all bits off */
260abb78 1355
dd1f5bd0
YW
1356 r = capability_set_from_string(rvalue, &sum);
1357 if (r == -ENOMEM)
1358 return log_oom();
1359 if (r < 0) {
1360 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word: %s", rvalue);
1361 return 0;
94f04347 1362 }
9eba9da4 1363
a103496c 1364 if (sum == 0 || *capability_set == initial)
c792ec2e
IP
1365 /* "", "~" or uninitialized data -> replace */
1366 *capability_set = invert ? ~sum : sum;
1367 else {
a103496c 1368 /* previous data -> merge */
c792ec2e
IP
1369 if (invert)
1370 *capability_set &= ~sum;
1371 else
1372 *capability_set |= sum;
1373 }
260abb78 1374
9eba9da4
LP
1375 return 0;
1376}
1377
91518d20 1378int config_parse_limit(
d580265e
LP
1379 const char *unit,
1380 const char *filename,
1381 unsigned line,
1382 const char *section,
1383 unsigned section_line,
1384 const char *lvalue,
1385 int ltype,
1386 const char *rvalue,
1387 void *data,
1388 void *userdata) {
412ea7a9 1389
d0a7c5f6
LP
1390 struct rlimit **rl = data, d = {};
1391 int r;
a4c18002
LP
1392
1393 assert(filename);
1394 assert(lvalue);
1395 assert(rvalue);
1396 assert(data);
1397
d0a7c5f6
LP
1398 r = rlimit_parse(ltype, rvalue, &d);
1399 if (r == -EILSEQ) {
1400 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1401 return 0;
1402 }
1403 if (r < 0) {
1404 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1405 return 0;
1406 }
a4c18002 1407
d0a7c5f6
LP
1408 if (rl[ltype])
1409 *rl[ltype] = d;
1410 else {
1411 rl[ltype] = newdup(struct rlimit, &d, 1);
1412 if (!rl[ltype])
1413 return log_oom();
1414 }
a4c18002 1415
d0a7c5f6 1416 return 0;
91518d20 1417}
a4c18002 1418
349cc4a5 1419#if HAVE_SYSV_COMPAT
e8e581bf
ZJS
1420int config_parse_sysv_priority(const char *unit,
1421 const char *filename,
1422 unsigned line,
1423 const char *section,
71a61510 1424 unsigned section_line,
e8e581bf
ZJS
1425 const char *lvalue,
1426 int ltype,
1427 const char *rvalue,
1428 void *data,
1429 void *userdata) {
a9a1e00a
LP
1430
1431 int *priority = data;
e8e581bf 1432 int i, r;
a9a1e00a
LP
1433
1434 assert(filename);
1435 assert(lvalue);
1436 assert(rvalue);
1437 assert(data);
1438
e8e581bf
ZJS
1439 r = safe_atoi(rvalue, &i);
1440 if (r < 0 || i < 0) {
12ca818f 1441 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
c0b34696 1442 return 0;
a9a1e00a
LP
1443 }
1444
1445 *priority = (int) i;
1446 return 0;
1447}
07459bb6 1448#endif
a9a1e00a 1449
023a4f67 1450DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
f975e971 1451DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
50159e6a 1452
83555251
LP
1453int config_parse_exec_mount_flags(
1454 const char *unit,
1455 const char *filename,
1456 unsigned line,
1457 const char *section,
1458 unsigned section_line,
1459 const char *lvalue,
1460 int ltype,
1461 const char *rvalue,
1462 void *data,
1463 void *userdata) {
15ae422b 1464
e28bb14a 1465
e28bb14a 1466 ExecContext *c = data;
c7383828 1467 int r;
15ae422b
LP
1468
1469 assert(filename);
1470 assert(lvalue);
1471 assert(rvalue);
1472 assert(data);
1473
c7383828
ZJS
1474 r = mount_propagation_flags_from_string(rvalue, &c->mount_flags);
1475 if (r < 0)
1476 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
e28bb14a 1477
15ae422b
LP
1478 return 0;
1479}
1480
5f8640fb
LP
1481int config_parse_exec_selinux_context(
1482 const char *unit,
1483 const char *filename,
1484 unsigned line,
1485 const char *section,
1486 unsigned section_line,
1487 const char *lvalue,
1488 int ltype,
1489 const char *rvalue,
1490 void *data,
1491 void *userdata) {
1492
1493 ExecContext *c = data;
1494 Unit *u = userdata;
1495 bool ignore;
1496 char *k;
1497 int r;
1498
1499 assert(filename);
1500 assert(lvalue);
1501 assert(rvalue);
1502 assert(data);
1503
1504 if (isempty(rvalue)) {
a1e58e8e 1505 c->selinux_context = mfree(c->selinux_context);
5f8640fb
LP
1506 c->selinux_context_ignore = false;
1507 return 0;
1508 }
1509
1510 if (rvalue[0] == '-') {
1511 ignore = true;
1512 rvalue++;
1513 } else
1514 ignore = false;
1515
18913df9 1516 r = unit_full_printf(u, rvalue, &k);
5f8640fb 1517 if (r < 0) {
bb28e684
ZJS
1518 log_syntax(unit, LOG_ERR, filename, line, r,
1519 "Failed to resolve specifiers%s: %m",
1520 ignore ? ", ignoring" : "");
1521 return ignore ? 0 : -ENOEXEC;
5f8640fb
LP
1522 }
1523
1524 free(c->selinux_context);
1525 c->selinux_context = k;
1526 c->selinux_context_ignore = ignore;
1527
1528 return 0;
1529}
1530
eef65bf3
MS
1531int config_parse_exec_apparmor_profile(
1532 const char *unit,
1533 const char *filename,
1534 unsigned line,
1535 const char *section,
1536 unsigned section_line,
1537 const char *lvalue,
1538 int ltype,
1539 const char *rvalue,
1540 void *data,
1541 void *userdata) {
1542
1543 ExecContext *c = data;
1544 Unit *u = userdata;
1545 bool ignore;
1546 char *k;
1547 int r;
1548
1549 assert(filename);
1550 assert(lvalue);
1551 assert(rvalue);
1552 assert(data);
1553
1554 if (isempty(rvalue)) {
a1e58e8e 1555 c->apparmor_profile = mfree(c->apparmor_profile);
eef65bf3
MS
1556 c->apparmor_profile_ignore = false;
1557 return 0;
1558 }
1559
1560 if (rvalue[0] == '-') {
1561 ignore = true;
1562 rvalue++;
1563 } else
1564 ignore = false;
1565
18913df9 1566 r = unit_full_printf(u, rvalue, &k);
eef65bf3 1567 if (r < 0) {
bb28e684
ZJS
1568 log_syntax(unit, LOG_ERR, filename, line, r,
1569 "Failed to resolve specifiers%s: %m",
1570 ignore ? ", ignoring" : "");
1571 return ignore ? 0 : -ENOEXEC;
eef65bf3
MS
1572 }
1573
1574 free(c->apparmor_profile);
1575 c->apparmor_profile = k;
1576 c->apparmor_profile_ignore = ignore;
1577
1578 return 0;
1579}
1580
2ca620c4
WC
1581int config_parse_exec_smack_process_label(
1582 const char *unit,
1583 const char *filename,
1584 unsigned line,
1585 const char *section,
1586 unsigned section_line,
1587 const char *lvalue,
1588 int ltype,
1589 const char *rvalue,
1590 void *data,
1591 void *userdata) {
1592
1593 ExecContext *c = data;
1594 Unit *u = userdata;
1595 bool ignore;
1596 char *k;
1597 int r;
1598
1599 assert(filename);
1600 assert(lvalue);
1601 assert(rvalue);
1602 assert(data);
1603
1604 if (isempty(rvalue)) {
a1e58e8e 1605 c->smack_process_label = mfree(c->smack_process_label);
2ca620c4
WC
1606 c->smack_process_label_ignore = false;
1607 return 0;
1608 }
1609
1610 if (rvalue[0] == '-') {
1611 ignore = true;
1612 rvalue++;
1613 } else
1614 ignore = false;
1615
18913df9 1616 r = unit_full_printf(u, rvalue, &k);
2ca620c4 1617 if (r < 0) {
bb28e684
ZJS
1618 log_syntax(unit, LOG_ERR, filename, line, r,
1619 "Failed to resolve specifiers%s: %m",
1620 ignore ? ", ignoring" : "");
1621 return ignore ? 0 : -ENOEXEC;
2ca620c4
WC
1622 }
1623
1624 free(c->smack_process_label);
1625 c->smack_process_label = k;
1626 c->smack_process_label_ignore = ignore;
1627
1628 return 0;
1629}
1630
e8e581bf
ZJS
1631int config_parse_timer(const char *unit,
1632 const char *filename,
1633 unsigned line,
1634 const char *section,
71a61510 1635 unsigned section_line,
e8e581bf
ZJS
1636 const char *lvalue,
1637 int ltype,
1638 const char *rvalue,
1639 void *data,
1640 void *userdata) {
871d7de4
LP
1641
1642 Timer *t = data;
2507992f 1643 usec_t usec = 0;
871d7de4
LP
1644 TimerValue *v;
1645 TimerBase b;
36697dc0 1646 CalendarSpec *c = NULL;
2507992f
DC
1647 Unit *u = userdata;
1648 _cleanup_free_ char *k = NULL;
1649 int r;
871d7de4
LP
1650
1651 assert(filename);
1652 assert(lvalue);
1653 assert(rvalue);
1654 assert(data);
1655
74051b9b
LP
1656 if (isempty(rvalue)) {
1657 /* Empty assignment resets list */
1658 timer_free_values(t);
1659 return 0;
1660 }
1661
36697dc0
LP
1662 b = timer_base_from_string(lvalue);
1663 if (b < 0) {
12ca818f 1664 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
c0b34696 1665 return 0;
871d7de4
LP
1666 }
1667
2507992f
DC
1668 r = unit_full_printf(u, rvalue, &k);
1669 if (r < 0) {
1670 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1671 return 0;
1672 }
1673
36697dc0 1674 if (b == TIMER_CALENDAR) {
2507992f
DC
1675 if (calendar_spec_from_string(k, &c) < 0) {
1676 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k);
36697dc0
LP
1677 return 0;
1678 }
36697dc0 1679 } else {
2507992f
DC
1680 if (parse_sec(k, &usec) < 0) {
1681 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k);
36697dc0
LP
1682 return 0;
1683 }
871d7de4
LP
1684 }
1685
36697dc0 1686 v = new0(TimerValue, 1);
4d5e13a1 1687 if (!v) {
0b76b4d8 1688 calendar_spec_free(c);
74051b9b 1689 return log_oom();
4d5e13a1 1690 }
871d7de4
LP
1691
1692 v->base = b;
2507992f 1693 v->value = usec;
36697dc0 1694 v->calendar_spec = c;
871d7de4 1695
71fda00f 1696 LIST_PREPEND(value, t->values, v);
871d7de4
LP
1697
1698 return 0;
1699}
1700
3ecaa09b
LP
1701int config_parse_trigger_unit(
1702 const char *unit,
1703 const char *filename,
1704 unsigned line,
1705 const char *section,
71a61510 1706 unsigned section_line,
3ecaa09b
LP
1707 const char *lvalue,
1708 int ltype,
1709 const char *rvalue,
1710 void *data,
1711 void *userdata) {
871d7de4 1712
74051b9b 1713 _cleanup_free_ char *p = NULL;
3ecaa09b
LP
1714 Unit *u = data;
1715 UnitType type;
1716 int r;
398ef8ba
LP
1717
1718 assert(filename);
1719 assert(lvalue);
1720 assert(rvalue);
1721 assert(data);
1722
eef85c4a 1723 if (!hashmap_isempty(u->dependencies[UNIT_TRIGGERS])) {
12ca818f 1724 log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
3ecaa09b
LP
1725 return 0;
1726 }
871d7de4 1727
19f6d710 1728 r = unit_name_printf(u, rvalue, &p);
12ca818f
LP
1729 if (r < 0) {
1730 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1731 return 0;
1732 }
74051b9b 1733
12ca818f 1734 type = unit_name_to_type(p);
3ecaa09b 1735 if (type < 0) {
12ca818f 1736 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
c0b34696 1737 return 0;
871d7de4
LP
1738 }
1739
3ecaa09b 1740 if (type == u->type) {
12ca818f 1741 log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
3ecaa09b
LP
1742 return 0;
1743 }
1744
eef85c4a 1745 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true, UNIT_DEPENDENCY_FILE);
57020a3a 1746 if (r < 0) {
12ca818f 1747 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
c0b34696 1748 return 0;
871d7de4
LP
1749 }
1750
1751 return 0;
1752}
1753
e8e581bf
ZJS
1754int config_parse_path_spec(const char *unit,
1755 const char *filename,
1756 unsigned line,
1757 const char *section,
71a61510 1758 unsigned section_line,
e8e581bf
ZJS
1759 const char *lvalue,
1760 int ltype,
1761 const char *rvalue,
1762 void *data,
1763 void *userdata) {
01f78473
LP
1764
1765 Path *p = data;
1766 PathSpec *s;
1767 PathType b;
7fd1b19b 1768 _cleanup_free_ char *k = NULL;
19f6d710 1769 int r;
01f78473
LP
1770
1771 assert(filename);
1772 assert(lvalue);
1773 assert(rvalue);
1774 assert(data);
1775
74051b9b
LP
1776 if (isempty(rvalue)) {
1777 /* Empty assignment clears list */
1778 path_free_specs(p);
1779 return 0;
1780 }
1781
93e4c84b
LP
1782 b = path_type_from_string(lvalue);
1783 if (b < 0) {
12ca818f 1784 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 1785 return 0;
01f78473
LP
1786 }
1787
19f6d710
LP
1788 r = unit_full_printf(UNIT(p), rvalue, &k);
1789 if (r < 0) {
12ca818f
LP
1790 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1791 return 0;
487060c2 1792 }
93e4c84b
LP
1793
1794 if (!path_is_absolute(k)) {
12ca818f 1795 log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
c0b34696 1796 return 0;
01f78473
LP
1797 }
1798
93e4c84b 1799 s = new0(PathSpec, 1);
543295ad 1800 if (!s)
93e4c84b 1801 return log_oom();
01f78473 1802
718db961 1803 s->unit = UNIT(p);
93e4c84b 1804 s->path = path_kill_slashes(k);
543295ad 1805 k = NULL;
01f78473
LP
1806 s->type = b;
1807 s->inotify_fd = -1;
1808
71fda00f 1809 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
1810
1811 return 0;
1812}
1813
b02cb41c
LP
1814int config_parse_socket_service(
1815 const char *unit,
1816 const char *filename,
1817 unsigned line,
1818 const char *section,
1819 unsigned section_line,
1820 const char *lvalue,
1821 int ltype,
1822 const char *rvalue,
1823 void *data,
1824 void *userdata) {
d9ff321a 1825
4afd3348 1826 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8dd4c05b 1827 _cleanup_free_ char *p = NULL;
d9ff321a 1828 Socket *s = data;
4ff77f66 1829 Unit *x;
8dd4c05b 1830 int r;
d9ff321a
LP
1831
1832 assert(filename);
1833 assert(lvalue);
1834 assert(rvalue);
1835 assert(data);
1836
19f6d710 1837 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 1838 if (r < 0) {
bb28e684
ZJS
1839 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers: %s", rvalue);
1840 return -ENOEXEC;
613b411c 1841 }
74051b9b 1842
613b411c 1843 if (!endswith(p, ".service")) {
bb28e684
ZJS
1844 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service: %s", rvalue);
1845 return -ENOEXEC;
d9ff321a
LP
1846 }
1847
613b411c 1848 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 1849 if (r < 0) {
bb28e684
ZJS
1850 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s: %s", rvalue, bus_error_message(&error, r));
1851 return -ENOEXEC;
d9ff321a
LP
1852 }
1853
4ff77f66
LP
1854 unit_ref_set(&s->service, x);
1855
d9ff321a
LP
1856 return 0;
1857}
1858
8dd4c05b
LP
1859int config_parse_fdname(
1860 const char *unit,
1861 const char *filename,
1862 unsigned line,
1863 const char *section,
1864 unsigned section_line,
1865 const char *lvalue,
1866 int ltype,
1867 const char *rvalue,
1868 void *data,
1869 void *userdata) {
1870
1871 _cleanup_free_ char *p = NULL;
1872 Socket *s = data;
1873 int r;
1874
1875 assert(filename);
1876 assert(lvalue);
1877 assert(rvalue);
1878 assert(data);
1879
1880 if (isempty(rvalue)) {
1881 s->fdname = mfree(s->fdname);
1882 return 0;
1883 }
1884
18913df9 1885 r = unit_full_printf(UNIT(s), rvalue, &p);
8dd4c05b
LP
1886 if (r < 0) {
1887 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1888 return 0;
1889 }
1890
1891 if (!fdname_is_valid(p)) {
1892 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
1893 return 0;
1894 }
1895
3b319885 1896 return free_and_replace(s->fdname, p);
8dd4c05b
LP
1897}
1898
b02cb41c
LP
1899int config_parse_service_sockets(
1900 const char *unit,
1901 const char *filename,
1902 unsigned line,
1903 const char *section,
1904 unsigned section_line,
1905 const char *lvalue,
1906 int ltype,
1907 const char *rvalue,
1908 void *data,
1909 void *userdata) {
f976f3f6
LP
1910
1911 Service *s = data;
7b2313f5 1912 const char *p;
b02cb41c 1913 int r;
f976f3f6
LP
1914
1915 assert(filename);
1916 assert(lvalue);
1917 assert(rvalue);
1918 assert(data);
1919
7b2313f5 1920 p = rvalue;
9ed794a3 1921 for (;;) {
6a0f3175 1922 _cleanup_free_ char *word = NULL, *k = NULL;
f976f3f6 1923
7b2313f5
SS
1924 r = extract_first_word(&p, &word, NULL, 0);
1925 if (r == 0)
1926 break;
1927 if (r == -ENOMEM)
74051b9b 1928 return log_oom();
7b2313f5
SS
1929 if (r < 0) {
1930 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
1931 break;
1932 }
f976f3f6 1933
7b2313f5 1934 r = unit_name_printf(UNIT(s), word, &k);
b02cb41c
LP
1935 if (r < 0) {
1936 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1937 continue;
1938 }
57020a3a 1939
b02cb41c 1940 if (!endswith(k, ".socket")) {
12ca818f 1941 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
f976f3f6
LP
1942 continue;
1943 }
1944
eef85c4a 1945 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true, UNIT_DEPENDENCY_FILE);
57020a3a 1946 if (r < 0)
b02cb41c 1947 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6 1948
eef85c4a 1949 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true, UNIT_DEPENDENCY_FILE);
57020a3a 1950 if (r < 0)
b02cb41c 1951 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
f976f3f6
LP
1952 }
1953
1954 return 0;
1955}
1956
b02cb41c
LP
1957int config_parse_bus_name(
1958 const char *unit,
1959 const char *filename,
1960 unsigned line,
1961 const char *section,
1962 unsigned section_line,
1963 const char *lvalue,
1964 int ltype,
1965 const char *rvalue,
1966 void *data,
1967 void *userdata) {
1968
1969 _cleanup_free_ char *k = NULL;
1970 Unit *u = userdata;
1971 int r;
1972
1973 assert(filename);
1974 assert(lvalue);
1975 assert(rvalue);
1976 assert(u);
1977
1978 r = unit_full_printf(u, rvalue, &k);
1979 if (r < 0) {
1980 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1981 return 0;
1982 }
1983
1984 if (!service_name_is_valid(k)) {
12ca818f 1985 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
b02cb41c
LP
1986 return 0;
1987 }
1988
1989 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1990}
1991
aad41f08
LP
1992int config_parse_service_timeout(
1993 const char *unit,
1994 const char *filename,
1995 unsigned line,
1996 const char *section,
1997 unsigned section_line,
1998 const char *lvalue,
1999 int ltype,
2000 const char *rvalue,
2001 void *data,
2002 void *userdata) {
98709151
LN
2003
2004 Service *s = userdata;
aad41f08 2005 usec_t usec;
98709151
LN
2006 int r;
2007
2008 assert(filename);
2009 assert(lvalue);
2010 assert(rvalue);
2011 assert(s);
2012
aad41f08 2013 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
98709151 2014
aad41f08
LP
2015 r = parse_sec(rvalue, &usec);
2016 if (r < 0) {
2017 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
2018 return 0;
2019 }
d568a335 2020
36c16a7c
LP
2021 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
2022 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
2023 * all other timeouts. */
aad41f08
LP
2024 if (usec <= 0)
2025 usec = USEC_INFINITY;
2026
2027 if (!streq(lvalue, "TimeoutStopSec")) {
2028 s->start_timeout_defined = true;
2029 s->timeout_start_usec = usec;
2030 }
36c16a7c 2031
aad41f08
LP
2032 if (!streq(lvalue, "TimeoutStartSec"))
2033 s->timeout_stop_usec = usec;
36c16a7c 2034
d568a335 2035 return 0;
98709151
LN
2036}
2037
89beff89
LP
2038int config_parse_sec_fix_0(
2039 const char *unit,
2040 const char *filename,
2041 unsigned line,
2042 const char *section,
2043 unsigned section_line,
2044 const char *lvalue,
2045 int ltype,
2046 const char *rvalue,
2047 void *data,
2048 void *userdata) {
2049
2050 usec_t *usec = data;
2051 int r;
2052
2053 assert(filename);
2054 assert(lvalue);
2055 assert(rvalue);
2056 assert(usec);
2057
2058 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
2059 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
2060 * timeout. */
2061
0004f698 2062 r = parse_sec_fix_0(rvalue, usec);
89beff89
LP
2063 if (r < 0) {
2064 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
2065 return 0;
2066 }
2067
89beff89
LP
2068 return 0;
2069}
2070
66dccd8d
LP
2071int config_parse_user_group(
2072 const char *unit,
2073 const char *filename,
2074 unsigned line,
2075 const char *section,
2076 unsigned section_line,
2077 const char *lvalue,
2078 int ltype,
2079 const char *rvalue,
2080 void *data,
2081 void *userdata) {
2082
2083 char **user = data, *n;
2084 Unit *u = userdata;
2085 int r;
2086
2087 assert(filename);
2088 assert(lvalue);
2089 assert(rvalue);
2090 assert(u);
2091
2092 if (isempty(rvalue))
2093 n = NULL;
2094 else {
2095 _cleanup_free_ char *k = NULL;
2096
2097 r = unit_full_printf(u, rvalue, &k);
2098 if (r < 0) {
bb28e684
ZJS
2099 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
2100 return -ENOEXEC;
66dccd8d
LP
2101 }
2102
2103 if (!valid_user_group_name_or_id(k)) {
bb28e684
ZJS
2104 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
2105 return -ENOEXEC;
66dccd8d
LP
2106 }
2107
2108 n = k;
2109 k = NULL;
2110 }
2111
2112 free(*user);
2113 *user = n;
2114
2115 return 0;
2116}
2117
2118int config_parse_user_group_strv(
2119 const char *unit,
2120 const char *filename,
2121 unsigned line,
2122 const char *section,
2123 unsigned section_line,
2124 const char *lvalue,
2125 int ltype,
2126 const char *rvalue,
2127 void *data,
2128 void *userdata) {
2129
2130 char ***users = data;
2131 Unit *u = userdata;
2132 const char *p;
2133 int r;
2134
2135 assert(filename);
2136 assert(lvalue);
2137 assert(rvalue);
2138 assert(u);
2139
2140 if (isempty(rvalue)) {
9f2d41a6 2141 *users = strv_free(*users);
66dccd8d
LP
2142 return 0;
2143 }
2144
2145 p = rvalue;
2146 for (;;) {
2147 _cleanup_free_ char *word = NULL, *k = NULL;
2148
9a82ab95 2149 r = extract_first_word(&p, &word, NULL, 0);
66dccd8d
LP
2150 if (r == 0)
2151 break;
2152 if (r == -ENOMEM)
2153 return log_oom();
2154 if (r < 0) {
bb28e684
ZJS
2155 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax: %s", rvalue);
2156 return -ENOEXEC;
66dccd8d
LP
2157 }
2158
2159 r = unit_full_printf(u, word, &k);
2160 if (r < 0) {
bb28e684
ZJS
2161 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", word);
2162 return -ENOEXEC;
66dccd8d
LP
2163 }
2164
2165 if (!valid_user_group_name_or_id(k)) {
bb28e684
ZJS
2166 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
2167 return -ENOEXEC;
66dccd8d
LP
2168 }
2169
2170 r = strv_push(users, k);
2171 if (r < 0)
2172 return log_oom();
2173
2174 k = NULL;
2175 }
2176
2177 return 0;
2178}
2179
5f5d8eab
LP
2180int config_parse_working_directory(
2181 const char *unit,
2182 const char *filename,
2183 unsigned line,
2184 const char *section,
2185 unsigned section_line,
2186 const char *lvalue,
2187 int ltype,
2188 const char *rvalue,
2189 void *data,
2190 void *userdata) {
2191
2192 ExecContext *c = data;
2193 Unit *u = userdata;
2194 bool missing_ok;
2195 int r;
2196
2197 assert(filename);
2198 assert(lvalue);
2199 assert(rvalue);
2200 assert(c);
2201 assert(u);
2202
2203 if (rvalue[0] == '-') {
2204 missing_ok = true;
2205 rvalue++;
2206 } else
2207 missing_ok = false;
2208
2209 if (streq(rvalue, "~")) {
2210 c->working_directory_home = true;
2211 c->working_directory = mfree(c->working_directory);
2212 } else {
2213 _cleanup_free_ char *k = NULL;
2214
2215 r = unit_full_printf(u, rvalue, &k);
2216 if (r < 0) {
bb28e684
ZJS
2217 log_syntax(unit, LOG_ERR, filename, line, r,
2218 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2219 rvalue, missing_ok ? ", ignoring" : "");
2220 return missing_ok ? 0 : -ENOEXEC;
5f5d8eab
LP
2221 }
2222
2223 path_kill_slashes(k);
2224
2225 if (!utf8_is_valid(k)) {
0e05ee04 2226 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
bb28e684 2227 return missing_ok ? 0 : -ENOEXEC;
5f5d8eab
LP
2228 }
2229
2230 if (!path_is_absolute(k)) {
bb28e684
ZJS
2231 log_syntax(unit, LOG_ERR, filename, line, 0,
2232 "Working directory path '%s' is not absolute%s.",
2233 rvalue, missing_ok ? ", ignoring" : "");
2234 return missing_ok ? 0 : -ENOEXEC;
5f5d8eab
LP
2235 }
2236
5f5d8eab 2237 c->working_directory_home = false;
bb28e684 2238 free_and_replace(c->working_directory, k);
5f5d8eab
LP
2239 }
2240
2241 c->working_directory_missing_ok = missing_ok;
2242 return 0;
2243}
2244
e8e581bf
ZJS
2245int config_parse_unit_env_file(const char *unit,
2246 const char *filename,
2247 unsigned line,
2248 const char *section,
71a61510 2249 unsigned section_line,
e8e581bf
ZJS
2250 const char *lvalue,
2251 int ltype,
2252 const char *rvalue,
2253 void *data,
2254 void *userdata) {
ddb26e18 2255
853b8397 2256 char ***env = data;
8fef7659 2257 Unit *u = userdata;
19f6d710 2258 _cleanup_free_ char *n = NULL;
853b8397 2259 int r;
ddb26e18
LP
2260
2261 assert(filename);
2262 assert(lvalue);
2263 assert(rvalue);
2264 assert(data);
2265
74051b9b
LP
2266 if (isempty(rvalue)) {
2267 /* Empty assignment frees the list */
6796073e 2268 *env = strv_free(*env);
74051b9b
LP
2269 return 0;
2270 }
2271
19f6d710 2272 r = unit_full_printf(u, rvalue, &n);
12ca818f
LP
2273 if (r < 0) {
2274 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2275 return 0;
2276 }
8fef7659 2277
12ca818f
LP
2278 if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
2279 log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
afe4bfe2
LP
2280 return 0;
2281 }
2282
12ca818f 2283 r = strv_extend(env, n);
853b8397
LP
2284 if (r < 0)
2285 return log_oom();
2286
2287 return 0;
2288}
2289
f7f3f5c3
LP
2290int config_parse_environ(
2291 const char *unit,
2292 const char *filename,
2293 unsigned line,
2294 const char *section,
2295 unsigned section_line,
2296 const char *lvalue,
2297 int ltype,
2298 const char *rvalue,
2299 void *data,
2300 void *userdata) {
853b8397
LP
2301
2302 Unit *u = userdata;
035fe294
ZJS
2303 char ***env = data;
2304 const char *p;
19f6d710 2305 int r;
853b8397
LP
2306
2307 assert(filename);
2308 assert(lvalue);
2309 assert(rvalue);
97d0e5f8 2310 assert(data);
853b8397
LP
2311
2312 if (isempty(rvalue)) {
2313 /* Empty assignment resets the list */
6796073e 2314 *env = strv_free(*env);
853b8397
LP
2315 return 0;
2316 }
2317
035fe294
ZJS
2318 for (p = rvalue;; ) {
2319 _cleanup_free_ char *word = NULL, *k = NULL;
035fe294
ZJS
2320
2321 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
2322 if (r == 0)
2323 return 0;
2324 if (r == -ENOMEM)
2325 return log_oom();
12ca818f 2326 if (r < 0) {
035fe294
ZJS
2327 log_syntax(unit, LOG_WARNING, filename, line, r,
2328 "Invalid syntax, ignoring: %s", rvalue);
12ca818f
LP
2329 return 0;
2330 }
97d0e5f8 2331
035fe294
ZJS
2332 if (u) {
2333 r = unit_full_printf(u, word, &k);
2334 if (r < 0) {
2335 log_syntax(unit, LOG_ERR, filename, line, r,
f7f3f5c3 2336 "Failed to resolve specifiers, ignoring: %s", word);
035fe294
ZJS
2337 continue;
2338 }
2339 } else {
2340 k = word;
2341 word = NULL;
527b7a42 2342 }
853b8397 2343
035fe294
ZJS
2344 if (!env_assignment_is_valid(k)) {
2345 log_syntax(unit, LOG_ERR, filename, line, 0,
2346 "Invalid environment assignment, ignoring: %s", k);
853b8397
LP
2347 continue;
2348 }
2349
54ac3494
ZJS
2350 r = strv_env_replace(env, k);
2351 if (r < 0)
853b8397 2352 return log_oom();
f7f3f5c3 2353
54ac3494 2354 k = NULL;
853b8397 2355 }
ddb26e18
LP
2356}
2357
00819cc1
LP
2358int config_parse_pass_environ(
2359 const char *unit,
2360 const char *filename,
2361 unsigned line,
2362 const char *section,
2363 unsigned section_line,
2364 const char *lvalue,
2365 int ltype,
2366 const char *rvalue,
2367 void *data,
2368 void *userdata) {
b4c14404
FB
2369
2370 const char *whole_rvalue = rvalue;
b4c14404
FB
2371 _cleanup_strv_free_ char **n = NULL;
2372 size_t nlen = 0, nbufsize = 0;
41de9cc2
LP
2373 char*** passenv = data;
2374 Unit *u = userdata;
b4c14404
FB
2375 int r;
2376
2377 assert(filename);
2378 assert(lvalue);
2379 assert(rvalue);
2380 assert(data);
2381
2382 if (isempty(rvalue)) {
2383 /* Empty assignment resets the list */
2384 *passenv = strv_free(*passenv);
2385 return 0;
2386 }
2387
2388 for (;;) {
41de9cc2 2389 _cleanup_free_ char *word = NULL, *k = NULL;
b4c14404 2390
9a82ab95 2391 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
b4c14404
FB
2392 if (r == 0)
2393 break;
2394 if (r == -ENOMEM)
2395 return log_oom();
2396 if (r < 0) {
2397 log_syntax(unit, LOG_ERR, filename, line, r,
2398 "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
2399 break;
2400 }
2401
41de9cc2
LP
2402 if (u) {
2403 r = unit_full_printf(u, word, &k);
2404 if (r < 0) {
2405 log_syntax(unit, LOG_ERR, filename, line, r,
2406 "Failed to resolve specifiers, ignoring: %s", word);
2407 continue;
2408 }
2409 } else {
2410 k = word;
2411 word = NULL;
2412 }
2413
2414 if (!env_name_is_valid(k)) {
2415 log_syntax(unit, LOG_ERR, filename, line, 0,
2416 "Invalid environment name for %s, ignoring: %s", lvalue, k);
b4c14404
FB
2417 continue;
2418 }
2419
2420 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2421 return log_oom();
41de9cc2
LP
2422
2423 n[nlen++] = k;
b4c14404 2424 n[nlen] = NULL;
41de9cc2 2425 k = NULL;
b4c14404
FB
2426 }
2427
2428 if (n) {
2429 r = strv_extend_strv(passenv, n, true);
2430 if (r < 0)
2431 return r;
2432 }
2433
2434 return 0;
2435}
2436
00819cc1
LP
2437int config_parse_unset_environ(
2438 const char *unit,
2439 const char *filename,
2440 unsigned line,
2441 const char *section,
2442 unsigned section_line,
2443 const char *lvalue,
2444 int ltype,
2445 const char *rvalue,
2446 void *data,
2447 void *userdata) {
2448
2449 _cleanup_strv_free_ char **n = NULL;
2450 const char *whole_rvalue = rvalue;
2451 size_t nlen = 0, nbufsize = 0;
2452 char*** unsetenv = data;
2453 Unit *u = userdata;
2454 int r;
2455
2456 assert(filename);
2457 assert(lvalue);
2458 assert(rvalue);
2459 assert(data);
2460
2461 if (isempty(rvalue)) {
2462 /* Empty assignment resets the list */
2463 *unsetenv = strv_free(*unsetenv);
2464 return 0;
2465 }
2466
2467 for (;;) {
2468 _cleanup_free_ char *word = NULL, *k = NULL;
2469
6c5def2f 2470 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
00819cc1
LP
2471 if (r == 0)
2472 break;
2473 if (r == -ENOMEM)
2474 return log_oom();
2475 if (r < 0) {
2476 log_syntax(unit, LOG_ERR, filename, line, r,
2477 "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
2478 break;
2479 }
2480
2481 if (u) {
2482 r = unit_full_printf(u, word, &k);
2483 if (r < 0) {
2484 log_syntax(unit, LOG_ERR, filename, line, r,
2485 "Failed to resolve specifiers, ignoring: %s", word);
2486 continue;
2487 }
2488 } else {
2489 k = word;
2490 word = NULL;
2491 }
2492
2493 if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
2494 log_syntax(unit, LOG_ERR, filename, line, 0,
2495 "Invalid environment name or assignment %s, ignoring: %s", lvalue, k);
2496 continue;
2497 }
2498
2499 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2500 return log_oom();
2501
2502 n[nlen++] = k;
2503 n[nlen] = NULL;
2504 k = NULL;
2505 }
2506
2507 if (n) {
2508 r = strv_extend_strv(unsetenv, n, true);
2509 if (r < 0)
2510 return r;
2511 }
2512
2513 return 0;
2514}
2515
d3070fbd
LP
2516int config_parse_log_extra_fields(
2517 const char *unit,
2518 const char *filename,
2519 unsigned line,
2520 const char *section,
2521 unsigned section_line,
2522 const char *lvalue,
2523 int ltype,
2524 const char *rvalue,
2525 void *data,
2526 void *userdata) {
2527
2528 ExecContext *c = data;
2529 Unit *u = userdata;
2530 const char *p;
2531 int r;
2532
2533 assert(filename);
2534 assert(lvalue);
2535 assert(rvalue);
2536 assert(c);
2537
2538 if (isempty(rvalue)) {
2539 exec_context_free_log_extra_fields(c);
2540 return 0;
2541 }
2542
2543 for (p = rvalue;; ) {
2544 _cleanup_free_ char *word = NULL, *k = NULL;
2545 struct iovec *t;
2546 const char *eq;
2547
2548 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
2549 if (r == 0)
2550 break;
2551 if (r == -ENOMEM)
2552 return log_oom();
2553 if (r < 0) {
2554 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
2555 return 0;
2556 }
2557
2558 r = unit_full_printf(u, word, &k);
2559 if (r < 0) {
2560 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring field: %m", word);
2561 continue;
2562 }
2563
2564 eq = strchr(k, '=');
2565 if (!eq) {
2566 log_syntax(unit, LOG_ERR, filename, line, 0, "Log field lacks '=' character, ignoring field: %s", k);
2567 continue;
2568 }
2569
2570 if (!journal_field_valid(k, eq-k, false)) {
2571 log_syntax(unit, LOG_ERR, filename, line, 0, "Log field name is invalid, ignoring field: %s", k);
2572 continue;
2573 }
2574
2575 t = realloc_multiply(c->log_extra_fields, sizeof(struct iovec), c->n_log_extra_fields+1);
2576 if (!t)
2577 return log_oom();
2578
2579 c->log_extra_fields = t;
2580 c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE_STRING(k);
2581
2582 k = NULL;
2583 }
2584
2585 return 0;
2586}
2587
e8e581bf
ZJS
2588int config_parse_ip_tos(const char *unit,
2589 const char *filename,
2590 unsigned line,
2591 const char *section,
71a61510 2592 unsigned section_line,
e8e581bf
ZJS
2593 const char *lvalue,
2594 int ltype,
2595 const char *rvalue,
2596 void *data,
2597 void *userdata) {
4fd5948e
LP
2598
2599 int *ip_tos = data, x;
4fd5948e
LP
2600
2601 assert(filename);
2602 assert(lvalue);
2603 assert(rvalue);
2604 assert(data);
2605
f8b69d1d
MS
2606 x = ip_tos_from_string(rvalue);
2607 if (x < 0) {
12ca818f 2608 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
f8b69d1d
MS
2609 return 0;
2610 }
4fd5948e
LP
2611
2612 *ip_tos = x;
2613 return 0;
2614}
2615
59fccdc5
LP
2616int config_parse_unit_condition_path(
2617 const char *unit,
2618 const char *filename,
2619 unsigned line,
2620 const char *section,
2621 unsigned section_line,
2622 const char *lvalue,
2623 int ltype,
2624 const char *rvalue,
2625 void *data,
2626 void *userdata) {
52661efd 2627
2fbe635a 2628 _cleanup_free_ char *p = NULL;
59fccdc5
LP
2629 Condition **list = data, *c;
2630 ConditionType t = ltype;
2631 bool trigger, negate;
2632 Unit *u = userdata;
19f6d710 2633 int r;
52661efd
LP
2634
2635 assert(filename);
2636 assert(lvalue);
2637 assert(rvalue);
2638 assert(data);
2639
74051b9b
LP
2640 if (isempty(rvalue)) {
2641 /* Empty assignment resets the list */
447021aa 2642 *list = condition_free_list(*list);
74051b9b
LP
2643 return 0;
2644 }
2645
ab7f148f
LP
2646 trigger = rvalue[0] == '|';
2647 if (trigger)
267632f0
LP
2648 rvalue++;
2649
ab7f148f
LP
2650 negate = rvalue[0] == '!';
2651 if (negate)
52661efd
LP
2652 rvalue++;
2653
19f6d710 2654 r = unit_full_printf(u, rvalue, &p);
59fccdc5 2655 if (r < 0) {
12ca818f 2656 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
59fccdc5 2657 return 0;
19f6d710 2658 }
095b2d7a
AK
2659
2660 if (!path_is_absolute(p)) {
12ca818f 2661 log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
52661efd
LP
2662 return 0;
2663 }
2664
59fccdc5 2665 c = condition_new(t, p, trigger, negate);
ab7f148f 2666 if (!c)
74051b9b 2667 return log_oom();
52661efd 2668
59fccdc5 2669 LIST_PREPEND(conditions, *list, c);
52661efd
LP
2670 return 0;
2671}
2672
59fccdc5
LP
2673int config_parse_unit_condition_string(
2674 const char *unit,
2675 const char *filename,
2676 unsigned line,
2677 const char *section,
2678 unsigned section_line,
2679 const char *lvalue,
2680 int ltype,
2681 const char *rvalue,
2682 void *data,
2683 void *userdata) {
039655a4 2684
2fbe635a 2685 _cleanup_free_ char *s = NULL;
59fccdc5
LP
2686 Condition **list = data, *c;
2687 ConditionType t = ltype;
2688 bool trigger, negate;
2689 Unit *u = userdata;
19f6d710 2690 int r;
039655a4
LP
2691
2692 assert(filename);
2693 assert(lvalue);
2694 assert(rvalue);
2695 assert(data);
2696
74051b9b
LP
2697 if (isempty(rvalue)) {
2698 /* Empty assignment resets the list */
447021aa 2699 *list = condition_free_list(*list);
74051b9b
LP
2700 return 0;
2701 }
2702
c0d6e764
LP
2703 trigger = rvalue[0] == '|';
2704 if (trigger)
267632f0
LP
2705 rvalue++;
2706
c0d6e764
LP
2707 negate = rvalue[0] == '!';
2708 if (negate)
039655a4
LP
2709 rvalue++;
2710
19f6d710 2711 r = unit_full_printf(u, rvalue, &s);
59fccdc5 2712 if (r < 0) {
12ca818f 2713 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
59fccdc5 2714 return 0;
19f6d710 2715 }
095b2d7a 2716
59fccdc5 2717 c = condition_new(t, s, trigger, negate);
c0d6e764
LP
2718 if (!c)
2719 return log_oom();
039655a4 2720
59fccdc5 2721 LIST_PREPEND(conditions, *list, c);
039655a4
LP
2722 return 0;
2723}
2724
59fccdc5
LP
2725int config_parse_unit_condition_null(
2726 const char *unit,
2727 const char *filename,
2728 unsigned line,
2729 const char *section,
2730 unsigned section_line,
2731 const char *lvalue,
2732 int ltype,
2733 const char *rvalue,
2734 void *data,
2735 void *userdata) {
d257ddef 2736
59fccdc5 2737 Condition **list = data, *c;
267632f0 2738 bool trigger, negate;
d257ddef
LP
2739 int b;
2740
2741 assert(filename);
2742 assert(lvalue);
2743 assert(rvalue);
2744 assert(data);
2745
74051b9b
LP
2746 if (isempty(rvalue)) {
2747 /* Empty assignment resets the list */
447021aa 2748 *list = condition_free_list(*list);
74051b9b
LP
2749 return 0;
2750 }
2751
2752 trigger = rvalue[0] == '|';
2753 if (trigger)
267632f0
LP
2754 rvalue++;
2755
74051b9b
LP
2756 negate = rvalue[0] == '!';
2757 if (negate)
d257ddef
LP
2758 rvalue++;
2759
74051b9b
LP
2760 b = parse_boolean(rvalue);
2761 if (b < 0) {
12ca818f 2762 log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
d257ddef
LP
2763 return 0;
2764 }
2765
2766 if (!b)
2767 negate = !negate;
2768
74051b9b
LP
2769 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2770 if (!c)
2771 return log_oom();
d257ddef 2772
59fccdc5 2773 LIST_PREPEND(conditions, *list, c);
d257ddef
LP
2774 return 0;
2775}
2776
f975e971 2777DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
87a47f99 2778DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier");
c952c6ec 2779
a57f7e2c
LP
2780int config_parse_unit_requires_mounts_for(
2781 const char *unit,
2782 const char *filename,
2783 unsigned line,
2784 const char *section,
71a61510 2785 unsigned section_line,
a57f7e2c
LP
2786 const char *lvalue,
2787 int ltype,
2788 const char *rvalue,
2789 void *data,
2790 void *userdata) {
7c8fa05c
LP
2791
2792 Unit *u = userdata;
035fe294
ZJS
2793 const char *p;
2794 int r;
7c8fa05c
LP
2795
2796 assert(filename);
2797 assert(lvalue);
2798 assert(rvalue);
2799 assert(data);
2800
035fe294 2801 for (p = rvalue;; ) {
744bb5b1 2802 _cleanup_free_ char *word = NULL, *resolved = NULL;
a57f7e2c 2803
035fe294
ZJS
2804 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
2805 if (r == 0)
2806 return 0;
2807 if (r == -ENOMEM)
a57f7e2c 2808 return log_oom();
035fe294
ZJS
2809 if (r < 0) {
2810 log_syntax(unit, LOG_WARNING, filename, line, r,
2811 "Invalid syntax, ignoring: %s", rvalue);
2812 return 0;
2813 }
7c8fa05c 2814
035fe294 2815 if (!utf8_is_valid(word)) {
0e05ee04 2816 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
a57f7e2c
LP
2817 continue;
2818 }
7c8fa05c 2819
744bb5b1
LP
2820 r = unit_full_printf(u, word, &resolved);
2821 if (r < 0) {
2822 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit name \"%s\", ignoring: %m", word);
2823 continue;
2824 }
2825
eef85c4a 2826 r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
a57f7e2c 2827 if (r < 0) {
744bb5b1 2828 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", resolved);
a57f7e2c
LP
2829 continue;
2830 }
2831 }
7c8fa05c 2832}
9e372868 2833
e8e581bf
ZJS
2834int config_parse_documentation(const char *unit,
2835 const char *filename,
2836 unsigned line,
2837 const char *section,
71a61510 2838 unsigned section_line,
e8e581bf
ZJS
2839 const char *lvalue,
2840 int ltype,
2841 const char *rvalue,
2842 void *data,
2843 void *userdata) {
49dbfa7b
LP
2844
2845 Unit *u = userdata;
2846 int r;
2847 char **a, **b;
2848
2849 assert(filename);
2850 assert(lvalue);
2851 assert(rvalue);
2852 assert(u);
2853
74051b9b
LP
2854 if (isempty(rvalue)) {
2855 /* Empty assignment resets the list */
6796073e 2856 u->documentation = strv_free(u->documentation);
74051b9b
LP
2857 return 0;
2858 }
2859
71a61510 2860 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 2861 rvalue, data, userdata);
49dbfa7b
LP
2862 if (r < 0)
2863 return r;
2864
2865 for (a = b = u->documentation; a && *a; a++) {
2866
a2e03378 2867 if (documentation_url_is_valid(*a))
49dbfa7b
LP
2868 *(b++) = *a;
2869 else {
12ca818f 2870 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
49dbfa7b
LP
2871 free(*a);
2872 }
2873 }
f6d2d421
ZJS
2874 if (b)
2875 *b = NULL;
49dbfa7b
LP
2876
2877 return r;
2878}
2879
349cc4a5 2880#if HAVE_SECCOMP
8130926d 2881
201c1cc2
TM
2882static int syscall_filter_parse_one(
2883 const char *unit,
2884 const char *filename,
2885 unsigned line,
2886 ExecContext *c,
2887 bool invert,
2888 const char *t,
8cfa775f
YW
2889 bool warn,
2890 int errno_num) {
201c1cc2
TM
2891 int r;
2892
8130926d
LP
2893 if (t[0] == '@') {
2894 const SyscallFilterSet *set;
2895 const char *i;
201c1cc2 2896
8130926d
LP
2897 set = syscall_filter_set_find(t);
2898 if (!set) {
2899 if (warn)
ba77dac2 2900 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown system call group, ignoring: %s", t);
8130926d
LP
2901 return 0;
2902 }
201c1cc2 2903
8130926d 2904 NULSTR_FOREACH(i, set->value) {
8cfa775f 2905 r = syscall_filter_parse_one(unit, filename, line, c, invert, i, false, errno_num);
8130926d
LP
2906 if (r < 0)
2907 return r;
2908 }
201c1cc2
TM
2909 } else {
2910 int id;
2911
2912 id = seccomp_syscall_resolve_name(t);
391b81cd 2913 if (id == __NR_SCMP_ERROR) {
201c1cc2 2914 if (warn)
8130926d 2915 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
201c1cc2
TM
2916 return 0;
2917 }
2918
2919 /* If we previously wanted to forbid a syscall and now
ba77dac2 2920 * we want to allow it, then remove it from the list.
201c1cc2
TM
2921 */
2922 if (!invert == c->syscall_whitelist) {
8cfa775f 2923 r = hashmap_put(c->syscall_filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
201c1cc2
TM
2924 if (r == 0)
2925 return 0;
2926 if (r < 0)
2927 return log_oom();
2928 } else
8cfa775f 2929 (void) hashmap_remove(c->syscall_filter, INT_TO_PTR(id + 1));
201c1cc2 2930 }
8130926d 2931
201c1cc2
TM
2932 return 0;
2933}
2934
17df7223
LP
2935int config_parse_syscall_filter(
2936 const char *unit,
2937 const char *filename,
2938 unsigned line,
2939 const char *section,
2940 unsigned section_line,
2941 const char *lvalue,
2942 int ltype,
2943 const char *rvalue,
2944 void *data,
2945 void *userdata) {
2946
8351ceae
LP
2947 ExecContext *c = data;
2948 Unit *u = userdata;
b5fb3789 2949 bool invert = false;
8130926d 2950 const char *p;
17df7223 2951 int r;
8351ceae
LP
2952
2953 assert(filename);
2954 assert(lvalue);
2955 assert(rvalue);
2956 assert(u);
2957
74051b9b
LP
2958 if (isempty(rvalue)) {
2959 /* Empty assignment resets the list */
8cfa775f 2960 c->syscall_filter = hashmap_free(c->syscall_filter);
17df7223 2961 c->syscall_whitelist = false;
74051b9b
LP
2962 return 0;
2963 }
2964
8351ceae
LP
2965 if (rvalue[0] == '~') {
2966 invert = true;
2967 rvalue++;
2968 }
2969
17df7223 2970 if (!c->syscall_filter) {
8cfa775f 2971 c->syscall_filter = hashmap_new(NULL);
17df7223
LP
2972 if (!c->syscall_filter)
2973 return log_oom();
2974
c0467cf3 2975 if (invert)
17df7223
LP
2976 /* Allow everything but the ones listed */
2977 c->syscall_whitelist = false;
c0467cf3 2978 else {
17df7223
LP
2979 /* Allow nothing but the ones listed */
2980 c->syscall_whitelist = true;
8351ceae 2981
17df7223 2982 /* Accept default syscalls if we are on a whitelist */
8cfa775f 2983 r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false, -1);
201c1cc2
TM
2984 if (r < 0)
2985 return r;
c0467cf3 2986 }
8351ceae
LP
2987 }
2988
8130926d
LP
2989 p = rvalue;
2990 for (;;) {
8cfa775f
YW
2991 _cleanup_free_ char *word = NULL, *name = NULL;
2992 int num;
8351ceae 2993
8130926d
LP
2994 r = extract_first_word(&p, &word, NULL, 0);
2995 if (r == 0)
2996 break;
2997 if (r == -ENOMEM)
74051b9b 2998 return log_oom();
8130926d
LP
2999 if (r < 0) {
3000 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
3001 break;
3002 }
8351ceae 3003
8cfa775f
YW
3004 r = parse_syscall_and_errno(word, &name, &num);
3005 if (r < 0) {
3006 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall:errno, ignoring: %s", word);
3007 continue;
3008 }
3009
3010 r = syscall_filter_parse_one(unit, filename, line, c, invert, name, true, num);
201c1cc2
TM
3011 if (r < 0)
3012 return r;
c0467cf3
RC
3013 }
3014
17df7223
LP
3015 return 0;
3016}
3017
57183d11
LP
3018int config_parse_syscall_archs(
3019 const char *unit,
3020 const char *filename,
3021 unsigned line,
3022 const char *section,
3023 unsigned section_line,
3024 const char *lvalue,
3025 int ltype,
3026 const char *rvalue,
3027 void *data,
3028 void *userdata) {
3029
d3b1c508 3030 Set **archs = data;
035fe294 3031 const char *p;
57183d11
LP
3032 int r;
3033
3034 if (isempty(rvalue)) {
525d3cc7 3035 *archs = set_free(*archs);
57183d11
LP
3036 return 0;
3037 }
3038
d5099efc 3039 r = set_ensure_allocated(archs, NULL);
57183d11
LP
3040 if (r < 0)
3041 return log_oom();
3042
035fe294
ZJS
3043 for (p = rvalue;;) {
3044 _cleanup_free_ char *word = NULL;
57183d11
LP
3045 uint32_t a;
3046
035fe294
ZJS
3047 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3048 if (r == 0)
3049 return 0;
3050 if (r == -ENOMEM)
57183d11 3051 return log_oom();
035fe294
ZJS
3052 if (r < 0) {
3053 log_syntax(unit, LOG_WARNING, filename, line, r,
3054 "Invalid syntax, ignoring: %s", rvalue);
3055 return 0;
3056 }
57183d11 3057
035fe294 3058 r = seccomp_arch_from_string(word, &a);
57183d11 3059 if (r < 0) {
035fe294
ZJS
3060 log_syntax(unit, LOG_ERR, filename, line, r,
3061 "Failed to parse system call architecture \"%s\", ignoring: %m", word);
57183d11
LP
3062 continue;
3063 }
3064
d3b1c508 3065 r = set_put(*archs, UINT32_TO_PTR(a + 1));
57183d11
LP
3066 if (r < 0)
3067 return log_oom();
3068 }
57183d11
LP
3069}
3070
17df7223
LP
3071int config_parse_syscall_errno(
3072 const char *unit,
3073 const char *filename,
3074 unsigned line,
3075 const char *section,
3076 unsigned section_line,
3077 const char *lvalue,
3078 int ltype,
3079 const char *rvalue,
3080 void *data,
3081 void *userdata) {
3082
3083 ExecContext *c = data;
3084 int e;
3085
3086 assert(filename);
3087 assert(lvalue);
3088 assert(rvalue);
3089
3090 if (isempty(rvalue)) {
3091 /* Empty assignment resets to KILL */
3092 c->syscall_errno = 0;
3093 return 0;
8351ceae
LP
3094 }
3095
3df90f24
YW
3096 e = parse_errno(rvalue);
3097 if (e <= 0) {
12ca818f 3098 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
17df7223
LP
3099 return 0;
3100 }
8351ceae 3101
17df7223 3102 c->syscall_errno = e;
8351ceae
LP
3103 return 0;
3104}
4298d0b5
LP
3105
3106int config_parse_address_families(
3107 const char *unit,
3108 const char *filename,
3109 unsigned line,
3110 const char *section,
3111 unsigned section_line,
3112 const char *lvalue,
3113 int ltype,
3114 const char *rvalue,
3115 void *data,
3116 void *userdata) {
3117
3118 ExecContext *c = data;
4298d0b5 3119 bool invert = false;
035fe294 3120 const char *p;
4298d0b5
LP
3121 int r;
3122
3123 assert(filename);
3124 assert(lvalue);
3125 assert(rvalue);
4298d0b5
LP
3126
3127 if (isempty(rvalue)) {
3128 /* Empty assignment resets the list */
525d3cc7 3129 c->address_families = set_free(c->address_families);
4298d0b5
LP
3130 c->address_families_whitelist = false;
3131 return 0;
3132 }
3133
3134 if (rvalue[0] == '~') {
3135 invert = true;
3136 rvalue++;
3137 }
3138
3139 if (!c->address_families) {
d5099efc 3140 c->address_families = set_new(NULL);
4298d0b5
LP
3141 if (!c->address_families)
3142 return log_oom();
3143
3144 c->address_families_whitelist = !invert;
3145 }
3146
035fe294
ZJS
3147 for (p = rvalue;;) {
3148 _cleanup_free_ char *word = NULL;
4298d0b5
LP
3149 int af;
3150
035fe294
ZJS
3151 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3152 if (r == 0)
3153 return 0;
3154 if (r == -ENOMEM)
4298d0b5 3155 return log_oom();
035fe294
ZJS
3156 if (r < 0) {
3157 log_syntax(unit, LOG_WARNING, filename, line, r,
3158 "Invalid syntax, ignoring: %s", rvalue);
3159 return 0;
3160 }
4298d0b5 3161
035fe294 3162 af = af_from_name(word);
4298d0b5 3163 if (af <= 0) {
035fe294
ZJS
3164 log_syntax(unit, LOG_ERR, filename, line, 0,
3165 "Failed to parse address family \"%s\", ignoring: %m", word);
4298d0b5
LP
3166 continue;
3167 }
3168
3169 /* If we previously wanted to forbid an address family and now
035fe294 3170 * we want to allow it, then just remove it from the list.
4298d0b5
LP
3171 */
3172 if (!invert == c->address_families_whitelist) {
3173 r = set_put(c->address_families, INT_TO_PTR(af));
4298d0b5
LP
3174 if (r < 0)
3175 return log_oom();
3176 } else
3177 set_remove(c->address_families, INT_TO_PTR(af));
3178 }
4298d0b5 3179}
add00535
LP
3180
3181int config_parse_restrict_namespaces(
3182 const char *unit,
3183 const char *filename,
3184 unsigned line,
3185 const char *section,
3186 unsigned section_line,
3187 const char *lvalue,
3188 int ltype,
3189 const char *rvalue,
3190 void *data,
3191 void *userdata) {
3192
3193 ExecContext *c = data;
3194 bool invert = false;
3195 int r;
3196
3197 if (isempty(rvalue)) {
3198 /* Reset to the default. */
3199 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
3200 return 0;
3201 }
3202
3203 if (rvalue[0] == '~') {
3204 invert = true;
3205 rvalue++;
3206 }
3207
3208 r = parse_boolean(rvalue);
3209 if (r > 0)
3210 c->restrict_namespaces = 0;
3211 else if (r == 0)
3212 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
3213 else {
3214 /* Not a boolean argument, in this case it's a list of namespace types. */
3215
3216 r = namespace_flag_from_string_many(rvalue, &c->restrict_namespaces);
3217 if (r < 0) {
3218 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
3219 return 0;
3220 }
3221 }
3222
3223 if (invert)
3224 c->restrict_namespaces = (~c->restrict_namespaces) & NAMESPACE_FLAGS_ALL;
3225
3226 return 0;
3227}
c0467cf3 3228#endif
8351ceae 3229
a016b922
LP
3230int config_parse_unit_slice(
3231 const char *unit,
3232 const char *filename,
3233 unsigned line,
3234 const char *section,
71a61510 3235 unsigned section_line,
a016b922
LP
3236 const char *lvalue,
3237 int ltype,
3238 const char *rvalue,
3239 void *data,
3240 void *userdata) {
3241
3242 _cleanup_free_ char *k = NULL;
d79200e2 3243 Unit *u = userdata, *slice = NULL;
a016b922
LP
3244 int r;
3245
3246 assert(filename);
3247 assert(lvalue);
3248 assert(rvalue);
3249 assert(u);
3250
19f6d710 3251 r = unit_name_printf(u, rvalue, &k);
d79200e2
LP
3252 if (r < 0) {
3253 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
3254 return 0;
19f6d710 3255 }
a016b922 3256
19f6d710 3257 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
a016b922 3258 if (r < 0) {
d79200e2 3259 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
a016b922
LP
3260 return 0;
3261 }
3262
d79200e2
LP
3263 r = unit_set_slice(u, slice);
3264 if (r < 0) {
3265 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
a016b922
LP
3266 return 0;
3267 }
3268
a016b922
LP
3269 return 0;
3270}
3271
4ad49000
LP
3272DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
3273
66ebf6c0
TH
3274int config_parse_cpu_weight(
3275 const char *unit,
3276 const char *filename,
3277 unsigned line,
3278 const char *section,
3279 unsigned section_line,
3280 const char *lvalue,
3281 int ltype,
3282 const char *rvalue,
3283 void *data,
3284 void *userdata) {
3285
3286 uint64_t *weight = data;
3287 int r;
3288
3289 assert(filename);
3290 assert(lvalue);
3291 assert(rvalue);
3292
3293 r = cg_weight_parse(rvalue, weight);
3294 if (r < 0) {
3295 log_syntax(unit, LOG_ERR, filename, line, r, "CPU weight '%s' invalid. Ignoring.", rvalue);
3296 return 0;
3297 }
3298
3299 return 0;
3300}
3301
4ad49000
LP
3302int config_parse_cpu_shares(
3303 const char *unit,
3304 const char *filename,
3305 unsigned line,
3306 const char *section,
71a61510 3307 unsigned section_line,
4ad49000
LP
3308 const char *lvalue,
3309 int ltype,
3310 const char *rvalue,
3311 void *data,
3312 void *userdata) {
3313
d53d9474 3314 uint64_t *shares = data;
95ae05c0
WC
3315 int r;
3316
3317 assert(filename);
3318 assert(lvalue);
3319 assert(rvalue);
3320
d53d9474
LP
3321 r = cg_cpu_shares_parse(rvalue, shares);
3322 if (r < 0) {
3323 log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
3324 return 0;
3325 }
3326
4ad49000
LP
3327 return 0;
3328}
3329
b2f8b02e
LP
3330int config_parse_cpu_quota(
3331 const char *unit,
3332 const char *filename,
3333 unsigned line,
3334 const char *section,
3335 unsigned section_line,
3336 const char *lvalue,
3337 int ltype,
3338 const char *rvalue,
3339 void *data,
3340 void *userdata) {
3341
3342 CGroupContext *c = data;
9184ca48 3343 int r;
b2f8b02e
LP
3344
3345 assert(filename);
3346 assert(lvalue);
3347 assert(rvalue);
3348
3349 if (isempty(rvalue)) {
3a43da28 3350 c->cpu_quota_per_sec_usec = USEC_INFINITY;
b2f8b02e
LP
3351 return 0;
3352 }
3353
5124866d 3354 r = parse_percent_unbounded(rvalue);
9184ca48
LP
3355 if (r <= 0) {
3356 log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
9a054909 3357 return 0;
b2f8b02e
LP
3358 }
3359
9184ca48 3360 c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
b2f8b02e
LP
3361 return 0;
3362}
3363
4ad49000
LP
3364int config_parse_memory_limit(
3365 const char *unit,
3366 const char *filename,
3367 unsigned line,
3368 const char *section,
71a61510 3369 unsigned section_line,
4ad49000
LP
3370 const char *lvalue,
3371 int ltype,
3372 const char *rvalue,
3373 void *data,
3374 void *userdata) {
3375
3376 CGroupContext *c = data;
da4d897e 3377 uint64_t bytes = CGROUP_LIMIT_MAX;
4ad49000
LP
3378 int r;
3379
e57c9ce1 3380 if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
875ae566
LP
3381
3382 r = parse_percent(rvalue);
3383 if (r < 0) {
3384 r = parse_size(rvalue, 1024, &bytes);
3385 if (r < 0) {
3386 log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
3387 return 0;
3388 }
3389 } else
d8cf2ac7 3390 bytes = physical_memory_scale(r, 100U);
875ae566 3391
b3785cd5
LP
3392 if (bytes <= 0 || bytes >= UINT64_MAX) {
3393 log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
da4d897e
TH
3394 return 0;
3395 }
4ad49000
LP
3396 }
3397
da4d897e
TH
3398 if (streq(lvalue, "MemoryLow"))
3399 c->memory_low = bytes;
3400 else if (streq(lvalue, "MemoryHigh"))
3401 c->memory_high = bytes;
3402 else if (streq(lvalue, "MemoryMax"))
3403 c->memory_max = bytes;
96e131ea
WC
3404 else if (streq(lvalue, "MemorySwapMax"))
3405 c->memory_swap_max = bytes;
3406 else if (streq(lvalue, "MemoryLimit"))
da4d897e 3407 c->memory_limit = bytes;
96e131ea
WC
3408 else
3409 return -EINVAL;
4ad49000 3410
4ad49000
LP
3411 return 0;
3412}
3413
03a7b521
LP
3414int config_parse_tasks_max(
3415 const char *unit,
3416 const char *filename,
3417 unsigned line,
3418 const char *section,
3419 unsigned section_line,
3420 const char *lvalue,
3421 int ltype,
3422 const char *rvalue,
3423 void *data,
3424 void *userdata) {
3425
f5058264
TH
3426 uint64_t *tasks_max = data, v;
3427 Unit *u = userdata;
03a7b521
LP
3428 int r;
3429
f5058264
TH
3430 if (isempty(rvalue)) {
3431 *tasks_max = u->manager->default_tasks_max;
3432 return 0;
3433 }
3434
3435 if (streq(rvalue, "infinity")) {
3436 *tasks_max = CGROUP_LIMIT_MAX;
03a7b521
LP
3437 return 0;
3438 }
3439
83f8e808
LP
3440 r = parse_percent(rvalue);
3441 if (r < 0) {
f5058264 3442 r = safe_atou64(rvalue, &v);
83f8e808
LP
3443 if (r < 0) {
3444 log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
3445 return 0;
3446 }
3447 } else
f5058264 3448 v = system_tasks_max_scale(r, 100U);
83f8e808 3449
f5058264 3450 if (v <= 0 || v >= UINT64_MAX) {
83f8e808 3451 log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
03a7b521
LP
3452 return 0;
3453 }
3454
f5058264 3455 *tasks_max = v;
03a7b521
LP
3456 return 0;
3457}
3458
02638280
LP
3459int config_parse_delegate(
3460 const char *unit,
3461 const char *filename,
3462 unsigned line,
3463 const char *section,
3464 unsigned section_line,
3465 const char *lvalue,
3466 int ltype,
3467 const char *rvalue,
3468 void *data,
3469 void *userdata) {
3470
3471 CGroupContext *c = data;
3472 int r;
3473
3474 /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
3475 * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
3476 * mask to delegate. */
3477
1bdfc7b9
YW
3478 if (isempty(rvalue)) {
3479 c->delegate = true;
3480 c->delegate_controllers = 0;
3481 return 0;
3482 }
3483
02638280
LP
3484 r = parse_boolean(rvalue);
3485 if (r < 0) {
3486 const char *p = rvalue;
3487 CGroupMask mask = 0;
3488
3489 for (;;) {
3490 _cleanup_free_ char *word = NULL;
3491 CGroupController cc;
3492
3493 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3494 if (r == 0)
3495 break;
3496 if (r == -ENOMEM)
3497 return log_oom();
3498 if (r < 0) {
3499 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
3500 return r;
3501 }
3502
3503 cc = cgroup_controller_from_string(word);
3504 if (cc < 0) {
3505 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", rvalue);
3506 continue;
3507 }
3508
3509 mask |= CGROUP_CONTROLLER_TO_MASK(cc);
3510 }
3511
3512 c->delegate = true;
3513 c->delegate_controllers |= mask;
3514
3515 } else if (r > 0) {
3516 c->delegate = true;
3517 c->delegate_controllers = _CGROUP_MASK_ALL;
3518 } else {
3519 c->delegate = false;
3520 c->delegate_controllers = 0;
3521 }
3522
3523 return 0;
3524}
3525
4ad49000
LP
3526int config_parse_device_allow(
3527 const char *unit,
3528 const char *filename,
3529 unsigned line,
3530 const char *section,
71a61510 3531 unsigned section_line,
4ad49000
LP
3532 const char *lvalue,
3533 int ltype,
3534 const char *rvalue,
3535 void *data,
3536 void *userdata) {
3537
1116e14c 3538 _cleanup_free_ char *path = NULL, *t = NULL;
4ad49000
LP
3539 CGroupContext *c = data;
3540 CGroupDeviceAllow *a;
1116e14c 3541 const char *m = NULL;
4ad49000 3542 size_t n;
1116e14c 3543 int r;
4ad49000
LP
3544
3545 if (isempty(rvalue)) {
3546 while (c->device_allow)
3547 cgroup_context_free_device_allow(c, c->device_allow);
3548
3549 return 0;
3550 }
3551
1116e14c 3552 r = unit_full_printf(userdata, rvalue, &t);
508f63b4 3553 if (r < 0) {
1116e14c
NBS
3554 log_syntax(unit, LOG_WARNING, filename, line, r,
3555 "Failed to resolve specifiers in %s, ignoring: %m",
3556 rvalue);
3557 }
3558
3559 n = strcspn(t, WHITESPACE);
3560
3561 path = strndup(t, n);
4ad49000
LP
3562 if (!path)
3563 return log_oom();
3564
3ccb8862 3565 if (!is_deviceallow_pattern(path)) {
12ca818f 3566 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
3567 return 0;
3568 }
3569
1116e14c 3570 m = t + n + strspn(t + n, WHITESPACE);
4ad49000
LP
3571 if (isempty(m))
3572 m = "rwm";
3573
3574 if (!in_charset(m, "rwm")) {
12ca818f 3575 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
4ad49000
LP
3576 return 0;
3577 }
3578
3579 a = new0(CGroupDeviceAllow, 1);
3580 if (!a)
3581 return log_oom();
3582
3583 a->path = path;
3584 path = NULL;
3585 a->r = !!strchr(m, 'r');
3586 a->w = !!strchr(m, 'w');
3587 a->m = !!strchr(m, 'm');
3588
71fda00f 3589 LIST_PREPEND(device_allow, c->device_allow, a);
4ad49000
LP
3590 return 0;
3591}
3592
13c31542
TH
3593int config_parse_io_weight(
3594 const char *unit,
3595 const char *filename,
3596 unsigned line,
3597 const char *section,
3598 unsigned section_line,
3599 const char *lvalue,
3600 int ltype,
3601 const char *rvalue,
3602 void *data,
3603 void *userdata) {
3604
3605 uint64_t *weight = data;
3606 int r;
3607
3608 assert(filename);
3609 assert(lvalue);
3610 assert(rvalue);
3611
3612 r = cg_weight_parse(rvalue, weight);
3613 if (r < 0) {
3614 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
3615 return 0;
3616 }
3617
3618 return 0;
3619}
3620
3621int config_parse_io_device_weight(
3622 const char *unit,
3623 const char *filename,
3624 unsigned line,
3625 const char *section,
3626 unsigned section_line,
3627 const char *lvalue,
3628 int ltype,
3629 const char *rvalue,
3630 void *data,
3631 void *userdata) {
3632
3633 _cleanup_free_ char *path = NULL;
3634 CGroupIODeviceWeight *w;
3635 CGroupContext *c = data;
3636 const char *weight;
3637 uint64_t u;
3638 size_t n;
3639 int r;
3640
3641 assert(filename);
3642 assert(lvalue);
3643 assert(rvalue);
3644
3645 if (isempty(rvalue)) {
3646 while (c->io_device_weights)
3647 cgroup_context_free_io_device_weight(c, c->io_device_weights);
3648
3649 return 0;
3650 }
3651
3652 n = strcspn(rvalue, WHITESPACE);
3653 weight = rvalue + n;
3654 weight += strspn(weight, WHITESPACE);
3655
3656 if (isempty(weight)) {
3657 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3658 return 0;
3659 }
3660
3661 path = strndup(rvalue, n);
3662 if (!path)
3663 return log_oom();
3664
3665 if (!path_startswith(path, "/dev")) {
3666 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3667 return 0;
3668 }
3669
3670 r = cg_weight_parse(weight, &u);
3671 if (r < 0) {
3672 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
3673 return 0;
3674 }
3675
3676 assert(u != CGROUP_WEIGHT_INVALID);
3677
3678 w = new0(CGroupIODeviceWeight, 1);
3679 if (!w)
3680 return log_oom();
3681
3682 w->path = path;
3683 path = NULL;
3684
3685 w->weight = u;
3686
3687 LIST_PREPEND(device_weights, c->io_device_weights, w);
3688 return 0;
3689}
3690
3691int config_parse_io_limit(
3692 const char *unit,
3693 const char *filename,
3694 unsigned line,
3695 const char *section,
3696 unsigned section_line,
3697 const char *lvalue,
3698 int ltype,
3699 const char *rvalue,
3700 void *data,
3701 void *userdata) {
3702
3703 _cleanup_free_ char *path = NULL;
3704 CGroupIODeviceLimit *l = NULL, *t;
3705 CGroupContext *c = data;
9be57249 3706 CGroupIOLimitType type;
13c31542
TH
3707 const char *limit;
3708 uint64_t num;
13c31542
TH
3709 size_t n;
3710 int r;
3711
3712 assert(filename);
3713 assert(lvalue);
3714 assert(rvalue);
3715
9be57249
TH
3716 type = cgroup_io_limit_type_from_string(lvalue);
3717 assert(type >= 0);
13c31542
TH
3718
3719 if (isempty(rvalue)) {
3720 LIST_FOREACH(device_limits, l, c->io_device_limits)
9be57249 3721 l->limits[type] = cgroup_io_limit_defaults[type];
13c31542
TH
3722 return 0;
3723 }
3724
3725 n = strcspn(rvalue, WHITESPACE);
3726 limit = rvalue + n;
3727 limit += strspn(limit, WHITESPACE);
3728
3729 if (!*limit) {
3730 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3731 return 0;
3732 }
3733
3734 path = strndup(rvalue, n);
3735 if (!path)
3736 return log_oom();
3737
3738 if (!path_startswith(path, "/dev")) {
3739 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3740 return 0;
3741 }
3742
e57c9ce1 3743 if (streq("infinity", limit)) {
13c31542
TH
3744 num = CGROUP_LIMIT_MAX;
3745 } else {
3746 r = parse_size(limit, 1000, &num);
3747 if (r < 0 || num <= 0) {
3748 log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
3749 return 0;
3750 }
3751 }
3752
3753 LIST_FOREACH(device_limits, t, c->io_device_limits) {
3754 if (path_equal(path, t->path)) {
3755 l = t;
3756 break;
3757 }
3758 }
3759
3760 if (!l) {
9be57249
TH
3761 CGroupIOLimitType ttype;
3762
13c31542
TH
3763 l = new0(CGroupIODeviceLimit, 1);
3764 if (!l)
3765 return log_oom();
3766
3767 l->path = path;
3768 path = NULL;
9be57249
TH
3769 for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
3770 l->limits[ttype] = cgroup_io_limit_defaults[ttype];
13c31542
TH
3771
3772 LIST_PREPEND(device_limits, c->io_device_limits, l);
3773 }
3774
9be57249 3775 l->limits[type] = num;
13c31542
TH
3776
3777 return 0;
3778}
3779
4ad49000
LP
3780int config_parse_blockio_weight(
3781 const char *unit,
3782 const char *filename,
3783 unsigned line,
3784 const char *section,
71a61510 3785 unsigned section_line,
4ad49000
LP
3786 const char *lvalue,
3787 int ltype,
3788 const char *rvalue,
3789 void *data,
3790 void *userdata) {
3791
d53d9474 3792 uint64_t *weight = data;
95ae05c0
WC
3793 int r;
3794
3795 assert(filename);
3796 assert(lvalue);
3797 assert(rvalue);
3798
d53d9474
LP
3799 r = cg_blkio_weight_parse(rvalue, weight);
3800 if (r < 0) {
3801 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
3802 return 0;
3803 }
3804
8e7076ca
LP
3805 return 0;
3806}
3807
3808int config_parse_blockio_device_weight(
3809 const char *unit,
3810 const char *filename,
3811 unsigned line,
3812 const char *section,
71a61510 3813 unsigned section_line,
8e7076ca
LP
3814 const char *lvalue,
3815 int ltype,
3816 const char *rvalue,
3817 void *data,
3818 void *userdata) {
3819
4ad49000 3820 _cleanup_free_ char *path = NULL;
8e7076ca 3821 CGroupBlockIODeviceWeight *w;
4ad49000 3822 CGroupContext *c = data;
4ad49000 3823 const char *weight;
d53d9474 3824 uint64_t u;
4ad49000
LP
3825 size_t n;
3826 int r;
3827
3828 assert(filename);
3829 assert(lvalue);
3830 assert(rvalue);
3831
3832 if (isempty(rvalue)) {
4ad49000
LP
3833 while (c->blockio_device_weights)
3834 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3835
3836 return 0;
3837 }
3838
3839 n = strcspn(rvalue, WHITESPACE);
3840 weight = rvalue + n;
d53d9474
LP
3841 weight += strspn(weight, WHITESPACE);
3842
3843 if (isempty(weight)) {
12ca818f 3844 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
8e7076ca
LP
3845 return 0;
3846 }
4ad49000 3847
8e7076ca
LP
3848 path = strndup(rvalue, n);
3849 if (!path)
3850 return log_oom();
4ad49000 3851
8e7076ca 3852 if (!path_startswith(path, "/dev")) {
12ca818f 3853 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
8e7076ca
LP
3854 return 0;
3855 }
4ad49000 3856
d53d9474
LP
3857 r = cg_blkio_weight_parse(weight, &u);
3858 if (r < 0) {
3859 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
4ad49000
LP
3860 return 0;
3861 }
3862
d53d9474
LP
3863 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3864
8e7076ca
LP
3865 w = new0(CGroupBlockIODeviceWeight, 1);
3866 if (!w)
3867 return log_oom();
4ad49000 3868
8e7076ca
LP
3869 w->path = path;
3870 path = NULL;
4ad49000 3871
d53d9474 3872 w->weight = u;
4ad49000 3873
71fda00f 3874 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
3875 return 0;
3876}
3877
3878int config_parse_blockio_bandwidth(
3879 const char *unit,
3880 const char *filename,
3881 unsigned line,
3882 const char *section,
71a61510 3883 unsigned section_line,
4ad49000
LP
3884 const char *lvalue,
3885 int ltype,
3886 const char *rvalue,
3887 void *data,
3888 void *userdata) {
3889
3890 _cleanup_free_ char *path = NULL;
979d0311 3891 CGroupBlockIODeviceBandwidth *b = NULL, *t;
4ad49000
LP
3892 CGroupContext *c = data;
3893 const char *bandwidth;
59f448cf 3894 uint64_t bytes;
47c0980d 3895 bool read;
4ad49000
LP
3896 size_t n;
3897 int r;
3898
3899 assert(filename);
3900 assert(lvalue);
3901 assert(rvalue);
3902
47c0980d
G
3903 read = streq("BlockIOReadBandwidth", lvalue);
3904
4ad49000 3905 if (isempty(rvalue)) {
979d0311
TH
3906 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
3907 b->rbps = CGROUP_LIMIT_MAX;
3908 b->wbps = CGROUP_LIMIT_MAX;
3909 }
4ad49000
LP
3910 return 0;
3911 }
3912
3913 n = strcspn(rvalue, WHITESPACE);
3914 bandwidth = rvalue + n;
3915 bandwidth += strspn(bandwidth, WHITESPACE);
3916
3917 if (!*bandwidth) {
12ca818f 3918 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
4ad49000
LP
3919 return 0;
3920 }
3921
3922 path = strndup(rvalue, n);
3923 if (!path)
3924 return log_oom();
3925
3926 if (!path_startswith(path, "/dev")) {
12ca818f 3927 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
3928 return 0;
3929 }
3930
5556b5fe 3931 r = parse_size(bandwidth, 1000, &bytes);
4ad49000 3932 if (r < 0 || bytes <= 0) {
12ca818f 3933 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
3934 return 0;
3935 }
3936
979d0311
TH
3937 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
3938 if (path_equal(path, t->path)) {
3939 b = t;
3940 break;
3941 }
3942 }
4ad49000 3943
979d0311
TH
3944 if (!t) {
3945 b = new0(CGroupBlockIODeviceBandwidth, 1);
3946 if (!b)
3947 return log_oom();
3948
3949 b->path = path;
3950 path = NULL;
3951 b->rbps = CGROUP_LIMIT_MAX;
3952 b->wbps = CGROUP_LIMIT_MAX;
3953
3954 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3955 }
4ad49000 3956
979d0311
TH
3957 if (read)
3958 b->rbps = bytes;
3959 else
3960 b->wbps = bytes;
4ad49000
LP
3961
3962 return 0;
3963}
3964
d420282b
LP
3965DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3966
3967int config_parse_job_mode_isolate(
3968 const char *unit,
3969 const char *filename,
3970 unsigned line,
3971 const char *section,
3972 unsigned section_line,
3973 const char *lvalue,
3974 int ltype,
3975 const char *rvalue,
3976 void *data,
3977 void *userdata) {
3978
3979 JobMode *m = data;
3980 int r;
3981
3982 assert(filename);
3983 assert(lvalue);
3984 assert(rvalue);
3985
3986 r = parse_boolean(rvalue);
3987 if (r < 0) {
12ca818f 3988 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
d420282b
LP
3989 return 0;
3990 }
3991
3992 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3993 return 0;
3994}
3995
53f47dfc
YW
3996DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
3997
3536f49e 3998int config_parse_exec_directories(
e66cf1a3
LP
3999 const char *unit,
4000 const char *filename,
4001 unsigned line,
4002 const char *section,
4003 unsigned section_line,
4004 const char *lvalue,
4005 int ltype,
4006 const char *rvalue,
4007 void *data,
4008 void *userdata) {
4009
a2a5291b 4010 char***rt = data;
9b5864d9 4011 Unit *u = userdata;
035fe294 4012 const char *p;
e66cf1a3
LP
4013 int r;
4014
4015 assert(filename);
4016 assert(lvalue);
4017 assert(rvalue);
4018 assert(data);
4019
4020 if (isempty(rvalue)) {
4021 /* Empty assignment resets the list */
6796073e 4022 *rt = strv_free(*rt);
e66cf1a3
LP
4023 return 0;
4024 }
4025
035fe294
ZJS
4026 for (p = rvalue;;) {
4027 _cleanup_free_ char *word = NULL, *k = NULL;
e66cf1a3 4028
035fe294 4029 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
035fe294 4030 if (r == -ENOMEM)
e66cf1a3 4031 return log_oom();
035fe294
ZJS
4032 if (r < 0) {
4033 log_syntax(unit, LOG_WARNING, filename, line, r,
4034 "Invalid syntax, ignoring: %s", rvalue);
4035 return 0;
4036 }
091e9efe
LP
4037 if (r == 0)
4038 return 0;
e66cf1a3 4039
18913df9 4040 r = unit_full_printf(u, word, &k);
9b5864d9 4041 if (r < 0) {
035fe294
ZJS
4042 log_syntax(unit, LOG_ERR, filename, line, r,
4043 "Failed to resolve specifiers in \"%s\", ignoring: %m", word);
9b5864d9
MG
4044 continue;
4045 }
4046
99be45a4 4047 if (!path_is_normalized(k) || path_is_absolute(k)) {
035fe294 4048 log_syntax(unit, LOG_ERR, filename, line, 0,
091e9efe 4049 "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue);
e66cf1a3
LP
4050 continue;
4051 }
4052
035fe294 4053 r = strv_push(rt, k);
e66cf1a3
LP
4054 if (r < 0)
4055 return log_oom();
035fe294 4056 k = NULL;
e66cf1a3 4057 }
e66cf1a3
LP
4058}
4059
3af00fb8
LP
4060int config_parse_set_status(
4061 const char *unit,
4062 const char *filename,
4063 unsigned line,
4064 const char *section,
4065 unsigned section_line,
4066 const char *lvalue,
4067 int ltype,
4068 const char *rvalue,
4069 void *data,
4070 void *userdata) {
4071
3af00fb8 4072 size_t l;
a2a5291b 4073 const char *word, *state;
3af00fb8
LP
4074 int r;
4075 ExitStatusSet *status_set = data;
4076
4077 assert(filename);
4078 assert(lvalue);
4079 assert(rvalue);
4080 assert(data);
4081
3e2d435b 4082 /* Empty assignment resets the list */
3af00fb8 4083 if (isempty(rvalue)) {
3e2d435b 4084 exit_status_set_free(status_set);
3af00fb8
LP
4085 return 0;
4086 }
4087
a2a5291b 4088 FOREACH_WORD(word, l, rvalue, state) {
3af00fb8
LP
4089 _cleanup_free_ char *temp;
4090 int val;
61593865 4091 Set **set;
3af00fb8 4092
a2a5291b 4093 temp = strndup(word, l);
3af00fb8
LP
4094 if (!temp)
4095 return log_oom();
4096
4097 r = safe_atoi(temp, &val);
4098 if (r < 0) {
4099 val = signal_from_string_try_harder(temp);
4100
1e2fd62d 4101 if (val <= 0) {
12ca818f 4102 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
61593865 4103 continue;
3af00fb8 4104 }
61593865 4105 set = &status_set->signal;
3af00fb8 4106 } else {
1e2fd62d 4107 if (val < 0 || val > 255) {
12ca818f 4108 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
1e2fd62d 4109 continue;
3af00fb8 4110 }
61593865 4111 set = &status_set->status;
3af00fb8 4112 }
1e2fd62d 4113
61593865 4114 r = set_ensure_allocated(set, NULL);
1e2fd62d
ZJS
4115 if (r < 0)
4116 return log_oom();
4117
61593865 4118 r = set_put(*set, INT_TO_PTR(val));
1e2fd62d 4119 if (r < 0) {
12ca818f 4120 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
1e2fd62d
ZJS
4121 return r;
4122 }
3af00fb8 4123 }
b2fadec6 4124 if (!isempty(state))
12ca818f 4125 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3af00fb8
LP
4126
4127 return 0;
4128}
4129
94828d2d
LP
4130int config_parse_namespace_path_strv(
4131 const char *unit,
4132 const char *filename,
4133 unsigned line,
4134 const char *section,
4135 unsigned section_line,
4136 const char *lvalue,
4137 int ltype,
4138 const char *rvalue,
4139 void *data,
4140 void *userdata) {
4141
7b07e993 4142 Unit *u = userdata;
a2a5291b 4143 char*** sv = data;
727f76d7 4144 const char *cur;
94828d2d
LP
4145 int r;
4146
4147 assert(filename);
4148 assert(lvalue);
4149 assert(rvalue);
4150 assert(data);
4151
4152 if (isempty(rvalue)) {
4153 /* Empty assignment resets the list */
6796073e 4154 *sv = strv_free(*sv);
94828d2d
LP
4155 return 0;
4156 }
4157
7b07e993 4158 cur = rvalue;
727f76d7 4159 for (;;) {
7b07e993 4160 _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
20b7a007
LP
4161 const char *w;
4162 bool ignore_enoent = false, shall_prefix = false;
94828d2d 4163
727f76d7 4164 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
0293a7a8
EV
4165 if (r == 0)
4166 break;
4167 if (r == -ENOMEM)
4168 return log_oom();
727f76d7 4169 if (r < 0) {
7b07e993 4170 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
727f76d7
EV
4171 return 0;
4172 }
94828d2d 4173
727f76d7
EV
4174 if (!utf8_is_valid(word)) {
4175 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
94828d2d
LP
4176 continue;
4177 }
4178
20b7a007
LP
4179 w = word;
4180 if (startswith(w, "-")) {
4181 ignore_enoent = true;
4182 w++;
4183 }
4184 if (startswith(w, "+")) {
4185 shall_prefix = true;
4186 w++;
4187 }
7b07e993 4188
20b7a007 4189 r = unit_full_printf(u, w, &resolved);
7b07e993
LP
4190 if (r < 0) {
4191 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s: %m", word);
94828d2d
LP
4192 continue;
4193 }
4194
7b07e993
LP
4195 if (!path_is_absolute(resolved)) {
4196 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
4197 continue;
4198 }
4199
4200 path_kill_slashes(resolved);
94828d2d 4201
20b7a007
LP
4202 joined = strjoin(ignore_enoent ? "-" : "",
4203 shall_prefix ? "+" : "",
4204 resolved);
7b07e993
LP
4205
4206 r = strv_push(sv, joined);
94828d2d
LP
4207 if (r < 0)
4208 return log_oom();
4209
7b07e993 4210 joined = NULL;
94828d2d
LP
4211 }
4212
4213 return 0;
4214}
4215
d2d6c096
LP
4216int config_parse_bind_paths(
4217 const char *unit,
4218 const char *filename,
4219 unsigned line,
4220 const char *section,
4221 unsigned section_line,
4222 const char *lvalue,
4223 int ltype,
4224 const char *rvalue,
4225 void *data,
4226 void *userdata) {
4227
4228 ExecContext *c = data;
42d43f21 4229 Unit *u = userdata;
d2d6c096
LP
4230 const char *p;
4231 int r;
4232
4233 assert(filename);
4234 assert(lvalue);
4235 assert(rvalue);
4236 assert(data);
4237
4238 if (isempty(rvalue)) {
4239 /* Empty assignment resets the list */
4240 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
4241 c->bind_mounts = NULL;
4242 c->n_bind_mounts = 0;
4243 return 0;
4244 }
4245
4246 p = rvalue;
4247 for (;;) {
4248 _cleanup_free_ char *source = NULL, *destination = NULL;
42d43f21 4249 _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
d2d6c096
LP
4250 char *s = NULL, *d = NULL;
4251 bool rbind = true, ignore_enoent = false;
4252
4253 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
4254 if (r == 0)
4255 break;
4256 if (r == -ENOMEM)
4257 return log_oom();
4258 if (r < 0) {
4259 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4260 return 0;
4261 }
4262
42d43f21
DC
4263 r = unit_full_printf(u, source, &sresolved);
4264 if (r < 0) {
4265 log_syntax(unit, LOG_ERR, filename, line, r,
4266 "Failed to resolved specifiers in \"%s\", ignoring: %m", source);
4267 return 0;
4268 }
4269
4270 s = sresolved;
d2d6c096
LP
4271 if (s[0] == '-') {
4272 ignore_enoent = true;
4273 s++;
4274 }
4275
4276 if (!utf8_is_valid(s)) {
4277 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, s);
4278 return 0;
4279 }
4280 if (!path_is_absolute(s)) {
4281 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute source path, ignoring: %s", s);
4282 return 0;
4283 }
4284
4285 path_kill_slashes(s);
4286
4287 /* Optionally, the destination is specified. */
4288 if (p && p[-1] == ':') {
4289 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
4290 if (r == -ENOMEM)
4291 return log_oom();
4292 if (r < 0) {
4293 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4294 return 0;
4295 }
4296 if (r == 0) {
4297 log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':': %s", rvalue);
4298 return 0;
4299 }
4300
42d43f21
DC
4301 r = unit_full_printf(u, destination, &dresolved);
4302 if (r < 0) {
4303 log_syntax(unit, LOG_ERR, filename, line, r,
4304 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
4305 return 0;
4306 }
4307
4308 if (!utf8_is_valid(dresolved)) {
4309 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved);
d2d6c096
LP
4310 return 0;
4311 }
42d43f21
DC
4312 if (!path_is_absolute(dresolved)) {
4313 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved);
d2d6c096
LP
4314 return 0;
4315 }
4316
42d43f21 4317 d = path_kill_slashes(dresolved);
d2d6c096
LP
4318
4319 /* Optionally, there's also a short option string specified */
4320 if (p && p[-1] == ':') {
4321 _cleanup_free_ char *options = NULL;
4322
4323 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
4324 if (r == -ENOMEM)
4325 return log_oom();
4326 if (r < 0) {
4327 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4328 return 0;
4329 }
4330
4331 if (isempty(options) || streq(options, "rbind"))
4332 rbind = true;
4333 else if (streq(options, "norbind"))
4334 rbind = false;
4335 else {
4336 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
4337 return 0;
4338 }
4339 }
4340 } else
4341 d = s;
4342
4343 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
4344 &(BindMount) {
4345 .source = s,
4346 .destination = d,
4347 .read_only = !!strstr(lvalue, "ReadOnly"),
4348 .recursive = rbind,
4349 .ignore_enoent = ignore_enoent,
4350 });
4351 if (r < 0)
4352 return log_oom();
4353 }
4354
4355 return 0;
4356}
4357
f1721625 4358int config_parse_no_new_privileges(
760b9d7c
LP
4359 const char* unit,
4360 const char *filename,
4361 unsigned line,
4362 const char *section,
4363 unsigned section_line,
4364 const char *lvalue,
4365 int ltype,
4366 const char *rvalue,
4367 void *data,
4368 void *userdata) {
4369
4370 ExecContext *c = data;
4371 int k;
4372
4373 assert(filename);
4374 assert(lvalue);
4375 assert(rvalue);
4376 assert(data);
4377
4378 k = parse_boolean(rvalue);
4379 if (k < 0) {
12ca818f 4380 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
760b9d7c
LP
4381 return 0;
4382 }
4383
9b232d32 4384 c->no_new_privileges = k;
760b9d7c
LP
4385
4386 return 0;
4387}
4388
1b8689f9 4389int config_parse_protect_home(
417116f2
LP
4390 const char* unit,
4391 const char *filename,
4392 unsigned line,
4393 const char *section,
4394 unsigned section_line,
4395 const char *lvalue,
4396 int ltype,
4397 const char *rvalue,
4398 void *data,
4399 void *userdata) {
4400
4401 ExecContext *c = data;
4402 int k;
4403
4404 assert(filename);
4405 assert(lvalue);
4406 assert(rvalue);
4407 assert(data);
4408
4409 /* Our enum shall be a superset of booleans, hence first try
61233823 4410 * to parse as boolean, and then as enum */
417116f2
LP
4411
4412 k = parse_boolean(rvalue);
4413 if (k > 0)
1b8689f9 4414 c->protect_home = PROTECT_HOME_YES;
417116f2 4415 else if (k == 0)
1b8689f9 4416 c->protect_home = PROTECT_HOME_NO;
417116f2 4417 else {
1b8689f9 4418 ProtectHome h;
417116f2 4419
1b8689f9 4420 h = protect_home_from_string(rvalue);
9ed794a3 4421 if (h < 0) {
12ca818f 4422 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
4423 return 0;
4424 }
4425
1b8689f9
LP
4426 c->protect_home = h;
4427 }
4428
4429 return 0;
4430}
4431
4432int config_parse_protect_system(
4433 const char* unit,
4434 const char *filename,
4435 unsigned line,
4436 const char *section,
4437 unsigned section_line,
4438 const char *lvalue,
4439 int ltype,
4440 const char *rvalue,
4441 void *data,
4442 void *userdata) {
4443
4444 ExecContext *c = data;
4445 int k;
4446
4447 assert(filename);
4448 assert(lvalue);
4449 assert(rvalue);
4450 assert(data);
4451
4452 /* Our enum shall be a superset of booleans, hence first try
61233823 4453 * to parse as boolean, and then as enum */
1b8689f9
LP
4454
4455 k = parse_boolean(rvalue);
4456 if (k > 0)
4457 c->protect_system = PROTECT_SYSTEM_YES;
4458 else if (k == 0)
4459 c->protect_system = PROTECT_SYSTEM_NO;
4460 else {
4461 ProtectSystem s;
4462
4463 s = protect_system_from_string(rvalue);
9ed794a3 4464 if (s < 0) {
12ca818f 4465 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
1b8689f9
LP
4466 return 0;
4467 }
4468
4469 c->protect_system = s;
417116f2
LP
4470 }
4471
4472 return 0;
4473}
4474
b1edf445
LP
4475DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
4476
eae51da3
LP
4477int config_parse_job_timeout_sec(
4478 const char* unit,
4479 const char *filename,
4480 unsigned line,
4481 const char *section,
4482 unsigned section_line,
4483 const char *lvalue,
4484 int ltype,
4485 const char *rvalue,
4486 void *data,
4487 void *userdata) {
4488
4489 Unit *u = data;
4490 usec_t usec;
4491 int r;
4492
4493 assert(filename);
4494 assert(lvalue);
4495 assert(rvalue);
4496 assert(u);
4497
4498 r = parse_sec_fix_0(rvalue, &usec);
4499 if (r < 0) {
4500 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
4501 return 0;
4502 }
4503
4504 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
c05f3c8f 4505 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
eae51da3
LP
4506 * count. */
4507
4508 if (!u->job_running_timeout_set)
4509 u->job_running_timeout = usec;
4510
4511 u->job_timeout = usec;
4512
4513 return 0;
4514}
4515
4516int config_parse_job_running_timeout_sec(
4517 const char* unit,
4518 const char *filename,
4519 unsigned line,
4520 const char *section,
4521 unsigned section_line,
4522 const char *lvalue,
4523 int ltype,
4524 const char *rvalue,
4525 void *data,
4526 void *userdata) {
4527
4528 Unit *u = data;
4529 usec_t usec;
4530 int r;
4531
4532 assert(filename);
4533 assert(lvalue);
4534 assert(rvalue);
4535 assert(u);
4536
4537 r = parse_sec_fix_0(rvalue, &usec);
4538 if (r < 0) {
4539 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
4540 return 0;
4541 }
4542
4543 u->job_running_timeout = usec;
4544 u->job_running_timeout_set = true;
4545
4546 return 0;
4547}
4548
071830ff 4549#define FOLLOW_MAX 8
87f0e418 4550
9e2f7c11 4551static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
a837f088 4552 char *id = NULL;
0301abf4 4553 unsigned c = 0;
87f0e418
LP
4554 int fd, r;
4555 FILE *f;
87f0e418
LP
4556
4557 assert(filename);
4558 assert(*filename);
4559 assert(_f);
4560 assert(names);
4561
0301abf4
LP
4562 /* This will update the filename pointer if the loaded file is
4563 * reached by a symlink. The old string will be freed. */
87f0e418 4564
0301abf4 4565 for (;;) {
2c7108c4 4566 char *target, *name;
87f0e418 4567
0301abf4
LP
4568 if (c++ >= FOLLOW_MAX)
4569 return -ELOOP;
4570
b08d03ff
LP
4571 path_kill_slashes(*filename);
4572
87f0e418 4573 /* Add the file name we are currently looking at to
8f05424d
LP
4574 * the names of this unit, but only if it is a valid
4575 * unit name. */
2b6bf07d 4576 name = basename(*filename);
7410616c 4577 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
8f05424d 4578
15e11d81
LP
4579 id = set_get(names, name);
4580 if (!id) {
4581 id = strdup(name);
4582 if (!id)
8f05424d 4583 return -ENOMEM;
87f0e418 4584
ef42202a
ZJS
4585 r = set_consume(names, id);
4586 if (r < 0)
8f05424d 4587 return r;
87f0e418 4588 }
87f0e418
LP
4589 }
4590
0301abf4 4591 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
4592 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
4593 if (fd >= 0)
87f0e418
LP
4594 break;
4595
0301abf4
LP
4596 if (errno != ELOOP)
4597 return -errno;
4598
87f0e418 4599 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
4600 r = readlink_and_make_absolute(*filename, &target);
4601 if (r < 0)
0301abf4 4602 return r;
87f0e418 4603
0301abf4 4604 free(*filename);
2c7108c4 4605 *filename = target;
87f0e418
LP
4606 }
4607
9946996c
LP
4608 f = fdopen(fd, "re");
4609 if (!f) {
03e334a1 4610 safe_close(fd);
d4ad27a1 4611 return -errno;
87f0e418
LP
4612 }
4613
4614 *_f = f;
9e2f7c11 4615 *_final = id;
a837f088 4616
0301abf4 4617 return 0;
87f0e418
LP
4618}
4619
23a177ef
LP
4620static int merge_by_names(Unit **u, Set *names, const char *id) {
4621 char *k;
4622 int r;
4623
4624 assert(u);
4625 assert(*u);
4626 assert(names);
4627
4628 /* Let's try to add in all symlink names we found */
4629 while ((k = set_steal_first(names))) {
4630
4631 /* First try to merge in the other name into our
4632 * unit */
9946996c
LP
4633 r = unit_merge_by_name(*u, k);
4634 if (r < 0) {
23a177ef
LP
4635 Unit *other;
4636
4637 /* Hmm, we couldn't merge the other unit into
4638 * ours? Then let's try it the other way
4639 * round */
4640
7aad67e7
MS
4641 /* If the symlink name we are looking at is unit template, then
4642 we must search for instance of this template */
9d3e3406 4643 if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
7aad67e7
MS
4644 _cleanup_free_ char *instance = NULL;
4645
4646 r = unit_name_replace_instance(k, (*u)->instance, &instance);
4647 if (r < 0)
4648 return r;
4649
4650 other = manager_get_unit((*u)->manager, instance);
4651 } else
4652 other = manager_get_unit((*u)->manager, k);
4653
23a177ef
LP
4654 free(k);
4655
9946996c
LP
4656 if (other) {
4657 r = unit_merge(other, *u);
4658 if (r >= 0) {
23a177ef
LP
4659 *u = other;
4660 return merge_by_names(u, names, NULL);
4661 }
9946996c 4662 }
23a177ef
LP
4663
4664 return r;
4665 }
4666
4667 if (id == k)
4668 unit_choose_id(*u, id);
4669
4670 free(k);
4671 }
4672
4673 return 0;
4674}
4675
e537352b 4676static int load_from_path(Unit *u, const char *path) {
e48614c4
ZJS
4677 _cleanup_set_free_free_ Set *symlink_names = NULL;
4678 _cleanup_fclose_ FILE *f = NULL;
4679 _cleanup_free_ char *filename = NULL;
4680 char *id = NULL;
23a177ef 4681 Unit *merged;
45fb0699 4682 struct stat st;
a837f088 4683 int r;
23a177ef
LP
4684
4685 assert(u);
e537352b 4686 assert(path);
3efd4195 4687
d5099efc 4688 symlink_names = set_new(&string_hash_ops);
f975e971 4689 if (!symlink_names)
87f0e418 4690 return -ENOMEM;
3efd4195 4691
036643a2
LP
4692 if (path_is_absolute(path)) {
4693
9946996c 4694 filename = strdup(path);
e48614c4
ZJS
4695 if (!filename)
4696 return -ENOMEM;
036643a2 4697
9946996c
LP
4698 r = open_follow(&filename, &f, symlink_names, &id);
4699 if (r < 0) {
97b11eed 4700 filename = mfree(filename);
036643a2 4701 if (r != -ENOENT)
e48614c4 4702 return r;
036643a2
LP
4703 }
4704
4705 } else {
4706 char **p;
4707
a3c4eb07 4708 STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
036643a2
LP
4709
4710 /* Instead of opening the path right away, we manually
4711 * follow all symlinks and add their name to our unit
4712 * name set while doing so */
9946996c 4713 filename = path_make_absolute(path, *p);
e48614c4
ZJS
4714 if (!filename)
4715 return -ENOMEM;
036643a2 4716
ac155bb8
MS
4717 if (u->manager->unit_path_cache &&
4718 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
4719 r = -ENOENT;
4720 else
4721 r = open_follow(&filename, &f, symlink_names, &id);
a837f088
LP
4722 if (r >= 0)
4723 break;
4724 filename = mfree(filename);
a1feacf7
ZJS
4725
4726 /* ENOENT means that the file is missing or is a dangling symlink.
4727 * ENOTDIR means that one of paths we expect to be is a directory
4728 * is not a directory, we should just ignore that.
4729 * EACCES means that the directory or file permissions are wrong.
4730 */
4731 if (r == -EACCES)
4732 log_debug_errno(r, "Cannot access \"%s\": %m", filename);
4733 else if (!IN_SET(r, -ENOENT, -ENOTDIR))
a837f088 4734 return r;
fe51822e 4735
a837f088
LP
4736 /* Empty the symlink names for the next run */
4737 set_clear_free(symlink_names);
036643a2
LP
4738 }
4739 }
034c6ed7 4740
e48614c4 4741 if (!filename)
8f05424d 4742 /* Hmm, no suitable file found? */
e48614c4 4743 return 0;
87f0e418 4744
8a993b61 4745 if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
a837f088
LP
4746 log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
4747 return -ELOOP;
4748 }
4749
23a177ef 4750 merged = u;
9946996c
LP
4751 r = merge_by_names(&merged, symlink_names, id);
4752 if (r < 0)
e48614c4 4753 return r;
87f0e418 4754
23a177ef 4755 if (merged != u) {
ac155bb8 4756 u->load_state = UNIT_MERGED;
e48614c4 4757 return 0;
034c6ed7
LP
4758 }
4759
e48614c4
ZJS
4760 if (fstat(fileno(f), &st) < 0)
4761 return -errno;
45fb0699 4762
3a8db9fe 4763 if (null_or_empty(&st)) {
ac155bb8 4764 u->load_state = UNIT_MASKED;
3a8db9fe
ZJS
4765 u->fragment_mtime = 0;
4766 } else {
c2756a68 4767 u->load_state = UNIT_LOADED;
3a8db9fe 4768 u->fragment_mtime = timespec_load(&st.st_mtim);
c2756a68 4769
00dc5d76 4770 /* Now, parse the file contents */
36f822c4
ZJS
4771 r = config_parse(u->id, filename, f,
4772 UNIT_VTABLE(u)->sections,
4773 config_item_perf_lookup, load_fragment_gperf_lookup,
bcde742e 4774 CONFIG_PARSE_ALLOW_INCLUDE, u);
f975e971 4775 if (r < 0)
e48614c4 4776 return r;
00dc5d76 4777 }
b08d03ff 4778
ac155bb8
MS
4779 free(u->fragment_path);
4780 u->fragment_path = filename;
0301abf4 4781 filename = NULL;
87f0e418 4782
1b64d026
LP
4783 if (u->source_path) {
4784 if (stat(u->source_path, &st) >= 0)
4785 u->source_mtime = timespec_load(&st.st_mtim);
4786 else
4787 u->source_mtime = 0;
4788 }
4789
e48614c4 4790 return 0;
0301abf4
LP
4791}
4792
e537352b 4793int unit_load_fragment(Unit *u) {
23a177ef 4794 int r;
294d81f1
LP
4795 Iterator i;
4796 const char *t;
0301abf4
LP
4797
4798 assert(u);
ac155bb8
MS
4799 assert(u->load_state == UNIT_STUB);
4800 assert(u->id);
23a177ef 4801
3f5e8115
LP
4802 if (u->transient) {
4803 u->load_state = UNIT_LOADED;
4804 return 0;
4805 }
4806
294d81f1
LP
4807 /* First, try to find the unit under its id. We always look
4808 * for unit files in the default directories, to make it easy
4809 * to override things by placing things in /etc/systemd/system */
9946996c
LP
4810 r = load_from_path(u, u->id);
4811 if (r < 0)
294d81f1
LP
4812 return r;
4813
4814 /* Try to find an alias we can load this with */
abc08d4d 4815 if (u->load_state == UNIT_STUB) {
ac155bb8 4816 SET_FOREACH(t, u->names, i) {
294d81f1 4817
ac155bb8 4818 if (t == u->id)
294d81f1
LP
4819 continue;
4820
9946996c
LP
4821 r = load_from_path(u, t);
4822 if (r < 0)
294d81f1
LP
4823 return r;
4824
ac155bb8 4825 if (u->load_state != UNIT_STUB)
294d81f1
LP
4826 break;
4827 }
abc08d4d 4828 }
23a177ef 4829
294d81f1 4830 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 4831 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 4832
9946996c
LP
4833 r = load_from_path(u, u->fragment_path);
4834 if (r < 0)
23a177ef 4835 return r;
0301abf4 4836
ece174c5 4837 if (u->load_state == UNIT_STUB)
6ccb1b44
LP
4838 /* Hmm, this didn't work? Then let's get rid
4839 * of the fragment path stored for us, so that
4840 * we don't point to an invalid location. */
a1e58e8e 4841 u->fragment_path = mfree(u->fragment_path);
6ccb1b44
LP
4842 }
4843
294d81f1 4844 /* Look for a template */
ac155bb8 4845 if (u->load_state == UNIT_STUB && u->instance) {
7410616c 4846 _cleanup_free_ char *k = NULL;
294d81f1 4847
7410616c
LP
4848 r = unit_name_template(u->id, &k);
4849 if (r < 0)
4850 return r;
294d81f1
LP
4851
4852 r = load_from_path(u, k);
bb28e684
ZJS
4853 if (r < 0) {
4854 if (r == -ENOEXEC)
4855 log_unit_notice(u, "Unit configuration has fatal error, unit will not be started.");
9e2f7c11 4856 return r;
bb28e684 4857 }
890f434c 4858
abc08d4d 4859 if (u->load_state == UNIT_STUB) {
ac155bb8 4860 SET_FOREACH(t, u->names, i) {
bc9fd78c 4861 _cleanup_free_ char *z = NULL;
87f0e418 4862
ac155bb8 4863 if (t == u->id)
23a177ef 4864 continue;
071830ff 4865
7410616c
LP
4866 r = unit_name_template(t, &z);
4867 if (r < 0)
4868 return r;
294d81f1 4869
bc9fd78c 4870 r = load_from_path(u, z);
294d81f1 4871 if (r < 0)
23a177ef 4872 return r;
890f434c 4873
ac155bb8 4874 if (u->load_state != UNIT_STUB)
23a177ef
LP
4875 break;
4876 }
abc08d4d 4877 }
071830ff
LP
4878 }
4879
23a177ef 4880 return 0;
3efd4195 4881}
e537352b
LP
4882
4883void unit_dump_config_items(FILE *f) {
f975e971
LP
4884 static const struct {
4885 const ConfigParserCallback callback;
4886 const char *rvalue;
4887 } table[] = {
f9fa32f0 4888#if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
17df7223
LP
4889 { config_parse_warn_compat, "NOTSUPPORTED" },
4890#endif
f975e971
LP
4891 { config_parse_int, "INTEGER" },
4892 { config_parse_unsigned, "UNSIGNED" },
5556b5fe 4893 { config_parse_iec_size, "SIZE" },
59f448cf 4894 { config_parse_iec_uint64, "SIZE" },
5556b5fe 4895 { config_parse_si_size, "SIZE" },
f975e971
LP
4896 { config_parse_bool, "BOOLEAN" },
4897 { config_parse_string, "STRING" },
4898 { config_parse_path, "PATH" },
4899 { config_parse_unit_path_printf, "PATH" },
4900 { config_parse_strv, "STRING [...]" },
4901 { config_parse_exec_nice, "NICE" },
4902 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4903 { config_parse_exec_io_class, "IOCLASS" },
4904 { config_parse_exec_io_priority, "IOPRIORITY" },
4905 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4906 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4907 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4908 { config_parse_mode, "MODE" },
4909 { config_parse_unit_env_file, "FILE" },
52c239d7
LB
4910 { config_parse_exec_output, "OUTPUT" },
4911 { config_parse_exec_input, "INPUT" },
ca37242e
LP
4912 { config_parse_log_facility, "FACILITY" },
4913 { config_parse_log_level, "LEVEL" },
f975e971 4914 { config_parse_exec_secure_bits, "SECUREBITS" },
a103496c 4915 { config_parse_capability_set, "BOUNDINGSET" },
f975e971 4916 { config_parse_limit, "LIMIT" },
f975e971 4917 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
4918 { config_parse_exec, "PATH [ARGUMENT [...]]" },
4919 { config_parse_service_type, "SERVICETYPE" },
4920 { config_parse_service_restart, "SERVICERESTART" },
349cc4a5 4921#if HAVE_SYSV_COMPAT
f975e971 4922 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
4923#endif
4924 { config_parse_kill_mode, "KILLMODE" },
f757855e 4925 { config_parse_signal, "SIGNAL" },
f975e971
LP
4926 { config_parse_socket_listen, "SOCKET [...]" },
4927 { config_parse_socket_bind, "SOCKETBIND" },
4928 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 4929 { config_parse_sec, "SECONDS" },
d88a251b 4930 { config_parse_nsec, "NANOSECONDS" },
94828d2d 4931 { config_parse_namespace_path_strv, "PATH [...]" },
d2d6c096 4932 { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
7c8fa05c 4933 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
4934 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4935 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 4936 { config_parse_trigger_unit, "UNIT" },
f975e971 4937 { config_parse_timer, "TIMER" },
f975e971 4938 { config_parse_path_spec, "PATH" },
f975e971
LP
4939 { config_parse_notify_access, "ACCESS" },
4940 { config_parse_ip_tos, "TOS" },
4941 { config_parse_unit_condition_path, "CONDITION" },
4942 { config_parse_unit_condition_string, "CONDITION" },
4943 { config_parse_unit_condition_null, "CONDITION" },
a016b922 4944 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
4945 { config_parse_documentation, "URL" },
4946 { config_parse_service_timeout, "SECONDS" },
87a47f99 4947 { config_parse_emergency_action, "ACTION" },
7f0386f6
LP
4948 { config_parse_set_status, "STATUS" },
4949 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 4950 { config_parse_environ, "ENVIRON" },
349cc4a5 4951#if HAVE_SECCOMP
17df7223 4952 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 4953 { config_parse_syscall_archs, "ARCHS" },
17df7223 4954 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 4955 { config_parse_address_families, "FAMILIES" },
add00535 4956 { config_parse_restrict_namespaces, "NAMESPACES" },
c0467cf3 4957#endif
7f0386f6 4958 { config_parse_cpu_shares, "SHARES" },
66ebf6c0 4959 { config_parse_cpu_weight, "WEIGHT" },
7f0386f6
LP
4960 { config_parse_memory_limit, "LIMIT" },
4961 { config_parse_device_allow, "DEVICE" },
4962 { config_parse_device_policy, "POLICY" },
13c31542
TH
4963 { config_parse_io_limit, "LIMIT" },
4964 { config_parse_io_weight, "WEIGHT" },
4965 { config_parse_io_device_weight, "DEVICEWEIGHT" },
7f0386f6
LP
4966 { config_parse_blockio_bandwidth, "BANDWIDTH" },
4967 { config_parse_blockio_weight, "WEIGHT" },
4968 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4969 { config_parse_long, "LONG" },
4970 { config_parse_socket_service, "SERVICE" },
349cc4a5 4971#if HAVE_SELINUX
6a6751fe
LP
4972 { config_parse_exec_selinux_context, "LABEL" },
4973#endif
4974 { config_parse_job_mode, "MODE" },
4975 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 4976 { config_parse_personality, "PERSONALITY" },
f975e971
LP
4977 };
4978
4979 const char *prev = NULL;
4980 const char *i;
4981
4982 assert(f);
e537352b 4983
f975e971
LP
4984 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4985 const char *rvalue = "OTHER", *lvalue;
4986 unsigned j;
4987 size_t prefix_len;
4988 const char *dot;
4989 const ConfigPerfItem *p;
4990
4991 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4992
4993 dot = strchr(i, '.');
4994 lvalue = dot ? dot + 1 : i;
4995 prefix_len = dot-i;
4996
4997 if (dot)
641906e9 4998 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
4999 if (prev)
5000 fputc('\n', f);
5001
5002 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
5003 }
5004
5005 for (j = 0; j < ELEMENTSOF(table); j++)
5006 if (p->parse == table[j].callback) {
5007 rvalue = table[j].rvalue;
5008 break;
5009 }
5010
5011 fprintf(f, "%s=%s\n", lvalue, rvalue);
5012 prev = i;
5013 }
e537352b 5014}