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