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