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