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