]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
core: fix build without libseccomp
[thirdparty/systemd.git] / src / core / load-fragment.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3efd4195 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
bb112710 7 Copyright 2012 Holger Hans Peter Freyther
a7334b09
LP
8
9 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 17 Lesser General Public License for more details.
a7334b09 18
5430f7f2 19 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
87f0e418 23#include <linux/oom.h>
3efd4195
LP
24#include <assert.h>
25#include <errno.h>
26#include <string.h>
87f0e418
LP
27#include <unistd.h>
28#include <fcntl.h>
94f04347
LP
29#include <sched.h>
30#include <sys/prctl.h>
15ae422b 31#include <sys/mount.h>
25e870b5 32#include <linux/fs.h>
45fb0699 33#include <sys/stat.h>
3d57c6ab
LP
34#include <sys/time.h>
35#include <sys/resource.h>
17df7223 36
c0467cf3
RC
37#ifdef HAVE_SECCOMP
38#include <seccomp.h>
c0467cf3 39#endif
3efd4195 40
84f6181c 41#include "sd-messages.h"
87f0e418 42#include "unit.h"
3efd4195
LP
43#include "strv.h"
44#include "conf-parser.h"
45#include "load-fragment.h"
16354eff 46#include "log.h"
9eba9da4 47#include "ioprio.h"
94f04347
LP
48#include "securebits.h"
49#include "missing.h"
9e2f7c11 50#include "unit-name.h"
41f9172f 51#include "unit-printf.h"
7f110ff9 52#include "utf8.h"
9eb977db 53#include "path-util.h"
853b8397 54#include "env-util.h"
4ad49000 55#include "cgroup.h"
718db961
LP
56#include "bus-util.h"
57#include "bus-error.h"
17df7223 58#include "errno-list.h"
3efd4195 59
c0467cf3 60#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP)
17df7223
LP
61int config_parse_warn_compat(
62 const char *unit,
63 const char *filename,
64 unsigned line,
65 const char *section,
66 unsigned section_line,
67 const char *lvalue,
68 int ltype,
69 const char *rvalue,
70 void *data,
71 void *userdata) {
e8e581bf
ZJS
72
73 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
74 "Support for option %s= has been disabled at compile time and is ignored",
75 lvalue);
07459bb6
FF
76 return 0;
77}
78#endif
79
e8e581bf
ZJS
80int config_parse_unit_deps(const char* unit,
81 const char *filename,
82 unsigned line,
83 const char *section,
71a61510 84 unsigned section_line,
e8e581bf
ZJS
85 const char *lvalue,
86 int ltype,
87 const char *rvalue,
88 void *data,
89 void *userdata) {
3efd4195 90
f975e971 91 UnitDependency d = ltype;
87f0e418 92 Unit *u = userdata;
3efd4195
LP
93 char *w;
94 size_t l;
95 char *state;
96
97 assert(filename);
98 assert(lvalue);
99 assert(rvalue);
3efd4195 100
f60f22df 101 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 102 _cleanup_free_ char *t = NULL, *k = NULL;
3efd4195 103 int r;
3efd4195 104
57020a3a
LP
105 t = strndup(w, l);
106 if (!t)
74051b9b 107 return log_oom();
3efd4195 108
19f6d710
LP
109 r = unit_name_printf(u, t, &k);
110 if (r < 0) {
111 log_syntax(unit, LOG_ERR, filename, line, -r,
112 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
113 continue;
114 }
9e2f7c11 115
701cc384 116 r = unit_add_dependency_by_name(u, d, k, NULL, true);
57020a3a 117 if (r < 0)
e8e581bf
ZJS
118 log_syntax(unit, LOG_ERR, filename, line, -r,
119 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
3efd4195
LP
120 }
121
122 return 0;
123}
124
e8e581bf
ZJS
125int config_parse_unit_string_printf(const char *unit,
126 const char *filename,
127 unsigned line,
128 const char *section,
71a61510 129 unsigned section_line,
e8e581bf
ZJS
130 const char *lvalue,
131 int ltype,
132 const char *rvalue,
133 void *data,
134 void *userdata) {
932921b5
LP
135
136 Unit *u = userdata;
74051b9b 137 _cleanup_free_ char *k = NULL;
19f6d710 138 int r;
932921b5
LP
139
140 assert(filename);
141 assert(lvalue);
142 assert(rvalue);
f2d3769a 143 assert(u);
932921b5 144
19f6d710
LP
145 r = unit_full_printf(u, rvalue, &k);
146 if (r < 0)
147 log_syntax(unit, LOG_ERR, filename, line, -r,
148 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
932921b5 149
71a61510 150 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 151 k ? k : rvalue, data, userdata);
932921b5
LP
152}
153
e8e581bf
ZJS
154int config_parse_unit_strv_printf(const char *unit,
155 const char *filename,
156 unsigned line,
157 const char *section,
71a61510 158 unsigned section_line,
e8e581bf
ZJS
159 const char *lvalue,
160 int ltype,
161 const char *rvalue,
162 void *data,
163 void *userdata) {
8fef7659
LP
164
165 Unit *u = userdata;
74051b9b 166 _cleanup_free_ char *k = NULL;
19f6d710 167 int r;
8fef7659
LP
168
169 assert(filename);
170 assert(lvalue);
171 assert(rvalue);
172 assert(u);
173
19f6d710
LP
174 r = unit_full_printf(u, rvalue, &k);
175 if (r < 0)
176 log_syntax(unit, LOG_ERR, filename, line, -r,
177 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
8fef7659 178
71a61510 179 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 180 k ? k : rvalue, data, userdata);
8fef7659
LP
181}
182
e8e581bf
ZJS
183int config_parse_unit_path_printf(const char *unit,
184 const char *filename,
185 unsigned line,
186 const char *section,
71a61510 187 unsigned section_line,
e8e581bf
ZJS
188 const char *lvalue,
189 int ltype,
190 const char *rvalue,
191 void *data,
192 void *userdata) {
6ea832a2
LP
193
194 Unit *u = userdata;
74051b9b 195 _cleanup_free_ char *k = NULL;
19f6d710 196 int r;
6ea832a2
LP
197
198 assert(filename);
199 assert(lvalue);
200 assert(rvalue);
6ea832a2
LP
201 assert(u);
202
19f6d710
LP
203 r = unit_full_printf(u, rvalue, &k);
204 if (r < 0)
205 log_syntax(unit, LOG_ERR, filename, line, -r,
206 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
6ea832a2 207
71a61510 208 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 209 k ? k : rvalue, data, userdata);
6ea832a2
LP
210}
211
e8e581bf
ZJS
212int config_parse_socket_listen(const char *unit,
213 const char *filename,
214 unsigned line,
215 const char *section,
71a61510 216 unsigned section_line,
e8e581bf
ZJS
217 const char *lvalue,
218 int ltype,
219 const char *rvalue,
220 void *data,
221 void *userdata) {
42f4e3c4 222
49f91047 223 SocketPort *p, *tail;
542563ba 224 Socket *s;
19f6d710 225 int r;
16354eff 226
42f4e3c4
LP
227 assert(filename);
228 assert(lvalue);
229 assert(rvalue);
230 assert(data);
231
595ed347 232 s = SOCKET(data);
542563ba 233
74051b9b
LP
234 if (isempty(rvalue)) {
235 /* An empty assignment removes all ports */
236 socket_free_ports(s);
237 return 0;
238 }
239
7f110ff9
LP
240 p = new0(SocketPort, 1);
241 if (!p)
74051b9b 242 return log_oom();
916abb21 243
74051b9b 244 if (ltype != SOCKET_SOCKET) {
916abb21 245
74051b9b 246 p->type = ltype;
19f6d710
LP
247 r = unit_full_printf(UNIT(s), rvalue, &p->path);
248 if (r < 0) {
487060c2
LP
249 p->path = strdup(rvalue);
250 if (!p->path) {
251 free(p);
252 return log_oom();
253 } else
19f6d710
LP
254 log_syntax(unit, LOG_ERR, filename, line, -r,
255 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
916abb21
LP
256 }
257
258 path_kill_slashes(p->path);
259
7a22745a 260 } else if (streq(lvalue, "ListenNetlink")) {
74051b9b 261 _cleanup_free_ char *k = NULL;
1fd45a90 262
7a22745a 263 p->type = SOCKET_SOCKET;
19f6d710
LP
264 r = unit_full_printf(UNIT(s), rvalue, &k);
265 if (r < 0)
266 log_syntax(unit, LOG_ERR, filename, line, -r,
267 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
7a22745a 268
487060c2 269 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
1fd45a90 270 if (r < 0) {
19f6d710 271 log_syntax(unit, LOG_ERR, filename, line, -r,
e8e581bf 272 "Failed to parse address value, ignoring: %s", rvalue);
7a22745a
LP
273 free(p);
274 return 0;
275 }
276
542563ba 277 } else {
74051b9b 278 _cleanup_free_ char *k = NULL;
1fd45a90 279
542563ba 280 p->type = SOCKET_SOCKET;
19f6d710
LP
281 r = unit_full_printf(UNIT(s), rvalue, &k);
282 if (r < 0)
283 log_syntax(unit, LOG_ERR, filename, line, -r,
284 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
542563ba 285
487060c2 286 r = socket_address_parse(&p->address, k ? k : rvalue);
1fd45a90 287 if (r < 0) {
19f6d710 288 log_syntax(unit, LOG_ERR, filename, line, -r,
e8e581bf 289 "Failed to parse address value, ignoring: %s", rvalue);
542563ba 290 free(p);
c0b34696 291 return 0;
542563ba
LP
292 }
293
294 if (streq(lvalue, "ListenStream"))
295 p->address.type = SOCK_STREAM;
296 else if (streq(lvalue, "ListenDatagram"))
297 p->address.type = SOCK_DGRAM;
298 else {
299 assert(streq(lvalue, "ListenSequentialPacket"));
300 p->address.type = SOCK_SEQPACKET;
301 }
302
303 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
e8e581bf
ZJS
304 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
305 "Address family not supported, ignoring: %s", rvalue);
542563ba 306 free(p);
c0b34696 307 return 0;
542563ba 308 }
16354eff
LP
309 }
310
542563ba 311 p->fd = -1;
2e41a51e 312 p->socket = s;
49f91047
LP
313
314 if (s->ports) {
71fda00f
LP
315 LIST_FIND_TAIL(port, s->ports, tail);
316 LIST_INSERT_AFTER(port, s->ports, tail, p);
49f91047 317 } else
71fda00f 318 LIST_PREPEND(port, s->ports, p);
542563ba 319
16354eff 320 return 0;
42f4e3c4
LP
321}
322
e8e581bf
ZJS
323int config_parse_socket_bind(const char *unit,
324 const char *filename,
325 unsigned line,
326 const char *section,
71a61510 327 unsigned section_line,
e8e581bf
ZJS
328 const char *lvalue,
329 int ltype,
330 const char *rvalue,
331 void *data,
332 void *userdata) {
42f4e3c4 333
542563ba 334 Socket *s;
c0120d99 335 SocketAddressBindIPv6Only b;
42f4e3c4
LP
336
337 assert(filename);
338 assert(lvalue);
339 assert(rvalue);
340 assert(data);
341
595ed347 342 s = SOCKET(data);
542563ba 343
5198dabc
LP
344 b = socket_address_bind_ipv6_only_from_string(rvalue);
345 if (b < 0) {
c0120d99
LP
346 int r;
347
5198dabc
LP
348 r = parse_boolean(rvalue);
349 if (r < 0) {
e8e581bf
ZJS
350 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
351 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
c0b34696 352 return 0;
c0120d99 353 }
42f4e3c4 354
c0120d99
LP
355 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
356 } else
357 s->bind_ipv6_only = b;
542563ba 358
42f4e3c4
LP
359 return 0;
360}
361
e8e581bf
ZJS
362int config_parse_exec_nice(const char *unit,
363 const char *filename,
364 unsigned line,
365 const char *section,
71a61510 366 unsigned section_line,
e8e581bf
ZJS
367 const char *lvalue,
368 int ltype,
369 const char *rvalue,
370 void *data,
371 void *userdata) {
034c6ed7 372
fb33a393 373 ExecContext *c = data;
e8e581bf 374 int priority, r;
034c6ed7
LP
375
376 assert(filename);
377 assert(lvalue);
378 assert(rvalue);
379 assert(data);
380
e8e581bf
ZJS
381 r = safe_atoi(rvalue, &priority);
382 if (r < 0) {
383 log_syntax(unit, LOG_ERR, filename, line, -r,
384 "Failed to parse nice priority, ignoring: %s. ", rvalue);
c0b34696 385 return 0;
034c6ed7
LP
386 }
387
388 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
e8e581bf
ZJS
389 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
390 "Nice priority out of range, ignoring: %s", rvalue);
c0b34696 391 return 0;
034c6ed7
LP
392 }
393
fb33a393 394 c->nice = priority;
71155933 395 c->nice_set = true;
fb33a393 396
034c6ed7
LP
397 return 0;
398}
399
e8e581bf
ZJS
400int config_parse_exec_oom_score_adjust(const char* unit,
401 const char *filename,
402 unsigned line,
403 const char *section,
71a61510 404 unsigned section_line,
e8e581bf
ZJS
405 const char *lvalue,
406 int ltype,
407 const char *rvalue,
408 void *data,
409 void *userdata) {
034c6ed7 410
fb33a393 411 ExecContext *c = data;
e8e581bf 412 int oa, r;
034c6ed7
LP
413
414 assert(filename);
415 assert(lvalue);
416 assert(rvalue);
417 assert(data);
418
e8e581bf
ZJS
419 r = safe_atoi(rvalue, &oa);
420 if (r < 0) {
421 log_syntax(unit, LOG_ERR, filename, line, -r,
422 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
c0b34696 423 return 0;
034c6ed7
LP
424 }
425
dd6c17b1 426 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
e8e581bf
ZJS
427 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
428 "OOM score adjust value out of range, ignoring: %s", rvalue);
c0b34696 429 return 0;
034c6ed7
LP
430 }
431
dd6c17b1
LP
432 c->oom_score_adjust = oa;
433 c->oom_score_adjust_set = true;
fb33a393 434
034c6ed7
LP
435 return 0;
436}
437
e8e581bf
ZJS
438int config_parse_exec(const char *unit,
439 const char *filename,
440 unsigned line,
441 const char *section,
71a61510 442 unsigned section_line,
e8e581bf
ZJS
443 const char *lvalue,
444 int ltype,
445 const char *rvalue,
446 void *data,
447 void *userdata) {
034c6ed7 448
61e5d8ed
LP
449 ExecCommand **e = data, *nce;
450 char *path, **n;
034c6ed7 451 unsigned k;
7f110ff9 452 int r;
034c6ed7
LP
453
454 assert(filename);
455 assert(lvalue);
456 assert(rvalue);
61e5d8ed 457 assert(e);
034c6ed7 458
74051b9b
LP
459 e += ltype;
460
461 if (isempty(rvalue)) {
462 /* An empty assignment resets the list */
463 exec_command_free_list(*e);
464 *e = NULL;
465 return 0;
466 }
467
6c666e26
LP
468 /* We accept an absolute path as first argument, or
469 * alternatively an absolute prefixed with @ to allow
470 * overriding of argv[0]. */
61e5d8ed 471 for (;;) {
0f67f1ef 472 int i;
61e5d8ed
LP
473 char *w;
474 size_t l;
475 char *state;
b708e7ce 476 bool honour_argv0 = false, ignore = false;
6c666e26 477
61e5d8ed
LP
478 path = NULL;
479 nce = NULL;
480 n = NULL;
6c666e26 481
61e5d8ed 482 rvalue += strspn(rvalue, WHITESPACE);
034c6ed7 483
61e5d8ed
LP
484 if (rvalue[0] == 0)
485 break;
034c6ed7 486
0f67f1ef
ZJS
487 for (i = 0; i < 2; i++) {
488 if (rvalue[0] == '-' && !ignore) {
489 ignore = true;
490 rvalue ++;
491 }
b708e7ce 492
0f67f1ef
ZJS
493 if (rvalue[0] == '@' && !honour_argv0) {
494 honour_argv0 = true;
495 rvalue ++;
496 }
b708e7ce 497 }
61e5d8ed 498
b708e7ce 499 if (*rvalue != '/') {
e8e581bf
ZJS
500 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
501 "Executable path is not absolute, ignoring: %s", rvalue);
c0b34696 502 return 0;
6c666e26 503 }
034c6ed7 504
61e5d8ed
LP
505 k = 0;
506 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
641906e9 507 if (strneq(w, ";", MAX(l, 1U)))
61e5d8ed 508 break;
034c6ed7 509
61e5d8ed
LP
510 k++;
511 }
034c6ed7 512
7f110ff9
LP
513 n = new(char*, k + !honour_argv0);
514 if (!n)
74051b9b 515 return log_oom();
61e5d8ed
LP
516
517 k = 0;
61e5d8ed 518 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
641906e9 519 if (strneq(w, ";", MAX(l, 1U)))
61e5d8ed 520 break;
641906e9 521 else if (strneq(w, "\\;", MAX(l, 1U)))
7e1a84f5 522 w ++;
61e5d8ed 523
b708e7ce
LP
524 if (honour_argv0 && w == rvalue) {
525 assert(!path);
7f110ff9
LP
526
527 path = strndup(w, l);
528 if (!path) {
74051b9b 529 r = log_oom();
7f110ff9
LP
530 goto fail;
531 }
532
533 if (!utf8_is_valid(path)) {
e8e581bf
ZJS
534 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
535 "Path is not UTF-8 clean, ignoring assignment: %s",
536 rvalue);
7f110ff9 537 r = 0;
61e5d8ed 538 goto fail;
7f110ff9
LP
539 }
540
61e5d8ed 541 } else {
7f110ff9
LP
542 char *c;
543
544 c = n[k++] = cunescape_length(w, l);
545 if (!c) {
74051b9b 546 r = log_oom();
61e5d8ed 547 goto fail;
7f110ff9
LP
548 }
549
550 if (!utf8_is_valid(c)) {
e8e581bf
ZJS
551 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
552 "Path is not UTF-8 clean, ignoring assignment: %s",
553 rvalue);
7f110ff9
LP
554 r = 0;
555 goto fail;
556 }
61e5d8ed
LP
557 }
558 }
559
560 n[k] = NULL;
561
562 if (!n[0]) {
e8e581bf
ZJS
563 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
564 "Invalid command line, ignoring: %s", rvalue);
7f110ff9
LP
565 r = 0;
566 goto fail;
61e5d8ed
LP
567 }
568
7f110ff9
LP
569 if (!path) {
570 path = strdup(n[0]);
571 if (!path) {
74051b9b 572 r = log_oom();
61e5d8ed 573 goto fail;
7f110ff9
LP
574 }
575 }
6c666e26 576
61e5d8ed 577 assert(path_is_absolute(path));
6c666e26 578
7f110ff9
LP
579 nce = new0(ExecCommand, 1);
580 if (!nce) {
74051b9b 581 r = log_oom();
61e5d8ed 582 goto fail;
7f110ff9 583 }
61e5d8ed
LP
584
585 nce->argv = n;
586 nce->path = path;
b708e7ce 587 nce->ignore = ignore;
034c6ed7 588
61e5d8ed 589 path_kill_slashes(nce->path);
034c6ed7 590
61e5d8ed 591 exec_command_append_list(e, nce);
01f78473 592
61e5d8ed
LP
593 rvalue = state;
594 }
034c6ed7
LP
595
596 return 0;
597
598fail:
6c666e26
LP
599 n[k] = NULL;
600 strv_free(n);
601 free(path);
034c6ed7
LP
602 free(nce);
603
7f110ff9 604 return r;
034c6ed7
LP
605}
606
f975e971
LP
607DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
608DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
034c6ed7 609
e8e581bf
ZJS
610int config_parse_socket_bindtodevice(const char* unit,
611 const char *filename,
612 unsigned line,
613 const char *section,
71a61510 614 unsigned section_line,
e8e581bf
ZJS
615 const char *lvalue,
616 int ltype,
617 const char *rvalue,
618 void *data,
619 void *userdata) {
acbb0225
LP
620
621 Socket *s = data;
622 char *n;
623
624 assert(filename);
625 assert(lvalue);
626 assert(rvalue);
627 assert(data);
628
629 if (rvalue[0] && !streq(rvalue, "*")) {
74051b9b
LP
630 n = strdup(rvalue);
631 if (!n)
632 return log_oom();
acbb0225
LP
633 } else
634 n = NULL;
635
636 free(s->bind_to_device);
637 s->bind_to_device = n;
638
639 return 0;
640}
641
f975e971
LP
642DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
643DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
87f0e418 644
e8e581bf
ZJS
645int config_parse_exec_io_class(const char *unit,
646 const char *filename,
647 unsigned line,
648 const char *section,
71a61510 649 unsigned section_line,
e8e581bf
ZJS
650 const char *lvalue,
651 int ltype,
652 const char *rvalue,
653 void *data,
654 void *userdata) {
94f04347
LP
655
656 ExecContext *c = data;
657 int x;
658
659 assert(filename);
660 assert(lvalue);
661 assert(rvalue);
662 assert(data);
663
f8b69d1d
MS
664 x = ioprio_class_from_string(rvalue);
665 if (x < 0) {
e8e581bf
ZJS
666 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
667 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
c0b34696 668 return 0;
0d87eb42 669 }
94f04347
LP
670
671 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
672 c->ioprio_set = true;
673
674 return 0;
675}
676
e8e581bf
ZJS
677int config_parse_exec_io_priority(const char *unit,
678 const char *filename,
679 unsigned line,
680 const char *section,
71a61510 681 unsigned section_line,
e8e581bf
ZJS
682 const char *lvalue,
683 int ltype,
684 const char *rvalue,
685 void *data,
686 void *userdata) {
94f04347
LP
687
688 ExecContext *c = data;
e8e581bf 689 int i, r;
94f04347
LP
690
691 assert(filename);
692 assert(lvalue);
693 assert(rvalue);
694 assert(data);
695
e8e581bf
ZJS
696 r = safe_atoi(rvalue, &i);
697 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
698 log_syntax(unit, LOG_ERR, filename, line, -r,
699 "Failed to parse IO priority, ignoring: %s", rvalue);
c0b34696 700 return 0;
071830ff
LP
701 }
702
94f04347
LP
703 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
704 c->ioprio_set = true;
705
071830ff
LP
706 return 0;
707}
708
e8e581bf
ZJS
709int config_parse_exec_cpu_sched_policy(const char *unit,
710 const char *filename,
711 unsigned line,
712 const char *section,
71a61510 713 unsigned section_line,
e8e581bf
ZJS
714 const char *lvalue,
715 int ltype,
716 const char *rvalue,
717 void *data,
718 void *userdata) {
9eba9da4 719
94f04347
LP
720
721 ExecContext *c = data;
722 int x;
723
724 assert(filename);
725 assert(lvalue);
726 assert(rvalue);
727 assert(data);
728
f8b69d1d
MS
729 x = sched_policy_from_string(rvalue);
730 if (x < 0) {
e8e581bf
ZJS
731 log_syntax(unit, LOG_ERR, filename, line, -x,
732 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 733 return 0;
0d87eb42 734 }
94f04347
LP
735
736 c->cpu_sched_policy = x;
bb112710
HHPF
737 /* Moving to or from real-time policy? We need to adjust the priority */
738 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
94f04347
LP
739 c->cpu_sched_set = true;
740
741 return 0;
742}
743
e8e581bf
ZJS
744int config_parse_exec_cpu_sched_prio(const char *unit,
745 const char *filename,
746 unsigned line,
747 const char *section,
71a61510 748 unsigned section_line,
e8e581bf
ZJS
749 const char *lvalue,
750 int ltype,
751 const char *rvalue,
752 void *data,
753 void *userdata) {
9eba9da4
LP
754
755 ExecContext *c = data;
e8e581bf 756 int i, min, max, r;
9eba9da4
LP
757
758 assert(filename);
759 assert(lvalue);
760 assert(rvalue);
761 assert(data);
762
e8e581bf
ZJS
763 r = safe_atoi(rvalue, &i);
764 if (r < 0) {
765 log_syntax(unit, LOG_ERR, filename, line, -r,
766 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 767 return 0;
94f04347 768 }
9eba9da4 769
bb112710
HHPF
770 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
771 min = sched_get_priority_min(c->cpu_sched_policy);
772 max = sched_get_priority_max(c->cpu_sched_policy);
773
774 if (i < min || i > max) {
e8e581bf
ZJS
775 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
776 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
bb112710
HHPF
777 return 0;
778 }
779
94f04347
LP
780 c->cpu_sched_priority = i;
781 c->cpu_sched_set = true;
782
783 return 0;
784}
785
e8e581bf
ZJS
786int config_parse_exec_cpu_affinity(const char *unit,
787 const char *filename,
788 unsigned line,
789 const char *section,
71a61510 790 unsigned section_line,
e8e581bf
ZJS
791 const char *lvalue,
792 int ltype,
793 const char *rvalue,
794 void *data,
795 void *userdata) {
94f04347
LP
796
797 ExecContext *c = data;
798 char *w;
799 size_t l;
800 char *state;
801
802 assert(filename);
803 assert(lvalue);
804 assert(rvalue);
805 assert(data);
806
74051b9b
LP
807 if (isempty(rvalue)) {
808 /* An empty assignment resets the CPU list */
809 if (c->cpuset)
810 CPU_FREE(c->cpuset);
811 c->cpuset = NULL;
812 return 0;
813 }
814
f60f22df 815 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 816 _cleanup_free_ char *t = NULL;
94f04347
LP
817 int r;
818 unsigned cpu;
819
c040936b
ZJS
820 t = strndup(w, l);
821 if (!t)
74051b9b 822 return log_oom();
94f04347 823
487393e9 824 r = safe_atou(t, &cpu);
487393e9 825
c040936b
ZJS
826 if (!c->cpuset) {
827 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
828 if (!c->cpuset)
74051b9b 829 return log_oom();
c040936b 830 }
82c121a4 831
82c121a4 832 if (r < 0 || cpu >= c->cpuset_ncpus) {
e8e581bf
ZJS
833 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
834 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
c0b34696 835 return 0;
9eba9da4 836 }
94f04347 837
82c121a4 838 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
9eba9da4
LP
839 }
840
94f04347
LP
841 return 0;
842}
843
e8e581bf
ZJS
844int config_parse_exec_capabilities(const char *unit,
845 const char *filename,
846 unsigned line,
847 const char *section,
71a61510 848 unsigned section_line,
e8e581bf
ZJS
849 const char *lvalue,
850 int ltype,
851 const char *rvalue,
852 void *data,
853 void *userdata) {
94f04347
LP
854
855 ExecContext *c = data;
856 cap_t cap;
857
858 assert(filename);
859 assert(lvalue);
860 assert(rvalue);
861 assert(data);
862
74051b9b
LP
863 cap = cap_from_text(rvalue);
864 if (!cap) {
e8e581bf
ZJS
865 log_syntax(unit, LOG_ERR, filename, line, errno,
866 "Failed to parse capabilities, ignoring: %s", rvalue);
c0b34696 867 return 0;
94f04347
LP
868 }
869
870 if (c->capabilities)
871 cap_free(c->capabilities);
872 c->capabilities = cap;
873
874 return 0;
875}
876
e8e581bf
ZJS
877int config_parse_exec_secure_bits(const char *unit,
878 const char *filename,
879 unsigned line,
880 const char *section,
71a61510 881 unsigned section_line,
e8e581bf
ZJS
882 const char *lvalue,
883 int ltype,
884 const char *rvalue,
885 void *data,
886 void *userdata) {
94f04347
LP
887
888 ExecContext *c = data;
889 char *w;
890 size_t l;
891 char *state;
892
893 assert(filename);
894 assert(lvalue);
895 assert(rvalue);
896 assert(data);
897
74051b9b
LP
898 if (isempty(rvalue)) {
899 /* An empty assignment resets the field */
900 c->secure_bits = 0;
901 return 0;
902 }
903
f60f22df 904 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94f04347 905 if (first_word(w, "keep-caps"))
cbb21cca 906 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
94f04347 907 else if (first_word(w, "keep-caps-locked"))
cbb21cca 908 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
94f04347 909 else if (first_word(w, "no-setuid-fixup"))
cbb21cca 910 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
94f04347 911 else if (first_word(w, "no-setuid-fixup-locked"))
cbb21cca 912 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
94f04347 913 else if (first_word(w, "noroot"))
cbb21cca 914 c->secure_bits |= 1<<SECURE_NOROOT;
94f04347 915 else if (first_word(w, "noroot-locked"))
cbb21cca 916 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
9eba9da4 917 else {
e8e581bf
ZJS
918 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
919 "Failed to parse secure bits, ignoring: %s", rvalue);
c0b34696 920 return 0;
9eba9da4
LP
921 }
922 }
923
94f04347
LP
924 return 0;
925}
926
e8e581bf
ZJS
927int config_parse_bounding_set(const char *unit,
928 const char *filename,
929 unsigned line,
930 const char *section,
71a61510 931 unsigned section_line,
e8e581bf
ZJS
932 const char *lvalue,
933 int ltype,
934 const char *rvalue,
935 void *data,
936 void *userdata) {
94f04347 937
ec8927ca 938 uint64_t *capability_bounding_set_drop = data;
94f04347
LP
939 char *w;
940 size_t l;
941 char *state;
260abb78
LP
942 bool invert = false;
943 uint64_t sum = 0;
94f04347
LP
944
945 assert(filename);
946 assert(lvalue);
947 assert(rvalue);
948 assert(data);
949
260abb78
LP
950 if (rvalue[0] == '~') {
951 invert = true;
952 rvalue++;
953 }
954
955 /* Note that we store this inverted internally, since the
956 * kernel wants it like this. But we actually expose it
957 * non-inverted everywhere to have a fully normalized
958 * interface. */
959
f60f22df 960 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 961 _cleanup_free_ char *t = NULL;
94f04347
LP
962 int r;
963 cap_value_t cap;
964
ec8927ca
LP
965 t = strndup(w, l);
966 if (!t)
74051b9b 967 return log_oom();
94f04347
LP
968
969 r = cap_from_name(t, &cap);
94f04347 970 if (r < 0) {
e8e581bf
ZJS
971 log_syntax(unit, LOG_ERR, filename, line, errno,
972 "Failed to parse capability in bounding set, ignoring: %s", t);
8351ceae 973 continue;
94f04347
LP
974 }
975
260abb78 976 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
94f04347 977 }
9eba9da4 978
260abb78 979 if (invert)
ec8927ca 980 *capability_bounding_set_drop |= sum;
260abb78 981 else
ec8927ca 982 *capability_bounding_set_drop |= ~sum;
260abb78 983
9eba9da4
LP
984 return 0;
985}
986
e8e581bf
ZJS
987int config_parse_limit(const char *unit,
988 const char *filename,
989 unsigned line,
990 const char *section,
71a61510 991 unsigned section_line,
e8e581bf
ZJS
992 const char *lvalue,
993 int ltype,
994 const char *rvalue,
995 void *data,
996 void *userdata) {
94f04347
LP
997
998 struct rlimit **rl = data;
999 unsigned long long u;
94f04347
LP
1000
1001 assert(filename);
1002 assert(lvalue);
1003 assert(rvalue);
1004 assert(data);
1005
f975e971
LP
1006 rl += ltype;
1007
3d57c6ab
LP
1008 if (streq(rvalue, "infinity"))
1009 u = (unsigned long long) RLIM_INFINITY;
e8e581bf
ZJS
1010 else {
1011 int r;
1012
1013 r = safe_atollu(rvalue, &u);
1014 if (r < 0) {
1015 log_syntax(unit, LOG_ERR, filename, line, -r,
1016 "Failed to parse resource value, ignoring: %s", rvalue);
1017 return 0;
1018 }
94f04347
LP
1019 }
1020
74051b9b
LP
1021 if (!*rl) {
1022 *rl = new(struct rlimit, 1);
1023 if (!*rl)
1024 return log_oom();
1025 }
9eba9da4 1026
94f04347 1027 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
9eba9da4
LP
1028 return 0;
1029}
1030
07459bb6 1031#ifdef HAVE_SYSV_COMPAT
e8e581bf
ZJS
1032int config_parse_sysv_priority(const char *unit,
1033 const char *filename,
1034 unsigned line,
1035 const char *section,
71a61510 1036 unsigned section_line,
e8e581bf
ZJS
1037 const char *lvalue,
1038 int ltype,
1039 const char *rvalue,
1040 void *data,
1041 void *userdata) {
a9a1e00a
LP
1042
1043 int *priority = data;
e8e581bf 1044 int i, r;
a9a1e00a
LP
1045
1046 assert(filename);
1047 assert(lvalue);
1048 assert(rvalue);
1049 assert(data);
1050
e8e581bf
ZJS
1051 r = safe_atoi(rvalue, &i);
1052 if (r < 0 || i < 0) {
1053 log_syntax(unit, LOG_ERR, filename, line, -r,
1054 "Failed to parse SysV start priority, ignoring: %s", rvalue);
c0b34696 1055 return 0;
a9a1e00a
LP
1056 }
1057
1058 *priority = (int) i;
1059 return 0;
1060}
07459bb6 1061#endif
a9a1e00a 1062
f975e971 1063DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
50159e6a 1064
e8e581bf
ZJS
1065int config_parse_kill_signal(const char *unit,
1066 const char *filename,
1067 unsigned line,
1068 const char *section,
71a61510 1069 unsigned section_line,
e8e581bf
ZJS
1070 const char *lvalue,
1071 int ltype,
1072 const char *rvalue,
1073 void *data,
1074 void *userdata) {
2e22afe9
LP
1075
1076 int *sig = data;
1077 int r;
1078
1079 assert(filename);
1080 assert(lvalue);
1081 assert(rvalue);
1082 assert(sig);
1083
74051b9b
LP
1084 r = signal_from_string_try_harder(rvalue);
1085 if (r <= 0) {
e8e581bf
ZJS
1086 log_syntax(unit, LOG_ERR, filename, line, -r,
1087 "Failed to parse kill signal, ignoring: %s", rvalue);
c0b34696 1088 return 0;
2e22afe9
LP
1089 }
1090
1091 *sig = r;
1092 return 0;
1093}
1094
e8e581bf
ZJS
1095int config_parse_exec_mount_flags(const char *unit,
1096 const char *filename,
1097 unsigned line,
1098 const char *section,
71a61510 1099 unsigned section_line,
e8e581bf
ZJS
1100 const char *lvalue,
1101 int ltype,
1102 const char *rvalue,
1103 void *data,
1104 void *userdata) {
15ae422b
LP
1105
1106 ExecContext *c = data;
1107 char *w;
1108 size_t l;
1109 char *state;
1110 unsigned long flags = 0;
1111
1112 assert(filename);
1113 assert(lvalue);
1114 assert(rvalue);
1115 assert(data);
1116
ac97e2c5 1117 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
7fd1b19b 1118 _cleanup_free_ char *t;
ac97e2c5
ZJS
1119
1120 t = strndup(w, l);
1121 if (!t)
74051b9b 1122 return log_oom();
ac97e2c5
ZJS
1123
1124 if (streq(t, "shared"))
15ae422b 1125 flags |= MS_SHARED;
ac97e2c5 1126 else if (streq(t, "slave"))
15ae422b 1127 flags |= MS_SLAVE;
ac97e2c5 1128 else if (streq(w, "private"))
15ae422b
LP
1129 flags |= MS_PRIVATE;
1130 else {
e8e581bf
ZJS
1131 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1132 "Failed to parse mount flag %s, ignoring: %s",
1133 t, rvalue);
c0b34696 1134 return 0;
15ae422b
LP
1135 }
1136 }
1137
1138 c->mount_flags = flags;
1139 return 0;
1140}
1141
e8e581bf
ZJS
1142int config_parse_timer(const char *unit,
1143 const char *filename,
1144 unsigned line,
1145 const char *section,
71a61510 1146 unsigned section_line,
e8e581bf
ZJS
1147 const char *lvalue,
1148 int ltype,
1149 const char *rvalue,
1150 void *data,
1151 void *userdata) {
871d7de4
LP
1152
1153 Timer *t = data;
36697dc0 1154 usec_t u = 0;
871d7de4
LP
1155 TimerValue *v;
1156 TimerBase b;
36697dc0
LP
1157 CalendarSpec *c = NULL;
1158 clockid_t id;
871d7de4
LP
1159
1160 assert(filename);
1161 assert(lvalue);
1162 assert(rvalue);
1163 assert(data);
1164
74051b9b
LP
1165 if (isempty(rvalue)) {
1166 /* Empty assignment resets list */
1167 timer_free_values(t);
1168 return 0;
1169 }
1170
36697dc0
LP
1171 b = timer_base_from_string(lvalue);
1172 if (b < 0) {
e8e581bf
ZJS
1173 log_syntax(unit, LOG_ERR, filename, line, -b,
1174 "Failed to parse timer base, ignoring: %s", lvalue);
c0b34696 1175 return 0;
871d7de4
LP
1176 }
1177
36697dc0
LP
1178 if (b == TIMER_CALENDAR) {
1179 if (calendar_spec_from_string(rvalue, &c) < 0) {
e8e581bf
ZJS
1180 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1181 "Failed to parse calendar specification, ignoring: %s",
1182 rvalue);
36697dc0
LP
1183 return 0;
1184 }
1185
1186 id = CLOCK_REALTIME;
1187 } else {
7f602784 1188 if (parse_sec(rvalue, &u) < 0) {
e8e581bf
ZJS
1189 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1190 "Failed to parse timer value, ignoring: %s",
1191 rvalue);
36697dc0
LP
1192 return 0;
1193 }
1194
1195 id = CLOCK_MONOTONIC;
871d7de4
LP
1196 }
1197
36697dc0
LP
1198 v = new0(TimerValue, 1);
1199 if (!v)
74051b9b 1200 return log_oom();
871d7de4
LP
1201
1202 v->base = b;
36697dc0 1203 v->clock_id = id;
871d7de4 1204 v->value = u;
36697dc0 1205 v->calendar_spec = c;
871d7de4 1206
71fda00f 1207 LIST_PREPEND(value, t->values, v);
871d7de4
LP
1208
1209 return 0;
1210}
1211
3ecaa09b
LP
1212int config_parse_trigger_unit(
1213 const char *unit,
1214 const char *filename,
1215 unsigned line,
1216 const char *section,
71a61510 1217 unsigned section_line,
3ecaa09b
LP
1218 const char *lvalue,
1219 int ltype,
1220 const char *rvalue,
1221 void *data,
1222 void *userdata) {
871d7de4 1223
74051b9b 1224 _cleanup_free_ char *p = NULL;
3ecaa09b
LP
1225 Unit *u = data;
1226 UnitType type;
1227 int r;
398ef8ba
LP
1228
1229 assert(filename);
1230 assert(lvalue);
1231 assert(rvalue);
1232 assert(data);
1233
3ecaa09b
LP
1234 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1235 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1236 "Multiple units to trigger specified, ignoring: %s", rvalue);
1237 return 0;
1238 }
871d7de4 1239
19f6d710
LP
1240 r = unit_name_printf(u, rvalue, &p);
1241 if (r < 0)
1242 log_syntax(unit, LOG_ERR, filename, line, -r,
1243 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
74051b9b 1244
19f6d710 1245 type = unit_name_to_type(p ?: rvalue);
3ecaa09b 1246 if (type < 0) {
e8e581bf 1247 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3ecaa09b 1248 "Unit type not valid, ignoring: %s", rvalue);
c0b34696 1249 return 0;
871d7de4
LP
1250 }
1251
3ecaa09b
LP
1252 if (type == u->type) {
1253 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1254 "Trigger cannot be of same type, ignoring: %s", rvalue);
1255 return 0;
1256 }
1257
19f6d710 1258 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
57020a3a 1259 if (r < 0) {
e8e581bf 1260 log_syntax(unit, LOG_ERR, filename, line, -r,
19f6d710 1261 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
c0b34696 1262 return 0;
871d7de4
LP
1263 }
1264
1265 return 0;
1266}
1267
e8e581bf
ZJS
1268int config_parse_path_spec(const char *unit,
1269 const char *filename,
1270 unsigned line,
1271 const char *section,
71a61510 1272 unsigned section_line,
e8e581bf
ZJS
1273 const char *lvalue,
1274 int ltype,
1275 const char *rvalue,
1276 void *data,
1277 void *userdata) {
01f78473
LP
1278
1279 Path *p = data;
1280 PathSpec *s;
1281 PathType b;
7fd1b19b 1282 _cleanup_free_ char *k = NULL;
19f6d710 1283 int r;
01f78473
LP
1284
1285 assert(filename);
1286 assert(lvalue);
1287 assert(rvalue);
1288 assert(data);
1289
74051b9b
LP
1290 if (isempty(rvalue)) {
1291 /* Empty assignment clears list */
1292 path_free_specs(p);
1293 return 0;
1294 }
1295
93e4c84b
LP
1296 b = path_type_from_string(lvalue);
1297 if (b < 0) {
e8e581bf
ZJS
1298 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1299 "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 1300 return 0;
01f78473
LP
1301 }
1302
19f6d710
LP
1303 r = unit_full_printf(UNIT(p), rvalue, &k);
1304 if (r < 0) {
487060c2
LP
1305 k = strdup(rvalue);
1306 if (!k)
1307 return log_oom();
1308 else
19f6d710 1309 log_syntax(unit, LOG_ERR, filename, line, -r,
e8e581bf
ZJS
1310 "Failed to resolve unit specifiers on %s. Ignoring.",
1311 rvalue);
487060c2 1312 }
93e4c84b
LP
1313
1314 if (!path_is_absolute(k)) {
e8e581bf
ZJS
1315 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1316 "Path is not absolute, ignoring: %s", k);
c0b34696 1317 return 0;
01f78473
LP
1318 }
1319
93e4c84b 1320 s = new0(PathSpec, 1);
543295ad 1321 if (!s)
93e4c84b 1322 return log_oom();
01f78473 1323
718db961 1324 s->unit = UNIT(p);
93e4c84b 1325 s->path = path_kill_slashes(k);
543295ad 1326 k = NULL;
01f78473
LP
1327 s->type = b;
1328 s->inotify_fd = -1;
1329
71fda00f 1330 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
1331
1332 return 0;
1333}
1334
e8e581bf
ZJS
1335int config_parse_socket_service(const char *unit,
1336 const char *filename,
1337 unsigned line,
1338 const char *section,
71a61510 1339 unsigned section_line,
e8e581bf
ZJS
1340 const char *lvalue,
1341 int ltype,
1342 const char *rvalue,
1343 void *data,
1344 void *userdata) {
d9ff321a 1345
718db961 1346 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d9ff321a
LP
1347 Socket *s = data;
1348 int r;
4ff77f66 1349 Unit *x;
74051b9b 1350 _cleanup_free_ char *p = NULL;
d9ff321a
LP
1351
1352 assert(filename);
1353 assert(lvalue);
1354 assert(rvalue);
1355 assert(data);
1356
19f6d710 1357 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 1358 if (r < 0) {
718db961 1359 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
613b411c
LP
1360 return 0;
1361 }
74051b9b 1362
613b411c 1363 if (!endswith(p, ".service")) {
718db961 1364 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
d9ff321a
LP
1365 return 0;
1366 }
1367
613b411c 1368 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 1369 if (r < 0) {
718db961 1370 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
d9ff321a
LP
1371 return 0;
1372 }
1373
4ff77f66
LP
1374 unit_ref_set(&s->service, x);
1375
d9ff321a
LP
1376 return 0;
1377}
1378
e8e581bf
ZJS
1379int config_parse_service_sockets(const char *unit,
1380 const char *filename,
1381 unsigned line,
1382 const char *section,
71a61510 1383 unsigned section_line,
e8e581bf
ZJS
1384 const char *lvalue,
1385 int ltype,
1386 const char *rvalue,
1387 void *data,
1388 void *userdata) {
f976f3f6
LP
1389
1390 Service *s = data;
1391 int r;
f976f3f6
LP
1392 char *state, *w;
1393 size_t l;
1394
1395 assert(filename);
1396 assert(lvalue);
1397 assert(rvalue);
1398 assert(data);
1399
f976f3f6 1400 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 1401 _cleanup_free_ char *t = NULL, *k = NULL;
f976f3f6 1402
57020a3a
LP
1403 t = strndup(w, l);
1404 if (!t)
74051b9b 1405 return log_oom();
f976f3f6 1406
19f6d710
LP
1407 r = unit_name_printf(UNIT(s), t, &k);
1408 if (r < 0)
1409 log_syntax(unit, LOG_ERR, filename, line, -r,
1410 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
57020a3a 1411
19f6d710 1412 if (!endswith(k ?: t, ".socket")) {
e8e581bf 1413 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
19f6d710 1414 "Unit must be of type socket, ignoring: %s", k ?: t);
f976f3f6
LP
1415 continue;
1416 }
1417
19f6d710 1418 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
57020a3a 1419 if (r < 0)
e8e581bf
ZJS
1420 log_syntax(unit, LOG_ERR, filename, line, -r,
1421 "Failed to add dependency on %s, ignoring: %s",
19f6d710 1422 k ?: t, strerror(-r));
f976f3f6 1423
19f6d710 1424 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
57020a3a 1425 if (r < 0)
f976f3f6
LP
1426 return r;
1427 }
1428
1429 return 0;
1430}
1431
e8e581bf
ZJS
1432int config_parse_service_timeout(const char *unit,
1433 const char *filename,
1434 unsigned line,
1435 const char *section,
71a61510 1436 unsigned section_line,
e8e581bf
ZJS
1437 const char *lvalue,
1438 int ltype,
1439 const char *rvalue,
1440 void *data,
1441 void *userdata) {
98709151
LN
1442
1443 Service *s = userdata;
1444 int r;
1445
1446 assert(filename);
1447 assert(lvalue);
1448 assert(rvalue);
1449 assert(s);
1450
71a61510 1451 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 1452 rvalue, data, userdata);
74051b9b 1453 if (r < 0)
d568a335 1454 return r;
98709151 1455
d568a335
MS
1456 if (streq(lvalue, "TimeoutSec")) {
1457 s->start_timeout_defined = true;
1458 s->timeout_stop_usec = s->timeout_start_usec;
1459 } else if (streq(lvalue, "TimeoutStartSec"))
1460 s->start_timeout_defined = true;
1461
1462 return 0;
98709151
LN
1463}
1464
e821075a
LP
1465int config_parse_busname_service(
1466 const char *unit,
1467 const char *filename,
1468 unsigned line,
1469 const char *section,
1470 unsigned section_line,
1471 const char *lvalue,
1472 int ltype,
1473 const char *rvalue,
1474 void *data,
1475 void *userdata) {
1476
1477 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1478 BusName *n = data;
1479 int r;
1480 Unit *x;
1481 _cleanup_free_ char *p = NULL;
1482
1483 assert(filename);
1484 assert(lvalue);
1485 assert(rvalue);
1486 assert(data);
1487
1488 r = unit_name_printf(UNIT(n), rvalue, &p);
1489 if (r < 0) {
1490 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1491 return 0;
1492 }
1493
1494 if (!endswith(p, ".service")) {
1495 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1496 return 0;
1497 }
1498
1499 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1500 if (r < 0) {
1501 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1502 return 0;
1503 }
1504
1505 unit_ref_set(&n->service, x);
1506
1507 return 0;
1508}
1509
e8e581bf
ZJS
1510int config_parse_unit_env_file(const char *unit,
1511 const char *filename,
1512 unsigned line,
1513 const char *section,
71a61510 1514 unsigned section_line,
e8e581bf
ZJS
1515 const char *lvalue,
1516 int ltype,
1517 const char *rvalue,
1518 void *data,
1519 void *userdata) {
ddb26e18 1520
853b8397 1521 char ***env = data;
8fef7659 1522 Unit *u = userdata;
19f6d710
LP
1523 _cleanup_free_ char *n = NULL;
1524 const char *s;
853b8397 1525 int r;
ddb26e18
LP
1526
1527 assert(filename);
1528 assert(lvalue);
1529 assert(rvalue);
1530 assert(data);
1531
74051b9b
LP
1532 if (isempty(rvalue)) {
1533 /* Empty assignment frees the list */
74051b9b
LP
1534 strv_free(*env);
1535 *env = NULL;
1536 return 0;
1537 }
1538
19f6d710
LP
1539 r = unit_full_printf(u, rvalue, &n);
1540 if (r < 0)
1541 log_syntax(unit, LOG_ERR, filename, line, r,
1542 "Failed to resolve specifiers, ignoring: %s", rvalue);
8fef7659 1543
19f6d710 1544 s = n ?: rvalue;
8fef7659 1545 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
e8e581bf
ZJS
1546 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1547 "Path '%s' is not absolute, ignoring.", s);
afe4bfe2
LP
1548 return 0;
1549 }
1550
853b8397
LP
1551 r = strv_extend(env, s);
1552 if (r < 0)
1553 return log_oom();
1554
1555 return 0;
1556}
1557
e8e581bf
ZJS
1558int config_parse_environ(const char *unit,
1559 const char *filename,
1560 unsigned line,
1561 const char *section,
71a61510 1562 unsigned section_line,
e8e581bf
ZJS
1563 const char *lvalue,
1564 int ltype,
1565 const char *rvalue,
1566 void *data,
1567 void *userdata) {
853b8397
LP
1568
1569 Unit *u = userdata;
1570 char*** env = data, *w, *state;
1571 size_t l;
1572 _cleanup_free_ char *k = NULL;
19f6d710 1573 int r;
853b8397
LP
1574
1575 assert(filename);
1576 assert(lvalue);
1577 assert(rvalue);
97d0e5f8 1578 assert(data);
853b8397
LP
1579
1580 if (isempty(rvalue)) {
1581 /* Empty assignment resets the list */
1582 strv_free(*env);
1583 *env = NULL;
1584 return 0;
1585 }
1586
19f6d710
LP
1587 if (u) {
1588 r = unit_full_printf(u, rvalue, &k);
1589 if (r < 0)
1590 log_syntax(unit, LOG_ERR, filename, line, -r,
1591 "Failed to resolve specifiers, ignoring: %s", rvalue);
1592 }
97d0e5f8 1593
19f6d710
LP
1594 if (!k)
1595 k = strdup(rvalue);
8fef7659 1596 if (!k)
74051b9b 1597 return log_oom();
ddb26e18 1598
853b8397
LP
1599 FOREACH_WORD_QUOTED(w, l, k, state) {
1600 _cleanup_free_ char *n;
1601 char **x;
1602
1603 n = cunescape_length(w, l);
1604 if (!n)
1605 return log_oom();
1606
1607 if (!env_assignment_is_valid(n)) {
e8e581bf
ZJS
1608 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1609 "Invalid environment assignment, ignoring: %s", rvalue);
853b8397
LP
1610 continue;
1611 }
1612
1613 x = strv_env_set(*env, n);
1614 if (!x)
1615 return log_oom();
1616
1617 strv_free(*env);
1618 *env = x;
1619 }
ddb26e18 1620
8c7be95e 1621 return 0;
ddb26e18
LP
1622}
1623
e8e581bf
ZJS
1624int config_parse_ip_tos(const char *unit,
1625 const char *filename,
1626 unsigned line,
1627 const char *section,
71a61510 1628 unsigned section_line,
e8e581bf
ZJS
1629 const char *lvalue,
1630 int ltype,
1631 const char *rvalue,
1632 void *data,
1633 void *userdata) {
4fd5948e
LP
1634
1635 int *ip_tos = data, x;
4fd5948e
LP
1636
1637 assert(filename);
1638 assert(lvalue);
1639 assert(rvalue);
1640 assert(data);
1641
f8b69d1d
MS
1642 x = ip_tos_from_string(rvalue);
1643 if (x < 0) {
e8e581bf
ZJS
1644 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1645 "Failed to parse IP TOS value, ignoring: %s", rvalue);
f8b69d1d
MS
1646 return 0;
1647 }
4fd5948e
LP
1648
1649 *ip_tos = x;
1650 return 0;
1651}
1652
e8e581bf
ZJS
1653int config_parse_unit_condition_path(const char *unit,
1654 const char *filename,
1655 unsigned line,
1656 const char *section,
71a61510 1657 unsigned section_line,
e8e581bf
ZJS
1658 const char *lvalue,
1659 int ltype,
1660 const char *rvalue,
1661 void *data,
1662 void *userdata) {
52661efd 1663
2b583ce6 1664 ConditionType cond = ltype;
52661efd 1665 Unit *u = data;
267632f0 1666 bool trigger, negate;
52661efd 1667 Condition *c;
2fbe635a 1668 _cleanup_free_ char *p = NULL;
19f6d710 1669 int r;
52661efd
LP
1670
1671 assert(filename);
1672 assert(lvalue);
1673 assert(rvalue);
1674 assert(data);
1675
74051b9b
LP
1676 if (isempty(rvalue)) {
1677 /* Empty assignment resets the list */
1678 condition_free_list(u->conditions);
1679 u->conditions = NULL;
1680 return 0;
1681 }
1682
ab7f148f
LP
1683 trigger = rvalue[0] == '|';
1684 if (trigger)
267632f0
LP
1685 rvalue++;
1686
ab7f148f
LP
1687 negate = rvalue[0] == '!';
1688 if (negate)
52661efd
LP
1689 rvalue++;
1690
19f6d710
LP
1691 r = unit_full_printf(u, rvalue, &p);
1692 if (r < 0)
1693 log_syntax(unit, LOG_ERR, filename, line, -r,
1694 "Failed to resolve specifiers, ignoring: %s", rvalue);
1695 if (!p) {
1696 p = strdup(rvalue);
1697 if (!p)
1698 return log_oom();
1699 }
095b2d7a
AK
1700
1701 if (!path_is_absolute(p)) {
e8e581bf
ZJS
1702 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1703 "Path in condition not absolute, ignoring: %s", p);
52661efd
LP
1704 return 0;
1705 }
1706
095b2d7a 1707 c = condition_new(cond, p, trigger, negate);
ab7f148f 1708 if (!c)
74051b9b 1709 return log_oom();
52661efd 1710
71fda00f 1711 LIST_PREPEND(conditions, u->conditions, c);
52661efd
LP
1712 return 0;
1713}
1714
e8e581bf
ZJS
1715int config_parse_unit_condition_string(const char *unit,
1716 const char *filename,
1717 unsigned line,
1718 const char *section,
71a61510 1719 unsigned section_line,
e8e581bf
ZJS
1720 const char *lvalue,
1721 int ltype,
1722 const char *rvalue,
1723 void *data,
1724 void *userdata) {
039655a4 1725
41584525 1726 ConditionType cond = ltype;
039655a4 1727 Unit *u = data;
267632f0 1728 bool trigger, negate;
039655a4 1729 Condition *c;
2fbe635a 1730 _cleanup_free_ char *s = NULL;
19f6d710 1731 int r;
039655a4
LP
1732
1733 assert(filename);
1734 assert(lvalue);
1735 assert(rvalue);
1736 assert(data);
1737
74051b9b
LP
1738 if (isempty(rvalue)) {
1739 /* Empty assignment resets the list */
1740 condition_free_list(u->conditions);
1741 u->conditions = NULL;
1742 return 0;
1743 }
1744
c0d6e764
LP
1745 trigger = rvalue[0] == '|';
1746 if (trigger)
267632f0
LP
1747 rvalue++;
1748
c0d6e764
LP
1749 negate = rvalue[0] == '!';
1750 if (negate)
039655a4
LP
1751 rvalue++;
1752
19f6d710
LP
1753 r = unit_full_printf(u, rvalue, &s);
1754 if (r < 0)
1755 log_syntax(unit, LOG_ERR, filename, line, -r,
1756 "Failed to resolve specifiers, ignoring: %s", rvalue);
1757 if (!s) {
1758 s = strdup(rvalue);
1759 if (!s)
1760 return log_oom();
1761 }
095b2d7a
AK
1762
1763 c = condition_new(cond, s, trigger, negate);
c0d6e764
LP
1764 if (!c)
1765 return log_oom();
039655a4 1766
71fda00f 1767 LIST_PREPEND(conditions, u->conditions, c);
039655a4
LP
1768 return 0;
1769}
1770
e8e581bf
ZJS
1771int config_parse_unit_condition_null(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) {
d257ddef
LP
1781
1782 Unit *u = data;
1783 Condition *c;
267632f0 1784 bool trigger, negate;
d257ddef
LP
1785 int b;
1786
1787 assert(filename);
1788 assert(lvalue);
1789 assert(rvalue);
1790 assert(data);
1791
74051b9b
LP
1792 if (isempty(rvalue)) {
1793 /* Empty assignment resets the list */
1794 condition_free_list(u->conditions);
1795 u->conditions = NULL;
1796 return 0;
1797 }
1798
1799 trigger = rvalue[0] == '|';
1800 if (trigger)
267632f0
LP
1801 rvalue++;
1802
74051b9b
LP
1803 negate = rvalue[0] == '!';
1804 if (negate)
d257ddef
LP
1805 rvalue++;
1806
74051b9b
LP
1807 b = parse_boolean(rvalue);
1808 if (b < 0) {
e8e581bf
ZJS
1809 log_syntax(unit, LOG_ERR, filename, line, -b,
1810 "Failed to parse boolean value in condition, ignoring: %s",
1811 rvalue);
d257ddef
LP
1812 return 0;
1813 }
1814
1815 if (!b)
1816 negate = !negate;
1817
74051b9b
LP
1818 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1819 if (!c)
1820 return log_oom();
d257ddef 1821
71fda00f 1822 LIST_PREPEND(conditions, u->conditions, c);
d257ddef
LP
1823 return 0;
1824}
1825
f975e971 1826DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
4b939747 1827DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
c952c6ec 1828
a57f7e2c
LP
1829int config_parse_unit_requires_mounts_for(
1830 const char *unit,
1831 const char *filename,
1832 unsigned line,
1833 const char *section,
71a61510 1834 unsigned section_line,
a57f7e2c
LP
1835 const char *lvalue,
1836 int ltype,
1837 const char *rvalue,
1838 void *data,
1839 void *userdata) {
7c8fa05c
LP
1840
1841 Unit *u = userdata;
a57f7e2c
LP
1842 char *state;
1843 size_t l;
1844 char *w;
7c8fa05c
LP
1845
1846 assert(filename);
1847 assert(lvalue);
1848 assert(rvalue);
1849 assert(data);
1850
a57f7e2c 1851 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
8a7935a2 1852 int r;
a57f7e2c
LP
1853 _cleanup_free_ char *n;
1854
1855 n = strndup(w, l);
1856 if (!n)
1857 return log_oom();
7c8fa05c 1858
a57f7e2c
LP
1859 if (!utf8_is_valid(n)) {
1860 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1861 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1862 continue;
1863 }
7c8fa05c 1864
a57f7e2c
LP
1865 r = unit_require_mounts_for(u, n);
1866 if (r < 0) {
1867 log_syntax(unit, LOG_ERR, filename, line, r,
1868 "Failed to add required mount for, ignoring: %s", rvalue);
1869 continue;
1870 }
1871 }
7c8fa05c 1872
8a7935a2 1873 return 0;
7c8fa05c 1874}
9e372868 1875
e8e581bf
ZJS
1876int config_parse_documentation(const char *unit,
1877 const char *filename,
1878 unsigned line,
1879 const char *section,
71a61510 1880 unsigned section_line,
e8e581bf
ZJS
1881 const char *lvalue,
1882 int ltype,
1883 const char *rvalue,
1884 void *data,
1885 void *userdata) {
49dbfa7b
LP
1886
1887 Unit *u = userdata;
1888 int r;
1889 char **a, **b;
1890
1891 assert(filename);
1892 assert(lvalue);
1893 assert(rvalue);
1894 assert(u);
1895
74051b9b
LP
1896 if (isempty(rvalue)) {
1897 /* Empty assignment resets the list */
1898 strv_free(u->documentation);
1899 u->documentation = NULL;
1900 return 0;
1901 }
1902
71a61510 1903 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 1904 rvalue, data, userdata);
49dbfa7b
LP
1905 if (r < 0)
1906 return r;
1907
1908 for (a = b = u->documentation; a && *a; a++) {
1909
1910 if (is_valid_documentation_url(*a))
1911 *(b++) = *a;
1912 else {
e8e581bf
ZJS
1913 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1914 "Invalid URL, ignoring: %s", *a);
49dbfa7b
LP
1915 free(*a);
1916 }
1917 }
f6d2d421
ZJS
1918 if (b)
1919 *b = NULL;
49dbfa7b
LP
1920
1921 return r;
1922}
1923
c0467cf3 1924#ifdef HAVE_SECCOMP
17df7223
LP
1925int config_parse_syscall_filter(
1926 const char *unit,
1927 const char *filename,
1928 unsigned line,
1929 const char *section,
1930 unsigned section_line,
1931 const char *lvalue,
1932 int ltype,
1933 const char *rvalue,
1934 void *data,
1935 void *userdata) {
1936
1937 static const char default_syscalls[] =
1938 "execve\0"
1939 "exit\0"
1940 "exit_group\0"
1941 "rt_sigreturn\0"
1942 "sigreturn\0";
1943
8351ceae
LP
1944 ExecContext *c = data;
1945 Unit *u = userdata;
b5fb3789 1946 bool invert = false;
17df7223 1947 char *w, *state;
8351ceae 1948 size_t l;
17df7223 1949 int r;
8351ceae
LP
1950
1951 assert(filename);
1952 assert(lvalue);
1953 assert(rvalue);
1954 assert(u);
1955
74051b9b
LP
1956 if (isempty(rvalue)) {
1957 /* Empty assignment resets the list */
17df7223
LP
1958 set_free(c->syscall_filter);
1959 c->syscall_filter = NULL;
1960 c->syscall_whitelist = false;
74051b9b
LP
1961 return 0;
1962 }
1963
8351ceae
LP
1964 if (rvalue[0] == '~') {
1965 invert = true;
1966 rvalue++;
1967 }
1968
17df7223
LP
1969 if (!c->syscall_filter) {
1970 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
1971 if (!c->syscall_filter)
1972 return log_oom();
1973
c0467cf3 1974 if (invert)
17df7223
LP
1975 /* Allow everything but the ones listed */
1976 c->syscall_whitelist = false;
c0467cf3 1977 else {
17df7223
LP
1978 const char *i;
1979
1980 /* Allow nothing but the ones listed */
1981 c->syscall_whitelist = true;
8351ceae 1982
17df7223
LP
1983 /* Accept default syscalls if we are on a whitelist */
1984 NULSTR_FOREACH(i, default_syscalls) {
1985 int id;
8351ceae 1986
17df7223 1987 id = seccomp_syscall_resolve_name(i);
c0467cf3
RC
1988 if (id < 0)
1989 continue;
8351ceae 1990
17df7223
LP
1991 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
1992 if (r == -EEXIST)
1993 continue;
1994 if (r < 0)
1995 return log_oom();
c0467cf3
RC
1996 }
1997 }
8351ceae
LP
1998 }
1999
2000 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 2001 _cleanup_free_ char *t = NULL;
17df7223 2002 int id;
8351ceae
LP
2003
2004 t = strndup(w, l);
2005 if (!t)
74051b9b 2006 return log_oom();
8351ceae 2007
c0467cf3 2008 id = seccomp_syscall_resolve_name(t);
8351ceae 2009 if (id < 0) {
17df7223 2010 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
8351ceae
LP
2011 continue;
2012 }
2013
17df7223
LP
2014 /* If we previously wanted to forbid a syscall and now
2015 * we want to allow it, then remove it from the list
c0467cf3 2016 */
17df7223
LP
2017 if (!invert == c->syscall_whitelist) {
2018 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2019 if (r == -EEXIST)
2020 continue;
2021 if (r < 0)
2022 return log_oom();
2023 } else
2024 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
c0467cf3
RC
2025 }
2026
17df7223
LP
2027 c->no_new_privileges = true;
2028
2029 return 0;
2030}
2031
2032int config_parse_syscall_errno(
2033 const char *unit,
2034 const char *filename,
2035 unsigned line,
2036 const char *section,
2037 unsigned section_line,
2038 const char *lvalue,
2039 int ltype,
2040 const char *rvalue,
2041 void *data,
2042 void *userdata) {
2043
2044 ExecContext *c = data;
2045 int e;
2046
2047 assert(filename);
2048 assert(lvalue);
2049 assert(rvalue);
2050
2051 if (isempty(rvalue)) {
2052 /* Empty assignment resets to KILL */
2053 c->syscall_errno = 0;
2054 return 0;
8351ceae
LP
2055 }
2056
17df7223
LP
2057 e = errno_from_name(rvalue);
2058 if (e < 0) {
2059 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2060 return 0;
2061 }
8351ceae 2062
17df7223 2063 c->syscall_errno = e;
8351ceae
LP
2064 return 0;
2065}
c0467cf3 2066#endif
8351ceae 2067
a016b922
LP
2068int config_parse_unit_slice(
2069 const char *unit,
2070 const char *filename,
2071 unsigned line,
2072 const char *section,
71a61510 2073 unsigned section_line,
a016b922
LP
2074 const char *lvalue,
2075 int ltype,
2076 const char *rvalue,
2077 void *data,
2078 void *userdata) {
2079
2080 _cleanup_free_ char *k = NULL;
2081 Unit *u = userdata, *slice;
2082 int r;
2083
2084 assert(filename);
2085 assert(lvalue);
2086 assert(rvalue);
2087 assert(u);
2088
19f6d710
LP
2089 r = unit_name_printf(u, rvalue, &k);
2090 if (r < 0)
2091 log_syntax(unit, LOG_ERR, filename, line, -r,
a016b922 2092 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
19f6d710
LP
2093 if (!k) {
2094 k = strdup(rvalue);
2095 if (!k)
2096 return log_oom();
2097 }
a016b922 2098
19f6d710 2099 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
a016b922
LP
2100 if (r < 0) {
2101 log_syntax(unit, LOG_ERR, filename, line, -r,
19f6d710 2102 "Failed to load slice unit %s. Ignoring.", k);
a016b922
LP
2103 return 0;
2104 }
2105
2106 if (slice->type != UNIT_SLICE) {
2107 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
19f6d710 2108 "Slice unit %s is not a slice. Ignoring.", k);
a016b922
LP
2109 return 0;
2110 }
2111
2112 unit_ref_set(&u->slice, slice);
2113 return 0;
2114}
2115
4ad49000
LP
2116DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2117
2118int config_parse_cpu_shares(
2119 const char *unit,
2120 const char *filename,
2121 unsigned line,
2122 const char *section,
71a61510 2123 unsigned section_line,
4ad49000
LP
2124 const char *lvalue,
2125 int ltype,
2126 const char *rvalue,
2127 void *data,
2128 void *userdata) {
2129
2130 CGroupContext *c = data;
2131 unsigned long lu;
2132 int r;
2133
2134 assert(filename);
2135 assert(lvalue);
2136 assert(rvalue);
2137
2138 if (isempty(rvalue)) {
2139 c->cpu_shares = 1024;
2140 return 0;
2141 }
2142
2143 r = safe_atolu(rvalue, &lu);
2144 if (r < 0 || lu <= 0) {
2145 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2146 "CPU shares '%s' invalid. Ignoring.", rvalue);
2147 return 0;
2148 }
2149
2150 c->cpu_shares = lu;
2151 return 0;
2152}
2153
2154int config_parse_memory_limit(
2155 const char *unit,
2156 const char *filename,
2157 unsigned line,
2158 const char *section,
71a61510 2159 unsigned section_line,
4ad49000
LP
2160 const char *lvalue,
2161 int ltype,
2162 const char *rvalue,
2163 void *data,
2164 void *userdata) {
2165
2166 CGroupContext *c = data;
4ad49000
LP
2167 off_t bytes;
2168 int r;
2169
4ad49000 2170 if (isempty(rvalue)) {
ddca82ac 2171 c->memory_limit = (uint64_t) -1;
4ad49000
LP
2172 return 0;
2173 }
2174
2175 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2176
2177 r = parse_bytes(rvalue, &bytes);
2178 if (r < 0) {
2179 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2180 "Memory limit '%s' invalid. Ignoring.", rvalue);
2181 return 0;
2182 }
2183
ddca82ac 2184 c->memory_limit = (uint64_t) bytes;
4ad49000
LP
2185 return 0;
2186}
2187
2188int config_parse_device_allow(
2189 const char *unit,
2190 const char *filename,
2191 unsigned line,
2192 const char *section,
71a61510 2193 unsigned section_line,
4ad49000
LP
2194 const char *lvalue,
2195 int ltype,
2196 const char *rvalue,
2197 void *data,
2198 void *userdata) {
2199
2200 _cleanup_free_ char *path = NULL;
2201 CGroupContext *c = data;
2202 CGroupDeviceAllow *a;
2203 const char *m;
2204 size_t n;
2205
2206 if (isempty(rvalue)) {
2207 while (c->device_allow)
2208 cgroup_context_free_device_allow(c, c->device_allow);
2209
2210 return 0;
2211 }
2212
2213 n = strcspn(rvalue, WHITESPACE);
2214 path = strndup(rvalue, n);
2215 if (!path)
2216 return log_oom();
2217
2218 if (!path_startswith(path, "/dev")) {
2219 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2220 "Invalid device node path '%s'. Ignoring.", path);
2221 return 0;
2222 }
2223
2224 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2225 if (isempty(m))
2226 m = "rwm";
2227
2228 if (!in_charset(m, "rwm")) {
2229 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2230 "Invalid device rights '%s'. Ignoring.", m);
2231 return 0;
2232 }
2233
2234 a = new0(CGroupDeviceAllow, 1);
2235 if (!a)
2236 return log_oom();
2237
2238 a->path = path;
2239 path = NULL;
2240 a->r = !!strchr(m, 'r');
2241 a->w = !!strchr(m, 'w');
2242 a->m = !!strchr(m, 'm');
2243
71fda00f 2244 LIST_PREPEND(device_allow, c->device_allow, a);
4ad49000
LP
2245 return 0;
2246}
2247
2248int config_parse_blockio_weight(
2249 const char *unit,
2250 const char *filename,
2251 unsigned line,
2252 const char *section,
71a61510 2253 unsigned section_line,
4ad49000
LP
2254 const char *lvalue,
2255 int ltype,
2256 const char *rvalue,
2257 void *data,
2258 void *userdata) {
2259
8e7076ca
LP
2260 CGroupContext *c = data;
2261 unsigned long lu;
2262 int r;
2263
2264 assert(filename);
2265 assert(lvalue);
2266 assert(rvalue);
2267
2268 if (isempty(rvalue)) {
2269 c->blockio_weight = 1000;
2270 return 0;
2271 }
2272
2273 r = safe_atolu(rvalue, &lu);
2274 if (r < 0 || lu < 10 || lu > 1000) {
2275 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2276 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2277 return 0;
2278 }
2279
2280 c->blockio_weight = lu;
2281
2282 return 0;
2283}
2284
2285int config_parse_blockio_device_weight(
2286 const char *unit,
2287 const char *filename,
2288 unsigned line,
2289 const char *section,
71a61510 2290 unsigned section_line,
8e7076ca
LP
2291 const char *lvalue,
2292 int ltype,
2293 const char *rvalue,
2294 void *data,
2295 void *userdata) {
2296
4ad49000 2297 _cleanup_free_ char *path = NULL;
8e7076ca 2298 CGroupBlockIODeviceWeight *w;
4ad49000
LP
2299 CGroupContext *c = data;
2300 unsigned long lu;
2301 const char *weight;
2302 size_t n;
2303 int r;
2304
2305 assert(filename);
2306 assert(lvalue);
2307 assert(rvalue);
2308
2309 if (isempty(rvalue)) {
4ad49000
LP
2310 while (c->blockio_device_weights)
2311 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2312
2313 return 0;
2314 }
2315
2316 n = strcspn(rvalue, WHITESPACE);
2317 weight = rvalue + n;
8e7076ca
LP
2318 if (!*weight) {
2319 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2320 "Expected block device and device weight. Ignoring.");
2321 return 0;
2322 }
4ad49000 2323
8e7076ca
LP
2324 path = strndup(rvalue, n);
2325 if (!path)
2326 return log_oom();
4ad49000 2327
8e7076ca
LP
2328 if (!path_startswith(path, "/dev")) {
2329 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2330 "Invalid device node path '%s'. Ignoring.", path);
2331 return 0;
2332 }
4ad49000 2333
8e7076ca 2334 weight += strspn(weight, WHITESPACE);
4ad49000
LP
2335 r = safe_atolu(weight, &lu);
2336 if (r < 0 || lu < 10 || lu > 1000) {
2337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2338 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2339 return 0;
2340 }
2341
4ad49000 2342
8e7076ca
LP
2343 w = new0(CGroupBlockIODeviceWeight, 1);
2344 if (!w)
2345 return log_oom();
4ad49000 2346
8e7076ca
LP
2347 w->path = path;
2348 path = NULL;
4ad49000 2349
8e7076ca 2350 w->weight = lu;
4ad49000 2351
71fda00f 2352 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
2353 return 0;
2354}
2355
2356int config_parse_blockio_bandwidth(
2357 const char *unit,
2358 const char *filename,
2359 unsigned line,
2360 const char *section,
71a61510 2361 unsigned section_line,
4ad49000
LP
2362 const char *lvalue,
2363 int ltype,
2364 const char *rvalue,
2365 void *data,
2366 void *userdata) {
2367
2368 _cleanup_free_ char *path = NULL;
2369 CGroupBlockIODeviceBandwidth *b;
2370 CGroupContext *c = data;
2371 const char *bandwidth;
2372 off_t bytes;
47c0980d 2373 bool read;
4ad49000
LP
2374 size_t n;
2375 int r;
2376
2377 assert(filename);
2378 assert(lvalue);
2379 assert(rvalue);
2380
47c0980d
G
2381 read = streq("BlockIOReadBandwidth", lvalue);
2382
4ad49000 2383 if (isempty(rvalue)) {
47c0980d
G
2384 CGroupBlockIODeviceBandwidth *next;
2385
2386 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2387 if (b->read == read)
2388 cgroup_context_free_blockio_device_bandwidth(c, b);
4ad49000
LP
2389
2390 return 0;
2391 }
2392
2393 n = strcspn(rvalue, WHITESPACE);
2394 bandwidth = rvalue + n;
2395 bandwidth += strspn(bandwidth, WHITESPACE);
2396
2397 if (!*bandwidth) {
2398 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2399 "Expected space separated pair of device node and bandwidth. Ignoring.");
2400 return 0;
2401 }
2402
2403 path = strndup(rvalue, n);
2404 if (!path)
2405 return log_oom();
2406
2407 if (!path_startswith(path, "/dev")) {
2408 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2409 "Invalid device node path '%s'. Ignoring.", path);
2410 return 0;
2411 }
2412
2413 r = parse_bytes(bandwidth, &bytes);
2414 if (r < 0 || bytes <= 0) {
2415 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2416 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2417 return 0;
2418 }
2419
2420 b = new0(CGroupBlockIODeviceBandwidth, 1);
2421 if (!b)
2422 return log_oom();
2423
2424 b->path = path;
2425 path = NULL;
2426 b->bandwidth = (uint64_t) bytes;
47c0980d 2427 b->read = read;
4ad49000 2428
71fda00f 2429 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
4ad49000
LP
2430
2431 return 0;
2432}
2433
d420282b
LP
2434DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2435
2436int config_parse_job_mode_isolate(
2437 const char *unit,
2438 const char *filename,
2439 unsigned line,
2440 const char *section,
2441 unsigned section_line,
2442 const char *lvalue,
2443 int ltype,
2444 const char *rvalue,
2445 void *data,
2446 void *userdata) {
2447
2448 JobMode *m = data;
2449 int r;
2450
2451 assert(filename);
2452 assert(lvalue);
2453 assert(rvalue);
2454
2455 r = parse_boolean(rvalue);
2456 if (r < 0) {
2457 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2458 return 0;
2459 }
2460
2461 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2462 return 0;
2463}
2464
071830ff 2465#define FOLLOW_MAX 8
87f0e418 2466
9e2f7c11 2467static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
0301abf4 2468 unsigned c = 0;
87f0e418
LP
2469 int fd, r;
2470 FILE *f;
0301abf4 2471 char *id = NULL;
87f0e418
LP
2472
2473 assert(filename);
2474 assert(*filename);
2475 assert(_f);
2476 assert(names);
2477
0301abf4
LP
2478 /* This will update the filename pointer if the loaded file is
2479 * reached by a symlink. The old string will be freed. */
87f0e418 2480
0301abf4 2481 for (;;) {
2c7108c4 2482 char *target, *name;
87f0e418 2483
0301abf4
LP
2484 if (c++ >= FOLLOW_MAX)
2485 return -ELOOP;
2486
b08d03ff
LP
2487 path_kill_slashes(*filename);
2488
87f0e418 2489 /* Add the file name we are currently looking at to
8f05424d
LP
2490 * the names of this unit, but only if it is a valid
2491 * unit name. */
2b6bf07d 2492 name = basename(*filename);
87f0e418 2493
f78e6385 2494 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
8f05424d 2495
15e11d81
LP
2496 id = set_get(names, name);
2497 if (!id) {
2498 id = strdup(name);
2499 if (!id)
8f05424d 2500 return -ENOMEM;
87f0e418 2501
ef42202a
ZJS
2502 r = set_consume(names, id);
2503 if (r < 0)
8f05424d 2504 return r;
87f0e418 2505 }
87f0e418
LP
2506 }
2507
0301abf4 2508 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
2509 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2510 if (fd >= 0)
87f0e418
LP
2511 break;
2512
0301abf4
LP
2513 if (errno != ELOOP)
2514 return -errno;
2515
87f0e418 2516 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
2517 r = readlink_and_make_absolute(*filename, &target);
2518 if (r < 0)
0301abf4 2519 return r;
87f0e418 2520
0301abf4 2521 free(*filename);
2c7108c4 2522 *filename = target;
87f0e418
LP
2523 }
2524
9946996c
LP
2525 f = fdopen(fd, "re");
2526 if (!f) {
87f0e418 2527 r = -errno;
9e2f7c11 2528 close_nointr_nofail(fd);
0301abf4 2529 return r;
87f0e418
LP
2530 }
2531
2532 *_f = f;
9e2f7c11 2533 *_final = id;
0301abf4 2534 return 0;
87f0e418
LP
2535}
2536
23a177ef
LP
2537static int merge_by_names(Unit **u, Set *names, const char *id) {
2538 char *k;
2539 int r;
2540
2541 assert(u);
2542 assert(*u);
2543 assert(names);
2544
2545 /* Let's try to add in all symlink names we found */
2546 while ((k = set_steal_first(names))) {
2547
2548 /* First try to merge in the other name into our
2549 * unit */
9946996c
LP
2550 r = unit_merge_by_name(*u, k);
2551 if (r < 0) {
23a177ef
LP
2552 Unit *other;
2553
2554 /* Hmm, we couldn't merge the other unit into
2555 * ours? Then let's try it the other way
2556 * round */
2557
ac155bb8 2558 other = manager_get_unit((*u)->manager, k);
23a177ef
LP
2559 free(k);
2560
9946996c
LP
2561 if (other) {
2562 r = unit_merge(other, *u);
2563 if (r >= 0) {
23a177ef
LP
2564 *u = other;
2565 return merge_by_names(u, names, NULL);
2566 }
9946996c 2567 }
23a177ef
LP
2568
2569 return r;
2570 }
2571
2572 if (id == k)
2573 unit_choose_id(*u, id);
2574
2575 free(k);
2576 }
2577
2578 return 0;
2579}
2580
e537352b 2581static int load_from_path(Unit *u, const char *path) {
0301abf4 2582 int r;
e48614c4
ZJS
2583 _cleanup_set_free_free_ Set *symlink_names = NULL;
2584 _cleanup_fclose_ FILE *f = NULL;
2585 _cleanup_free_ char *filename = NULL;
2586 char *id = NULL;
23a177ef 2587 Unit *merged;
45fb0699 2588 struct stat st;
23a177ef
LP
2589
2590 assert(u);
e537352b 2591 assert(path);
3efd4195 2592
f975e971
LP
2593 symlink_names = set_new(string_hash_func, string_compare_func);
2594 if (!symlink_names)
87f0e418 2595 return -ENOMEM;
3efd4195 2596
036643a2
LP
2597 if (path_is_absolute(path)) {
2598
9946996c 2599 filename = strdup(path);
e48614c4
ZJS
2600 if (!filename)
2601 return -ENOMEM;
036643a2 2602
9946996c
LP
2603 r = open_follow(&filename, &f, symlink_names, &id);
2604 if (r < 0) {
036643a2
LP
2605 free(filename);
2606 filename = NULL;
2607
2608 if (r != -ENOENT)
e48614c4 2609 return r;
036643a2
LP
2610 }
2611
2612 } else {
2613 char **p;
2614
ac155bb8 2615 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
036643a2
LP
2616
2617 /* Instead of opening the path right away, we manually
2618 * follow all symlinks and add their name to our unit
2619 * name set while doing so */
9946996c 2620 filename = path_make_absolute(path, *p);
e48614c4
ZJS
2621 if (!filename)
2622 return -ENOMEM;
036643a2 2623
ac155bb8
MS
2624 if (u->manager->unit_path_cache &&
2625 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
2626 r = -ENOENT;
2627 else
2628 r = open_follow(&filename, &f, symlink_names, &id);
2629
2630 if (r < 0) {
036643a2
LP
2631 free(filename);
2632 filename = NULL;
2633
2634 if (r != -ENOENT)
e48614c4 2635 return r;
036643a2
LP
2636
2637 /* Empty the symlink names for the next run */
9946996c 2638 set_clear_free(symlink_names);
036643a2
LP
2639 continue;
2640 }
2641
2642 break;
2643 }
2644 }
034c6ed7 2645
e48614c4 2646 if (!filename)
8f05424d 2647 /* Hmm, no suitable file found? */
e48614c4 2648 return 0;
87f0e418 2649
23a177ef 2650 merged = u;
9946996c
LP
2651 r = merge_by_names(&merged, symlink_names, id);
2652 if (r < 0)
e48614c4 2653 return r;
87f0e418 2654
23a177ef 2655 if (merged != u) {
ac155bb8 2656 u->load_state = UNIT_MERGED;
e48614c4 2657 return 0;
034c6ed7
LP
2658 }
2659
e48614c4
ZJS
2660 if (fstat(fileno(f), &st) < 0)
2661 return -errno;
45fb0699 2662
00dc5d76 2663 if (null_or_empty(&st))
ac155bb8 2664 u->load_state = UNIT_MASKED;
00dc5d76 2665 else {
c2756a68
LP
2666 u->load_state = UNIT_LOADED;
2667
00dc5d76 2668 /* Now, parse the file contents */
e8e581bf
ZJS
2669 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2670 config_item_perf_lookup,
db5c0122 2671 (void*) load_fragment_gperf_lookup, false, true, u);
f975e971 2672 if (r < 0)
e48614c4 2673 return r;
00dc5d76 2674 }
b08d03ff 2675
ac155bb8
MS
2676 free(u->fragment_path);
2677 u->fragment_path = filename;
0301abf4 2678 filename = NULL;
87f0e418 2679
ac155bb8 2680 u->fragment_mtime = timespec_load(&st.st_mtim);
45fb0699 2681
1b64d026
LP
2682 if (u->source_path) {
2683 if (stat(u->source_path, &st) >= 0)
2684 u->source_mtime = timespec_load(&st.st_mtim);
2685 else
2686 u->source_mtime = 0;
2687 }
2688
e48614c4 2689 return 0;
0301abf4
LP
2690}
2691
e537352b 2692int unit_load_fragment(Unit *u) {
23a177ef 2693 int r;
294d81f1
LP
2694 Iterator i;
2695 const char *t;
0301abf4
LP
2696
2697 assert(u);
ac155bb8
MS
2698 assert(u->load_state == UNIT_STUB);
2699 assert(u->id);
23a177ef 2700
294d81f1
LP
2701 /* First, try to find the unit under its id. We always look
2702 * for unit files in the default directories, to make it easy
2703 * to override things by placing things in /etc/systemd/system */
9946996c
LP
2704 r = load_from_path(u, u->id);
2705 if (r < 0)
294d81f1
LP
2706 return r;
2707
2708 /* Try to find an alias we can load this with */
ac155bb8
MS
2709 if (u->load_state == UNIT_STUB)
2710 SET_FOREACH(t, u->names, i) {
294d81f1 2711
ac155bb8 2712 if (t == u->id)
294d81f1
LP
2713 continue;
2714
9946996c
LP
2715 r = load_from_path(u, t);
2716 if (r < 0)
294d81f1
LP
2717 return r;
2718
ac155bb8 2719 if (u->load_state != UNIT_STUB)
294d81f1
LP
2720 break;
2721 }
23a177ef 2722
294d81f1 2723 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 2724 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 2725
9946996c
LP
2726 r = load_from_path(u, u->fragment_path);
2727 if (r < 0)
23a177ef 2728 return r;
0301abf4 2729
ac155bb8 2730 if (u->load_state == UNIT_STUB) {
6ccb1b44
LP
2731 /* Hmm, this didn't work? Then let's get rid
2732 * of the fragment path stored for us, so that
2733 * we don't point to an invalid location. */
ac155bb8
MS
2734 free(u->fragment_path);
2735 u->fragment_path = NULL;
6ccb1b44
LP
2736 }
2737 }
2738
294d81f1 2739 /* Look for a template */
ac155bb8 2740 if (u->load_state == UNIT_STUB && u->instance) {
bc9fd78c 2741 _cleanup_free_ char *k;
294d81f1 2742
9946996c
LP
2743 k = unit_name_template(u->id);
2744 if (!k)
294d81f1
LP
2745 return -ENOMEM;
2746
2747 r = load_from_path(u, k);
294d81f1 2748 if (r < 0)
9e2f7c11 2749 return r;
890f434c 2750
ac155bb8
MS
2751 if (u->load_state == UNIT_STUB)
2752 SET_FOREACH(t, u->names, i) {
bc9fd78c 2753 _cleanup_free_ char *z = NULL;
87f0e418 2754
ac155bb8 2755 if (t == u->id)
23a177ef 2756 continue;
071830ff 2757
bc9fd78c
LP
2758 z = unit_name_template(t);
2759 if (!z)
294d81f1
LP
2760 return -ENOMEM;
2761
bc9fd78c 2762 r = load_from_path(u, z);
294d81f1 2763 if (r < 0)
23a177ef 2764 return r;
890f434c 2765
ac155bb8 2766 if (u->load_state != UNIT_STUB)
23a177ef
LP
2767 break;
2768 }
071830ff
LP
2769 }
2770
23a177ef 2771 return 0;
3efd4195 2772}
e537352b
LP
2773
2774void unit_dump_config_items(FILE *f) {
f975e971
LP
2775 static const struct {
2776 const ConfigParserCallback callback;
2777 const char *rvalue;
2778 } table[] = {
17df7223
LP
2779#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP)
2780 { config_parse_warn_compat, "NOTSUPPORTED" },
2781#endif
f975e971
LP
2782 { config_parse_int, "INTEGER" },
2783 { config_parse_unsigned, "UNSIGNED" },
9ba1a159 2784 { config_parse_bytes_size, "SIZE" },
f975e971
LP
2785 { config_parse_bool, "BOOLEAN" },
2786 { config_parse_string, "STRING" },
2787 { config_parse_path, "PATH" },
2788 { config_parse_unit_path_printf, "PATH" },
2789 { config_parse_strv, "STRING [...]" },
2790 { config_parse_exec_nice, "NICE" },
2791 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2792 { config_parse_exec_io_class, "IOCLASS" },
2793 { config_parse_exec_io_priority, "IOPRIORITY" },
2794 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2795 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2796 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2797 { config_parse_mode, "MODE" },
2798 { config_parse_unit_env_file, "FILE" },
2799 { config_parse_output, "OUTPUT" },
2800 { config_parse_input, "INPUT" },
2801 { config_parse_facility, "FACILITY" },
2802 { config_parse_level, "LEVEL" },
2803 { config_parse_exec_capabilities, "CAPABILITIES" },
2804 { config_parse_exec_secure_bits, "SECUREBITS" },
ec8927ca 2805 { config_parse_bounding_set, "BOUNDINGSET" },
f975e971 2806 { config_parse_limit, "LIMIT" },
f975e971 2807 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
2808 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2809 { config_parse_service_type, "SERVICETYPE" },
2810 { config_parse_service_restart, "SERVICERESTART" },
2811#ifdef HAVE_SYSV_COMPAT
2812 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
2813#endif
2814 { config_parse_kill_mode, "KILLMODE" },
2815 { config_parse_kill_signal, "SIGNAL" },
2816 { config_parse_socket_listen, "SOCKET [...]" },
2817 { config_parse_socket_bind, "SOCKETBIND" },
2818 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 2819 { config_parse_sec, "SECONDS" },
d88a251b 2820 { config_parse_nsec, "NANOSECONDS" },
f975e971 2821 { config_parse_path_strv, "PATH [...]" },
7c8fa05c 2822 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
2823 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2824 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 2825 { config_parse_trigger_unit, "UNIT" },
f975e971 2826 { config_parse_timer, "TIMER" },
f975e971 2827 { config_parse_path_spec, "PATH" },
f975e971
LP
2828 { config_parse_notify_access, "ACCESS" },
2829 { config_parse_ip_tos, "TOS" },
2830 { config_parse_unit_condition_path, "CONDITION" },
2831 { config_parse_unit_condition_string, "CONDITION" },
2832 { config_parse_unit_condition_null, "CONDITION" },
a016b922 2833 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
2834 { config_parse_documentation, "URL" },
2835 { config_parse_service_timeout, "SECONDS" },
2836 { config_parse_start_limit_action, "ACTION" },
2837 { config_parse_set_status, "STATUS" },
2838 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 2839 { config_parse_environ, "ENVIRON" },
c0467cf3 2840#ifdef HAVE_SECCOMP
17df7223
LP
2841 { config_parse_syscall_filter, "SYSCALLS" },
2842 { config_parse_syscall_errno, "ERRNO" },
c0467cf3 2843#endif
7f0386f6
LP
2844 { config_parse_cpu_shares, "SHARES" },
2845 { config_parse_memory_limit, "LIMIT" },
2846 { config_parse_device_allow, "DEVICE" },
2847 { config_parse_device_policy, "POLICY" },
2848 { config_parse_blockio_bandwidth, "BANDWIDTH" },
2849 { config_parse_blockio_weight, "WEIGHT" },
2850 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
2851 { config_parse_long, "LONG" },
2852 { config_parse_socket_service, "SERVICE" },
f975e971
LP
2853 };
2854
2855 const char *prev = NULL;
2856 const char *i;
2857
2858 assert(f);
e537352b 2859
f975e971
LP
2860 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2861 const char *rvalue = "OTHER", *lvalue;
2862 unsigned j;
2863 size_t prefix_len;
2864 const char *dot;
2865 const ConfigPerfItem *p;
2866
2867 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2868
2869 dot = strchr(i, '.');
2870 lvalue = dot ? dot + 1 : i;
2871 prefix_len = dot-i;
2872
2873 if (dot)
641906e9 2874 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
2875 if (prev)
2876 fputc('\n', f);
2877
2878 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2879 }
2880
2881 for (j = 0; j < ELEMENTSOF(table); j++)
2882 if (p->parse == table[j].callback) {
2883 rvalue = table[j].rvalue;
2884 break;
2885 }
2886
2887 fprintf(f, "%s=%s\n", lvalue, rvalue);
2888 prev = i;
2889 }
e537352b 2890}