]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
resolved: do not free() sd_dhcp_lease_get_dns() results
[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>
54d76c92
DM
36#include <sys/types.h>
37#include <grp.h>
17df7223 38
c0467cf3
RC
39#ifdef HAVE_SECCOMP
40#include <seccomp.h>
c0467cf3 41#endif
3efd4195 42
84f6181c 43#include "sd-messages.h"
87f0e418 44#include "unit.h"
3efd4195
LP
45#include "strv.h"
46#include "conf-parser.h"
47#include "load-fragment.h"
16354eff 48#include "log.h"
9eba9da4 49#include "ioprio.h"
94f04347
LP
50#include "securebits.h"
51#include "missing.h"
9e2f7c11 52#include "unit-name.h"
41f9172f 53#include "unit-printf.h"
7f110ff9 54#include "utf8.h"
9eb977db 55#include "path-util.h"
853b8397 56#include "env-util.h"
4ad49000 57#include "cgroup.h"
718db961
LP
58#include "bus-util.h"
59#include "bus-error.h"
17df7223 60#include "errno-list.h"
4298d0b5 61#include "af-list.h"
3efd4195 62
57183d11
LP
63#ifdef HAVE_SECCOMP
64#include "seccomp-util.h"
65#endif
66
7f8aa671 67#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
68int config_parse_warn_compat(
69 const char *unit,
70 const char *filename,
71 unsigned line,
72 const char *section,
73 unsigned section_line,
74 const char *lvalue,
75 int ltype,
76 const char *rvalue,
77 void *data,
78 void *userdata) {
e8e581bf
ZJS
79
80 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
81 "Support for option %s= has been disabled at compile time and is ignored",
82 lvalue);
07459bb6
FF
83 return 0;
84}
85#endif
86
e8e581bf
ZJS
87int config_parse_unit_deps(const char* unit,
88 const char *filename,
89 unsigned line,
90 const char *section,
71a61510 91 unsigned section_line,
e8e581bf
ZJS
92 const char *lvalue,
93 int ltype,
94 const char *rvalue,
95 void *data,
96 void *userdata) {
3efd4195 97
f975e971 98 UnitDependency d = ltype;
87f0e418 99 Unit *u = userdata;
a429267c 100 char *w, *state;
3efd4195 101 size_t l;
3efd4195
LP
102
103 assert(filename);
104 assert(lvalue);
105 assert(rvalue);
3efd4195 106
f60f22df 107 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 108 _cleanup_free_ char *t = NULL, *k = NULL;
3efd4195 109 int r;
3efd4195 110
57020a3a
LP
111 t = strndup(w, l);
112 if (!t)
74051b9b 113 return log_oom();
3efd4195 114
19f6d710
LP
115 r = unit_name_printf(u, t, &k);
116 if (r < 0) {
117 log_syntax(unit, LOG_ERR, filename, line, -r,
118 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
119 continue;
120 }
9e2f7c11 121
701cc384 122 r = unit_add_dependency_by_name(u, d, k, NULL, true);
57020a3a 123 if (r < 0)
e8e581bf
ZJS
124 log_syntax(unit, LOG_ERR, filename, line, -r,
125 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
3efd4195
LP
126 }
127
128 return 0;
129}
130
e8e581bf
ZJS
131int config_parse_unit_string_printf(const char *unit,
132 const char *filename,
133 unsigned line,
134 const char *section,
71a61510 135 unsigned section_line,
e8e581bf
ZJS
136 const char *lvalue,
137 int ltype,
138 const char *rvalue,
139 void *data,
140 void *userdata) {
932921b5
LP
141
142 Unit *u = userdata;
74051b9b 143 _cleanup_free_ char *k = NULL;
19f6d710 144 int r;
932921b5
LP
145
146 assert(filename);
147 assert(lvalue);
148 assert(rvalue);
f2d3769a 149 assert(u);
932921b5 150
19f6d710
LP
151 r = unit_full_printf(u, rvalue, &k);
152 if (r < 0)
153 log_syntax(unit, LOG_ERR, filename, line, -r,
154 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
932921b5 155
71a61510 156 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 157 k ? k : rvalue, data, userdata);
932921b5
LP
158}
159
e8e581bf
ZJS
160int config_parse_unit_strv_printf(const char *unit,
161 const char *filename,
162 unsigned line,
163 const char *section,
71a61510 164 unsigned section_line,
e8e581bf
ZJS
165 const char *lvalue,
166 int ltype,
167 const char *rvalue,
168 void *data,
169 void *userdata) {
8fef7659
LP
170
171 Unit *u = userdata;
74051b9b 172 _cleanup_free_ char *k = NULL;
19f6d710 173 int r;
8fef7659
LP
174
175 assert(filename);
176 assert(lvalue);
177 assert(rvalue);
178 assert(u);
179
19f6d710
LP
180 r = unit_full_printf(u, rvalue, &k);
181 if (r < 0)
182 log_syntax(unit, LOG_ERR, filename, line, -r,
183 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
8fef7659 184
71a61510 185 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 186 k ? k : rvalue, data, userdata);
8fef7659
LP
187}
188
e8e581bf
ZJS
189int config_parse_unit_path_printf(const char *unit,
190 const char *filename,
191 unsigned line,
192 const char *section,
71a61510 193 unsigned section_line,
e8e581bf
ZJS
194 const char *lvalue,
195 int ltype,
196 const char *rvalue,
197 void *data,
198 void *userdata) {
6ea832a2 199
74051b9b 200 _cleanup_free_ char *k = NULL;
811ba7a0 201 Unit *u = userdata;
19f6d710 202 int r;
6ea832a2
LP
203
204 assert(filename);
205 assert(lvalue);
206 assert(rvalue);
6ea832a2
LP
207 assert(u);
208
19f6d710 209 r = unit_full_printf(u, rvalue, &k);
811ba7a0
LP
210 if (r < 0) {
211 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
212 return 0;
213 }
6ea832a2 214
811ba7a0
LP
215 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
216}
217
218int config_parse_unit_path_strv_printf(
219 const char *unit,
220 const char *filename,
221 unsigned line,
222 const char *section,
223 unsigned section_line,
224 const char *lvalue,
225 int ltype,
226 const char *rvalue,
227 void *data,
228 void *userdata) {
229
230 char *w, *state, ***x = data;
231 Unit *u = userdata;
232 size_t l;
233 int r;
234
235 assert(filename);
236 assert(lvalue);
237 assert(rvalue);
238 assert(u);
239
240 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
241 _cleanup_free_ char *k = NULL;
242 char t[l+1];
243
244 memcpy(t, w, l);
245 t[l] = 0;
246
247 r = unit_full_printf(u, t, &k);
248 if (r < 0) {
249 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
250 return 0;
251 }
252
253 if (!utf8_is_valid(k)) {
254 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
255 return 0;
256 }
257
258 if (!path_is_absolute(k)) {
259 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
260 return 0;
261 }
262
263 path_kill_slashes(k);
264
265 r = strv_push(x, k);
266 if (r < 0)
267 return log_oom();
268
269 k = NULL;
270 }
271
272 return 0;
6ea832a2
LP
273}
274
e8e581bf
ZJS
275int config_parse_socket_listen(const char *unit,
276 const char *filename,
277 unsigned line,
278 const char *section,
71a61510 279 unsigned section_line,
e8e581bf
ZJS
280 const char *lvalue,
281 int ltype,
282 const char *rvalue,
283 void *data,
284 void *userdata) {
42f4e3c4 285
49f91047 286 SocketPort *p, *tail;
542563ba 287 Socket *s;
19f6d710 288 int r;
16354eff 289
42f4e3c4
LP
290 assert(filename);
291 assert(lvalue);
292 assert(rvalue);
293 assert(data);
294
595ed347 295 s = SOCKET(data);
542563ba 296
74051b9b
LP
297 if (isempty(rvalue)) {
298 /* An empty assignment removes all ports */
299 socket_free_ports(s);
300 return 0;
301 }
302
7f110ff9
LP
303 p = new0(SocketPort, 1);
304 if (!p)
74051b9b 305 return log_oom();
916abb21 306
74051b9b 307 if (ltype != SOCKET_SOCKET) {
916abb21 308
74051b9b 309 p->type = ltype;
19f6d710
LP
310 r = unit_full_printf(UNIT(s), rvalue, &p->path);
311 if (r < 0) {
487060c2
LP
312 p->path = strdup(rvalue);
313 if (!p->path) {
314 free(p);
315 return log_oom();
316 } else
19f6d710
LP
317 log_syntax(unit, LOG_ERR, filename, line, -r,
318 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
916abb21
LP
319 }
320
321 path_kill_slashes(p->path);
322
7a22745a 323 } else if (streq(lvalue, "ListenNetlink")) {
74051b9b 324 _cleanup_free_ char *k = NULL;
1fd45a90 325
7a22745a 326 p->type = SOCKET_SOCKET;
19f6d710
LP
327 r = unit_full_printf(UNIT(s), rvalue, &k);
328 if (r < 0)
329 log_syntax(unit, LOG_ERR, filename, line, -r,
330 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
7a22745a 331
487060c2 332 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
1fd45a90 333 if (r < 0) {
19f6d710 334 log_syntax(unit, LOG_ERR, filename, line, -r,
e8e581bf 335 "Failed to parse address value, ignoring: %s", rvalue);
7a22745a
LP
336 free(p);
337 return 0;
338 }
339
542563ba 340 } else {
74051b9b 341 _cleanup_free_ char *k = NULL;
1fd45a90 342
542563ba 343 p->type = SOCKET_SOCKET;
19f6d710
LP
344 r = unit_full_printf(UNIT(s), rvalue, &k);
345 if (r < 0)
346 log_syntax(unit, LOG_ERR, filename, line, -r,
347 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
542563ba 348
487060c2 349 r = socket_address_parse(&p->address, k ? k : rvalue);
1fd45a90 350 if (r < 0) {
19f6d710 351 log_syntax(unit, LOG_ERR, filename, line, -r,
e8e581bf 352 "Failed to parse address value, ignoring: %s", rvalue);
542563ba 353 free(p);
c0b34696 354 return 0;
542563ba
LP
355 }
356
357 if (streq(lvalue, "ListenStream"))
358 p->address.type = SOCK_STREAM;
359 else if (streq(lvalue, "ListenDatagram"))
360 p->address.type = SOCK_DGRAM;
361 else {
362 assert(streq(lvalue, "ListenSequentialPacket"));
363 p->address.type = SOCK_SEQPACKET;
364 }
365
366 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
e8e581bf
ZJS
367 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
368 "Address family not supported, ignoring: %s", rvalue);
542563ba 369 free(p);
c0b34696 370 return 0;
542563ba 371 }
16354eff
LP
372 }
373
542563ba 374 p->fd = -1;
2e41a51e 375 p->socket = s;
49f91047
LP
376
377 if (s->ports) {
71fda00f
LP
378 LIST_FIND_TAIL(port, s->ports, tail);
379 LIST_INSERT_AFTER(port, s->ports, tail, p);
49f91047 380 } else
71fda00f 381 LIST_PREPEND(port, s->ports, p);
542563ba 382
16354eff 383 return 0;
42f4e3c4
LP
384}
385
e8e581bf
ZJS
386int config_parse_socket_bind(const char *unit,
387 const char *filename,
388 unsigned line,
389 const char *section,
71a61510 390 unsigned section_line,
e8e581bf
ZJS
391 const char *lvalue,
392 int ltype,
393 const char *rvalue,
394 void *data,
395 void *userdata) {
42f4e3c4 396
542563ba 397 Socket *s;
c0120d99 398 SocketAddressBindIPv6Only b;
42f4e3c4
LP
399
400 assert(filename);
401 assert(lvalue);
402 assert(rvalue);
403 assert(data);
404
595ed347 405 s = SOCKET(data);
542563ba 406
5198dabc
LP
407 b = socket_address_bind_ipv6_only_from_string(rvalue);
408 if (b < 0) {
c0120d99
LP
409 int r;
410
5198dabc
LP
411 r = parse_boolean(rvalue);
412 if (r < 0) {
e8e581bf
ZJS
413 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
414 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
c0b34696 415 return 0;
c0120d99 416 }
42f4e3c4 417
c0120d99
LP
418 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
419 } else
420 s->bind_ipv6_only = b;
542563ba 421
42f4e3c4
LP
422 return 0;
423}
424
e8e581bf
ZJS
425int config_parse_exec_nice(const char *unit,
426 const char *filename,
427 unsigned line,
428 const char *section,
71a61510 429 unsigned section_line,
e8e581bf
ZJS
430 const char *lvalue,
431 int ltype,
432 const char *rvalue,
433 void *data,
434 void *userdata) {
034c6ed7 435
fb33a393 436 ExecContext *c = data;
e8e581bf 437 int priority, r;
034c6ed7
LP
438
439 assert(filename);
440 assert(lvalue);
441 assert(rvalue);
442 assert(data);
443
e8e581bf
ZJS
444 r = safe_atoi(rvalue, &priority);
445 if (r < 0) {
446 log_syntax(unit, LOG_ERR, filename, line, -r,
447 "Failed to parse nice priority, ignoring: %s. ", rvalue);
c0b34696 448 return 0;
034c6ed7
LP
449 }
450
451 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
e8e581bf
ZJS
452 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
453 "Nice priority out of range, ignoring: %s", rvalue);
c0b34696 454 return 0;
034c6ed7
LP
455 }
456
fb33a393 457 c->nice = priority;
71155933 458 c->nice_set = true;
fb33a393 459
034c6ed7
LP
460 return 0;
461}
462
e8e581bf
ZJS
463int config_parse_exec_oom_score_adjust(const char* unit,
464 const char *filename,
465 unsigned line,
466 const char *section,
71a61510 467 unsigned section_line,
e8e581bf
ZJS
468 const char *lvalue,
469 int ltype,
470 const char *rvalue,
471 void *data,
472 void *userdata) {
034c6ed7 473
fb33a393 474 ExecContext *c = data;
e8e581bf 475 int oa, r;
034c6ed7
LP
476
477 assert(filename);
478 assert(lvalue);
479 assert(rvalue);
480 assert(data);
481
e8e581bf
ZJS
482 r = safe_atoi(rvalue, &oa);
483 if (r < 0) {
484 log_syntax(unit, LOG_ERR, filename, line, -r,
485 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
c0b34696 486 return 0;
034c6ed7
LP
487 }
488
dd6c17b1 489 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
e8e581bf
ZJS
490 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
491 "OOM score adjust value out of range, ignoring: %s", rvalue);
c0b34696 492 return 0;
034c6ed7
LP
493 }
494
dd6c17b1
LP
495 c->oom_score_adjust = oa;
496 c->oom_score_adjust_set = true;
fb33a393 497
034c6ed7
LP
498 return 0;
499}
500
e8e581bf
ZJS
501int config_parse_exec(const char *unit,
502 const char *filename,
503 unsigned line,
504 const char *section,
71a61510 505 unsigned section_line,
e8e581bf
ZJS
506 const char *lvalue,
507 int ltype,
508 const char *rvalue,
509 void *data,
510 void *userdata) {
034c6ed7 511
61e5d8ed
LP
512 ExecCommand **e = data, *nce;
513 char *path, **n;
034c6ed7 514 unsigned k;
7f110ff9 515 int r;
034c6ed7
LP
516
517 assert(filename);
518 assert(lvalue);
519 assert(rvalue);
61e5d8ed 520 assert(e);
034c6ed7 521
74051b9b
LP
522 e += ltype;
523
524 if (isempty(rvalue)) {
525 /* An empty assignment resets the list */
526 exec_command_free_list(*e);
527 *e = NULL;
528 return 0;
529 }
530
6c666e26
LP
531 /* We accept an absolute path as first argument, or
532 * alternatively an absolute prefixed with @ to allow
533 * overriding of argv[0]. */
61e5d8ed 534 for (;;) {
0f67f1ef 535 int i;
61e5d8ed
LP
536 char *w;
537 size_t l;
538 char *state;
b708e7ce 539 bool honour_argv0 = false, ignore = false;
6c666e26 540
61e5d8ed
LP
541 path = NULL;
542 nce = NULL;
543 n = NULL;
6c666e26 544
61e5d8ed 545 rvalue += strspn(rvalue, WHITESPACE);
034c6ed7 546
61e5d8ed
LP
547 if (rvalue[0] == 0)
548 break;
034c6ed7 549
0f67f1ef
ZJS
550 for (i = 0; i < 2; i++) {
551 if (rvalue[0] == '-' && !ignore) {
552 ignore = true;
553 rvalue ++;
554 }
b708e7ce 555
0f67f1ef
ZJS
556 if (rvalue[0] == '@' && !honour_argv0) {
557 honour_argv0 = true;
558 rvalue ++;
559 }
b708e7ce 560 }
61e5d8ed 561
b708e7ce 562 if (*rvalue != '/') {
e8e581bf
ZJS
563 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
564 "Executable path is not absolute, ignoring: %s", rvalue);
c0b34696 565 return 0;
6c666e26 566 }
034c6ed7 567
61e5d8ed
LP
568 k = 0;
569 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
641906e9 570 if (strneq(w, ";", MAX(l, 1U)))
61e5d8ed 571 break;
034c6ed7 572
61e5d8ed
LP
573 k++;
574 }
034c6ed7 575
7f110ff9
LP
576 n = new(char*, k + !honour_argv0);
577 if (!n)
74051b9b 578 return log_oom();
61e5d8ed
LP
579
580 k = 0;
61e5d8ed 581 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
641906e9 582 if (strneq(w, ";", MAX(l, 1U)))
61e5d8ed 583 break;
641906e9 584 else if (strneq(w, "\\;", MAX(l, 1U)))
7e1a84f5 585 w ++;
61e5d8ed 586
b708e7ce
LP
587 if (honour_argv0 && w == rvalue) {
588 assert(!path);
7f110ff9
LP
589
590 path = strndup(w, l);
591 if (!path) {
74051b9b 592 r = log_oom();
7f110ff9
LP
593 goto fail;
594 }
595
596 if (!utf8_is_valid(path)) {
b5d74213 597 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
7f110ff9 598 r = 0;
61e5d8ed 599 goto fail;
7f110ff9
LP
600 }
601
61e5d8ed 602 } else {
7f110ff9
LP
603 char *c;
604
605 c = n[k++] = cunescape_length(w, l);
606 if (!c) {
74051b9b 607 r = log_oom();
61e5d8ed 608 goto fail;
7f110ff9
LP
609 }
610
611 if (!utf8_is_valid(c)) {
b5d74213 612 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
7f110ff9
LP
613 r = 0;
614 goto fail;
615 }
61e5d8ed
LP
616 }
617 }
618
619 n[k] = NULL;
620
621 if (!n[0]) {
e8e581bf
ZJS
622 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
623 "Invalid command line, ignoring: %s", rvalue);
7f110ff9
LP
624 r = 0;
625 goto fail;
61e5d8ed
LP
626 }
627
7f110ff9
LP
628 if (!path) {
629 path = strdup(n[0]);
630 if (!path) {
74051b9b 631 r = log_oom();
61e5d8ed 632 goto fail;
7f110ff9
LP
633 }
634 }
6c666e26 635
61e5d8ed 636 assert(path_is_absolute(path));
6c666e26 637
7f110ff9
LP
638 nce = new0(ExecCommand, 1);
639 if (!nce) {
74051b9b 640 r = log_oom();
61e5d8ed 641 goto fail;
7f110ff9 642 }
61e5d8ed
LP
643
644 nce->argv = n;
645 nce->path = path;
b708e7ce 646 nce->ignore = ignore;
034c6ed7 647
61e5d8ed 648 path_kill_slashes(nce->path);
034c6ed7 649
61e5d8ed 650 exec_command_append_list(e, nce);
01f78473 651
61e5d8ed
LP
652 rvalue = state;
653 }
034c6ed7
LP
654
655 return 0;
656
657fail:
6c666e26
LP
658 n[k] = NULL;
659 strv_free(n);
660 free(path);
034c6ed7
LP
661 free(nce);
662
7f110ff9 663 return r;
034c6ed7
LP
664}
665
f975e971
LP
666DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
667DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
034c6ed7 668
e8e581bf
ZJS
669int config_parse_socket_bindtodevice(const char* unit,
670 const char *filename,
671 unsigned line,
672 const char *section,
71a61510 673 unsigned section_line,
e8e581bf
ZJS
674 const char *lvalue,
675 int ltype,
676 const char *rvalue,
677 void *data,
678 void *userdata) {
acbb0225
LP
679
680 Socket *s = data;
681 char *n;
682
683 assert(filename);
684 assert(lvalue);
685 assert(rvalue);
686 assert(data);
687
688 if (rvalue[0] && !streq(rvalue, "*")) {
74051b9b
LP
689 n = strdup(rvalue);
690 if (!n)
691 return log_oom();
acbb0225
LP
692 } else
693 n = NULL;
694
695 free(s->bind_to_device);
696 s->bind_to_device = n;
697
698 return 0;
699}
700
f975e971
LP
701DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
702DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
87f0e418 703
e8e581bf
ZJS
704int config_parse_exec_io_class(const char *unit,
705 const char *filename,
706 unsigned line,
707 const char *section,
71a61510 708 unsigned section_line,
e8e581bf
ZJS
709 const char *lvalue,
710 int ltype,
711 const char *rvalue,
712 void *data,
713 void *userdata) {
94f04347
LP
714
715 ExecContext *c = data;
716 int x;
717
718 assert(filename);
719 assert(lvalue);
720 assert(rvalue);
721 assert(data);
722
f8b69d1d
MS
723 x = ioprio_class_from_string(rvalue);
724 if (x < 0) {
e8e581bf
ZJS
725 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
726 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
c0b34696 727 return 0;
0d87eb42 728 }
94f04347
LP
729
730 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
731 c->ioprio_set = true;
732
733 return 0;
734}
735
e8e581bf
ZJS
736int config_parse_exec_io_priority(const char *unit,
737 const char *filename,
738 unsigned line,
739 const char *section,
71a61510 740 unsigned section_line,
e8e581bf
ZJS
741 const char *lvalue,
742 int ltype,
743 const char *rvalue,
744 void *data,
745 void *userdata) {
94f04347
LP
746
747 ExecContext *c = data;
e8e581bf 748 int i, r;
94f04347
LP
749
750 assert(filename);
751 assert(lvalue);
752 assert(rvalue);
753 assert(data);
754
e8e581bf
ZJS
755 r = safe_atoi(rvalue, &i);
756 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
757 log_syntax(unit, LOG_ERR, filename, line, -r,
758 "Failed to parse IO priority, ignoring: %s", rvalue);
c0b34696 759 return 0;
071830ff
LP
760 }
761
94f04347
LP
762 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
763 c->ioprio_set = true;
764
071830ff
LP
765 return 0;
766}
767
e8e581bf
ZJS
768int config_parse_exec_cpu_sched_policy(const char *unit,
769 const char *filename,
770 unsigned line,
771 const char *section,
71a61510 772 unsigned section_line,
e8e581bf
ZJS
773 const char *lvalue,
774 int ltype,
775 const char *rvalue,
776 void *data,
777 void *userdata) {
9eba9da4 778
94f04347
LP
779
780 ExecContext *c = data;
781 int x;
782
783 assert(filename);
784 assert(lvalue);
785 assert(rvalue);
786 assert(data);
787
f8b69d1d
MS
788 x = sched_policy_from_string(rvalue);
789 if (x < 0) {
e8e581bf
ZJS
790 log_syntax(unit, LOG_ERR, filename, line, -x,
791 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 792 return 0;
0d87eb42 793 }
94f04347
LP
794
795 c->cpu_sched_policy = x;
bb112710
HHPF
796 /* Moving to or from real-time policy? We need to adjust the priority */
797 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
94f04347
LP
798 c->cpu_sched_set = true;
799
800 return 0;
801}
802
e8e581bf
ZJS
803int config_parse_exec_cpu_sched_prio(const char *unit,
804 const char *filename,
805 unsigned line,
806 const char *section,
71a61510 807 unsigned section_line,
e8e581bf
ZJS
808 const char *lvalue,
809 int ltype,
810 const char *rvalue,
811 void *data,
812 void *userdata) {
9eba9da4
LP
813
814 ExecContext *c = data;
e8e581bf 815 int i, min, max, r;
9eba9da4
LP
816
817 assert(filename);
818 assert(lvalue);
819 assert(rvalue);
820 assert(data);
821
e8e581bf
ZJS
822 r = safe_atoi(rvalue, &i);
823 if (r < 0) {
824 log_syntax(unit, LOG_ERR, filename, line, -r,
825 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
c0b34696 826 return 0;
94f04347 827 }
9eba9da4 828
bb112710
HHPF
829 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
830 min = sched_get_priority_min(c->cpu_sched_policy);
831 max = sched_get_priority_max(c->cpu_sched_policy);
832
833 if (i < min || i > max) {
e8e581bf
ZJS
834 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
835 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
bb112710
HHPF
836 return 0;
837 }
838
94f04347
LP
839 c->cpu_sched_priority = i;
840 c->cpu_sched_set = true;
841
842 return 0;
843}
844
e8e581bf
ZJS
845int config_parse_exec_cpu_affinity(const char *unit,
846 const char *filename,
847 unsigned line,
848 const char *section,
71a61510 849 unsigned section_line,
e8e581bf
ZJS
850 const char *lvalue,
851 int ltype,
852 const char *rvalue,
853 void *data,
854 void *userdata) {
94f04347
LP
855
856 ExecContext *c = data;
857 char *w;
858 size_t l;
859 char *state;
860
861 assert(filename);
862 assert(lvalue);
863 assert(rvalue);
864 assert(data);
865
74051b9b
LP
866 if (isempty(rvalue)) {
867 /* An empty assignment resets the CPU list */
868 if (c->cpuset)
869 CPU_FREE(c->cpuset);
870 c->cpuset = NULL;
871 return 0;
872 }
873
f60f22df 874 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 875 _cleanup_free_ char *t = NULL;
94f04347
LP
876 int r;
877 unsigned cpu;
878
c040936b
ZJS
879 t = strndup(w, l);
880 if (!t)
74051b9b 881 return log_oom();
94f04347 882
487393e9 883 r = safe_atou(t, &cpu);
487393e9 884
c040936b
ZJS
885 if (!c->cpuset) {
886 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
887 if (!c->cpuset)
74051b9b 888 return log_oom();
c040936b 889 }
82c121a4 890
82c121a4 891 if (r < 0 || cpu >= c->cpuset_ncpus) {
e8e581bf
ZJS
892 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
893 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
c0b34696 894 return 0;
9eba9da4 895 }
94f04347 896
82c121a4 897 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
9eba9da4
LP
898 }
899
94f04347
LP
900 return 0;
901}
902
e8e581bf
ZJS
903int config_parse_exec_capabilities(const char *unit,
904 const char *filename,
905 unsigned line,
906 const char *section,
71a61510 907 unsigned section_line,
e8e581bf
ZJS
908 const char *lvalue,
909 int ltype,
910 const char *rvalue,
911 void *data,
912 void *userdata) {
94f04347
LP
913
914 ExecContext *c = data;
915 cap_t cap;
916
917 assert(filename);
918 assert(lvalue);
919 assert(rvalue);
920 assert(data);
921
74051b9b
LP
922 cap = cap_from_text(rvalue);
923 if (!cap) {
e8e581bf
ZJS
924 log_syntax(unit, LOG_ERR, filename, line, errno,
925 "Failed to parse capabilities, ignoring: %s", rvalue);
c0b34696 926 return 0;
94f04347
LP
927 }
928
929 if (c->capabilities)
930 cap_free(c->capabilities);
931 c->capabilities = cap;
932
933 return 0;
934}
935
e8e581bf
ZJS
936int config_parse_exec_secure_bits(const char *unit,
937 const char *filename,
938 unsigned line,
939 const char *section,
71a61510 940 unsigned section_line,
e8e581bf
ZJS
941 const char *lvalue,
942 int ltype,
943 const char *rvalue,
944 void *data,
945 void *userdata) {
94f04347
LP
946
947 ExecContext *c = data;
948 char *w;
949 size_t l;
950 char *state;
951
952 assert(filename);
953 assert(lvalue);
954 assert(rvalue);
955 assert(data);
956
74051b9b
LP
957 if (isempty(rvalue)) {
958 /* An empty assignment resets the field */
959 c->secure_bits = 0;
960 return 0;
961 }
962
f60f22df 963 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94f04347 964 if (first_word(w, "keep-caps"))
cbb21cca 965 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
94f04347 966 else if (first_word(w, "keep-caps-locked"))
cbb21cca 967 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
94f04347 968 else if (first_word(w, "no-setuid-fixup"))
cbb21cca 969 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
94f04347 970 else if (first_word(w, "no-setuid-fixup-locked"))
cbb21cca 971 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
94f04347 972 else if (first_word(w, "noroot"))
cbb21cca 973 c->secure_bits |= 1<<SECURE_NOROOT;
94f04347 974 else if (first_word(w, "noroot-locked"))
cbb21cca 975 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
9eba9da4 976 else {
e8e581bf
ZJS
977 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
978 "Failed to parse secure bits, ignoring: %s", rvalue);
c0b34696 979 return 0;
9eba9da4
LP
980 }
981 }
982
94f04347
LP
983 return 0;
984}
985
e8e581bf
ZJS
986int config_parse_bounding_set(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 996
ec8927ca 997 uint64_t *capability_bounding_set_drop = data;
94f04347
LP
998 char *w;
999 size_t l;
1000 char *state;
260abb78
LP
1001 bool invert = false;
1002 uint64_t sum = 0;
94f04347
LP
1003
1004 assert(filename);
1005 assert(lvalue);
1006 assert(rvalue);
1007 assert(data);
1008
260abb78
LP
1009 if (rvalue[0] == '~') {
1010 invert = true;
1011 rvalue++;
1012 }
1013
1014 /* Note that we store this inverted internally, since the
1015 * kernel wants it like this. But we actually expose it
1016 * non-inverted everywhere to have a fully normalized
1017 * interface. */
1018
f60f22df 1019 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 1020 _cleanup_free_ char *t = NULL;
94f04347
LP
1021 int r;
1022 cap_value_t cap;
1023
ec8927ca
LP
1024 t = strndup(w, l);
1025 if (!t)
74051b9b 1026 return log_oom();
94f04347
LP
1027
1028 r = cap_from_name(t, &cap);
94f04347 1029 if (r < 0) {
e8e581bf
ZJS
1030 log_syntax(unit, LOG_ERR, filename, line, errno,
1031 "Failed to parse capability in bounding set, ignoring: %s", t);
8351ceae 1032 continue;
94f04347
LP
1033 }
1034
260abb78 1035 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
94f04347 1036 }
9eba9da4 1037
260abb78 1038 if (invert)
ec8927ca 1039 *capability_bounding_set_drop |= sum;
260abb78 1040 else
ec8927ca 1041 *capability_bounding_set_drop |= ~sum;
260abb78 1042
9eba9da4
LP
1043 return 0;
1044}
1045
e8e581bf
ZJS
1046int config_parse_limit(const char *unit,
1047 const char *filename,
1048 unsigned line,
1049 const char *section,
71a61510 1050 unsigned section_line,
e8e581bf
ZJS
1051 const char *lvalue,
1052 int ltype,
1053 const char *rvalue,
1054 void *data,
1055 void *userdata) {
94f04347
LP
1056
1057 struct rlimit **rl = data;
1058 unsigned long long u;
94f04347
LP
1059
1060 assert(filename);
1061 assert(lvalue);
1062 assert(rvalue);
1063 assert(data);
1064
f975e971
LP
1065 rl += ltype;
1066
3d57c6ab
LP
1067 if (streq(rvalue, "infinity"))
1068 u = (unsigned long long) RLIM_INFINITY;
e8e581bf
ZJS
1069 else {
1070 int r;
1071
1072 r = safe_atollu(rvalue, &u);
1073 if (r < 0) {
1074 log_syntax(unit, LOG_ERR, filename, line, -r,
1075 "Failed to parse resource value, ignoring: %s", rvalue);
1076 return 0;
1077 }
94f04347
LP
1078 }
1079
74051b9b
LP
1080 if (!*rl) {
1081 *rl = new(struct rlimit, 1);
1082 if (!*rl)
1083 return log_oom();
1084 }
9eba9da4 1085
94f04347 1086 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
9eba9da4
LP
1087 return 0;
1088}
1089
07459bb6 1090#ifdef HAVE_SYSV_COMPAT
e8e581bf
ZJS
1091int config_parse_sysv_priority(const char *unit,
1092 const char *filename,
1093 unsigned line,
1094 const char *section,
71a61510 1095 unsigned section_line,
e8e581bf
ZJS
1096 const char *lvalue,
1097 int ltype,
1098 const char *rvalue,
1099 void *data,
1100 void *userdata) {
a9a1e00a
LP
1101
1102 int *priority = data;
e8e581bf 1103 int i, r;
a9a1e00a
LP
1104
1105 assert(filename);
1106 assert(lvalue);
1107 assert(rvalue);
1108 assert(data);
1109
e8e581bf
ZJS
1110 r = safe_atoi(rvalue, &i);
1111 if (r < 0 || i < 0) {
1112 log_syntax(unit, LOG_ERR, filename, line, -r,
1113 "Failed to parse SysV start priority, ignoring: %s", rvalue);
c0b34696 1114 return 0;
a9a1e00a
LP
1115 }
1116
1117 *priority = (int) i;
1118 return 0;
1119}
07459bb6 1120#endif
a9a1e00a 1121
f975e971 1122DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
50159e6a 1123
e8e581bf
ZJS
1124int config_parse_kill_signal(const char *unit,
1125 const char *filename,
1126 unsigned line,
1127 const char *section,
71a61510 1128 unsigned section_line,
e8e581bf
ZJS
1129 const char *lvalue,
1130 int ltype,
1131 const char *rvalue,
1132 void *data,
1133 void *userdata) {
2e22afe9
LP
1134
1135 int *sig = data;
1136 int r;
1137
1138 assert(filename);
1139 assert(lvalue);
1140 assert(rvalue);
1141 assert(sig);
1142
74051b9b
LP
1143 r = signal_from_string_try_harder(rvalue);
1144 if (r <= 0) {
e8e581bf
ZJS
1145 log_syntax(unit, LOG_ERR, filename, line, -r,
1146 "Failed to parse kill signal, ignoring: %s", rvalue);
c0b34696 1147 return 0;
2e22afe9
LP
1148 }
1149
1150 *sig = r;
1151 return 0;
1152}
1153
e8e581bf
ZJS
1154int config_parse_exec_mount_flags(const char *unit,
1155 const char *filename,
1156 unsigned line,
1157 const char *section,
71a61510 1158 unsigned section_line,
e8e581bf
ZJS
1159 const char *lvalue,
1160 int ltype,
1161 const char *rvalue,
1162 void *data,
1163 void *userdata) {
15ae422b
LP
1164
1165 ExecContext *c = data;
1166 char *w;
1167 size_t l;
1168 char *state;
1169 unsigned long flags = 0;
1170
1171 assert(filename);
1172 assert(lvalue);
1173 assert(rvalue);
1174 assert(data);
1175
ac97e2c5 1176 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
7fd1b19b 1177 _cleanup_free_ char *t;
ac97e2c5
ZJS
1178
1179 t = strndup(w, l);
1180 if (!t)
74051b9b 1181 return log_oom();
ac97e2c5
ZJS
1182
1183 if (streq(t, "shared"))
c2c13f2d 1184 flags = MS_SHARED;
ac97e2c5 1185 else if (streq(t, "slave"))
c2c13f2d 1186 flags = MS_SLAVE;
ac97e2c5 1187 else if (streq(w, "private"))
c2c13f2d 1188 flags = MS_PRIVATE;
15ae422b 1189 else {
c2c13f2d 1190 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
c0b34696 1191 return 0;
15ae422b
LP
1192 }
1193 }
1194
1195 c->mount_flags = flags;
1196 return 0;
1197}
1198
5f8640fb
LP
1199int config_parse_exec_selinux_context(
1200 const char *unit,
1201 const char *filename,
1202 unsigned line,
1203 const char *section,
1204 unsigned section_line,
1205 const char *lvalue,
1206 int ltype,
1207 const char *rvalue,
1208 void *data,
1209 void *userdata) {
1210
1211 ExecContext *c = data;
1212 Unit *u = userdata;
1213 bool ignore;
1214 char *k;
1215 int r;
1216
1217 assert(filename);
1218 assert(lvalue);
1219 assert(rvalue);
1220 assert(data);
1221
1222 if (isempty(rvalue)) {
1223 free(c->selinux_context);
1224 c->selinux_context = NULL;
1225 c->selinux_context_ignore = false;
1226 return 0;
1227 }
1228
1229 if (rvalue[0] == '-') {
1230 ignore = true;
1231 rvalue++;
1232 } else
1233 ignore = false;
1234
1235 r = unit_name_printf(u, rvalue, &k);
1236 if (r < 0) {
1237 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1238 return 0;
1239 }
1240
1241 free(c->selinux_context);
1242 c->selinux_context = k;
1243 c->selinux_context_ignore = ignore;
1244
1245 return 0;
1246}
1247
eef65bf3
MS
1248int config_parse_exec_apparmor_profile(
1249 const char *unit,
1250 const char *filename,
1251 unsigned line,
1252 const char *section,
1253 unsigned section_line,
1254 const char *lvalue,
1255 int ltype,
1256 const char *rvalue,
1257 void *data,
1258 void *userdata) {
1259
1260 ExecContext *c = data;
1261 Unit *u = userdata;
1262 bool ignore;
1263 char *k;
1264 int r;
1265
1266 assert(filename);
1267 assert(lvalue);
1268 assert(rvalue);
1269 assert(data);
1270
1271 if (isempty(rvalue)) {
1272 free(c->apparmor_profile);
1273 c->apparmor_profile = NULL;
1274 c->apparmor_profile_ignore = false;
1275 return 0;
1276 }
1277
1278 if (rvalue[0] == '-') {
1279 ignore = true;
1280 rvalue++;
1281 } else
1282 ignore = false;
1283
1284 r = unit_name_printf(u, rvalue, &k);
1285 if (r < 0) {
1286 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1287 return 0;
1288 }
1289
1290 free(c->apparmor_profile);
1291 c->apparmor_profile = k;
1292 c->apparmor_profile_ignore = ignore;
1293
1294 return 0;
1295}
1296
e8e581bf
ZJS
1297int config_parse_timer(const char *unit,
1298 const char *filename,
1299 unsigned line,
1300 const char *section,
71a61510 1301 unsigned section_line,
e8e581bf
ZJS
1302 const char *lvalue,
1303 int ltype,
1304 const char *rvalue,
1305 void *data,
1306 void *userdata) {
871d7de4
LP
1307
1308 Timer *t = data;
36697dc0 1309 usec_t u = 0;
871d7de4
LP
1310 TimerValue *v;
1311 TimerBase b;
36697dc0 1312 CalendarSpec *c = NULL;
871d7de4
LP
1313
1314 assert(filename);
1315 assert(lvalue);
1316 assert(rvalue);
1317 assert(data);
1318
74051b9b
LP
1319 if (isempty(rvalue)) {
1320 /* Empty assignment resets list */
1321 timer_free_values(t);
1322 return 0;
1323 }
1324
36697dc0
LP
1325 b = timer_base_from_string(lvalue);
1326 if (b < 0) {
e8e581bf
ZJS
1327 log_syntax(unit, LOG_ERR, filename, line, -b,
1328 "Failed to parse timer base, ignoring: %s", lvalue);
c0b34696 1329 return 0;
871d7de4
LP
1330 }
1331
36697dc0
LP
1332 if (b == TIMER_CALENDAR) {
1333 if (calendar_spec_from_string(rvalue, &c) < 0) {
e8e581bf
ZJS
1334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1335 "Failed to parse calendar specification, ignoring: %s",
1336 rvalue);
36697dc0
LP
1337 return 0;
1338 }
36697dc0 1339 } else {
7f602784 1340 if (parse_sec(rvalue, &u) < 0) {
e8e581bf
ZJS
1341 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1342 "Failed to parse timer value, ignoring: %s",
1343 rvalue);
36697dc0
LP
1344 return 0;
1345 }
871d7de4
LP
1346 }
1347
36697dc0
LP
1348 v = new0(TimerValue, 1);
1349 if (!v)
74051b9b 1350 return log_oom();
871d7de4
LP
1351
1352 v->base = b;
1353 v->value = u;
36697dc0 1354 v->calendar_spec = c;
871d7de4 1355
71fda00f 1356 LIST_PREPEND(value, t->values, v);
871d7de4
LP
1357
1358 return 0;
1359}
1360
3ecaa09b
LP
1361int config_parse_trigger_unit(
1362 const char *unit,
1363 const char *filename,
1364 unsigned line,
1365 const char *section,
71a61510 1366 unsigned section_line,
3ecaa09b
LP
1367 const char *lvalue,
1368 int ltype,
1369 const char *rvalue,
1370 void *data,
1371 void *userdata) {
871d7de4 1372
74051b9b 1373 _cleanup_free_ char *p = NULL;
3ecaa09b
LP
1374 Unit *u = data;
1375 UnitType type;
1376 int r;
398ef8ba
LP
1377
1378 assert(filename);
1379 assert(lvalue);
1380 assert(rvalue);
1381 assert(data);
1382
3ecaa09b
LP
1383 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1384 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1385 "Multiple units to trigger specified, ignoring: %s", rvalue);
1386 return 0;
1387 }
871d7de4 1388
19f6d710
LP
1389 r = unit_name_printf(u, rvalue, &p);
1390 if (r < 0)
1391 log_syntax(unit, LOG_ERR, filename, line, -r,
1392 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
74051b9b 1393
19f6d710 1394 type = unit_name_to_type(p ?: rvalue);
3ecaa09b 1395 if (type < 0) {
e8e581bf 1396 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3ecaa09b 1397 "Unit type not valid, ignoring: %s", rvalue);
c0b34696 1398 return 0;
871d7de4
LP
1399 }
1400
3ecaa09b
LP
1401 if (type == u->type) {
1402 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1403 "Trigger cannot be of same type, ignoring: %s", rvalue);
1404 return 0;
1405 }
1406
19f6d710 1407 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
57020a3a 1408 if (r < 0) {
e8e581bf 1409 log_syntax(unit, LOG_ERR, filename, line, -r,
19f6d710 1410 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
c0b34696 1411 return 0;
871d7de4
LP
1412 }
1413
1414 return 0;
1415}
1416
e8e581bf
ZJS
1417int config_parse_path_spec(const char *unit,
1418 const char *filename,
1419 unsigned line,
1420 const char *section,
71a61510 1421 unsigned section_line,
e8e581bf
ZJS
1422 const char *lvalue,
1423 int ltype,
1424 const char *rvalue,
1425 void *data,
1426 void *userdata) {
01f78473
LP
1427
1428 Path *p = data;
1429 PathSpec *s;
1430 PathType b;
7fd1b19b 1431 _cleanup_free_ char *k = NULL;
19f6d710 1432 int r;
01f78473
LP
1433
1434 assert(filename);
1435 assert(lvalue);
1436 assert(rvalue);
1437 assert(data);
1438
74051b9b
LP
1439 if (isempty(rvalue)) {
1440 /* Empty assignment clears list */
1441 path_free_specs(p);
1442 return 0;
1443 }
1444
93e4c84b
LP
1445 b = path_type_from_string(lvalue);
1446 if (b < 0) {
e8e581bf
ZJS
1447 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1448 "Failed to parse path type, ignoring: %s", lvalue);
c0b34696 1449 return 0;
01f78473
LP
1450 }
1451
19f6d710
LP
1452 r = unit_full_printf(UNIT(p), rvalue, &k);
1453 if (r < 0) {
487060c2
LP
1454 k = strdup(rvalue);
1455 if (!k)
1456 return log_oom();
1457 else
19f6d710 1458 log_syntax(unit, LOG_ERR, filename, line, -r,
e8e581bf
ZJS
1459 "Failed to resolve unit specifiers on %s. Ignoring.",
1460 rvalue);
487060c2 1461 }
93e4c84b
LP
1462
1463 if (!path_is_absolute(k)) {
e8e581bf
ZJS
1464 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1465 "Path is not absolute, ignoring: %s", k);
c0b34696 1466 return 0;
01f78473
LP
1467 }
1468
93e4c84b 1469 s = new0(PathSpec, 1);
543295ad 1470 if (!s)
93e4c84b 1471 return log_oom();
01f78473 1472
718db961 1473 s->unit = UNIT(p);
93e4c84b 1474 s->path = path_kill_slashes(k);
543295ad 1475 k = NULL;
01f78473
LP
1476 s->type = b;
1477 s->inotify_fd = -1;
1478
71fda00f 1479 LIST_PREPEND(spec, p->specs, s);
01f78473
LP
1480
1481 return 0;
1482}
1483
e8e581bf
ZJS
1484int config_parse_socket_service(const char *unit,
1485 const char *filename,
1486 unsigned line,
1487 const char *section,
71a61510 1488 unsigned section_line,
e8e581bf
ZJS
1489 const char *lvalue,
1490 int ltype,
1491 const char *rvalue,
1492 void *data,
1493 void *userdata) {
d9ff321a 1494
718db961 1495 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d9ff321a
LP
1496 Socket *s = data;
1497 int r;
4ff77f66 1498 Unit *x;
74051b9b 1499 _cleanup_free_ char *p = NULL;
d9ff321a
LP
1500
1501 assert(filename);
1502 assert(lvalue);
1503 assert(rvalue);
1504 assert(data);
1505
19f6d710 1506 r = unit_name_printf(UNIT(s), rvalue, &p);
613b411c 1507 if (r < 0) {
718db961 1508 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
613b411c
LP
1509 return 0;
1510 }
74051b9b 1511
613b411c 1512 if (!endswith(p, ".service")) {
718db961 1513 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
d9ff321a
LP
1514 return 0;
1515 }
1516
613b411c 1517 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
4ff77f66 1518 if (r < 0) {
718db961 1519 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
d9ff321a
LP
1520 return 0;
1521 }
1522
4ff77f66
LP
1523 unit_ref_set(&s->service, x);
1524
d9ff321a
LP
1525 return 0;
1526}
1527
e8e581bf
ZJS
1528int config_parse_service_sockets(const char *unit,
1529 const char *filename,
1530 unsigned line,
1531 const char *section,
71a61510 1532 unsigned section_line,
e8e581bf
ZJS
1533 const char *lvalue,
1534 int ltype,
1535 const char *rvalue,
1536 void *data,
1537 void *userdata) {
f976f3f6
LP
1538
1539 Service *s = data;
1540 int r;
f976f3f6
LP
1541 char *state, *w;
1542 size_t l;
1543
1544 assert(filename);
1545 assert(lvalue);
1546 assert(rvalue);
1547 assert(data);
1548
f976f3f6 1549 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 1550 _cleanup_free_ char *t = NULL, *k = NULL;
f976f3f6 1551
57020a3a
LP
1552 t = strndup(w, l);
1553 if (!t)
74051b9b 1554 return log_oom();
f976f3f6 1555
19f6d710
LP
1556 r = unit_name_printf(UNIT(s), t, &k);
1557 if (r < 0)
1558 log_syntax(unit, LOG_ERR, filename, line, -r,
1559 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
57020a3a 1560
19f6d710 1561 if (!endswith(k ?: t, ".socket")) {
e8e581bf 1562 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
19f6d710 1563 "Unit must be of type socket, ignoring: %s", k ?: t);
f976f3f6
LP
1564 continue;
1565 }
1566
19f6d710 1567 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
57020a3a 1568 if (r < 0)
e8e581bf
ZJS
1569 log_syntax(unit, LOG_ERR, filename, line, -r,
1570 "Failed to add dependency on %s, ignoring: %s",
19f6d710 1571 k ?: t, strerror(-r));
f976f3f6 1572
19f6d710 1573 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
57020a3a 1574 if (r < 0)
f976f3f6
LP
1575 return r;
1576 }
1577
1578 return 0;
1579}
1580
e8e581bf
ZJS
1581int config_parse_service_timeout(const char *unit,
1582 const char *filename,
1583 unsigned line,
1584 const char *section,
71a61510 1585 unsigned section_line,
e8e581bf
ZJS
1586 const char *lvalue,
1587 int ltype,
1588 const char *rvalue,
1589 void *data,
1590 void *userdata) {
98709151
LN
1591
1592 Service *s = userdata;
1593 int r;
1594
1595 assert(filename);
1596 assert(lvalue);
1597 assert(rvalue);
1598 assert(s);
1599
71a61510 1600 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 1601 rvalue, data, userdata);
74051b9b 1602 if (r < 0)
d568a335 1603 return r;
98709151 1604
d568a335
MS
1605 if (streq(lvalue, "TimeoutSec")) {
1606 s->start_timeout_defined = true;
1607 s->timeout_stop_usec = s->timeout_start_usec;
1608 } else if (streq(lvalue, "TimeoutStartSec"))
1609 s->start_timeout_defined = true;
1610
1611 return 0;
98709151
LN
1612}
1613
e821075a
LP
1614int config_parse_busname_service(
1615 const char *unit,
1616 const char *filename,
1617 unsigned line,
1618 const char *section,
1619 unsigned section_line,
1620 const char *lvalue,
1621 int ltype,
1622 const char *rvalue,
1623 void *data,
1624 void *userdata) {
1625
1626 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1627 BusName *n = data;
1628 int r;
1629 Unit *x;
1630 _cleanup_free_ char *p = NULL;
1631
1632 assert(filename);
1633 assert(lvalue);
1634 assert(rvalue);
1635 assert(data);
1636
1637 r = unit_name_printf(UNIT(n), rvalue, &p);
1638 if (r < 0) {
1639 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1640 return 0;
1641 }
1642
1643 if (!endswith(p, ".service")) {
1644 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1645 return 0;
1646 }
1647
1648 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1649 if (r < 0) {
1650 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1651 return 0;
1652 }
1653
1654 unit_ref_set(&n->service, x);
1655
1656 return 0;
1657}
1658
a4152e3f
LP
1659DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
1660
54d76c92
DM
1661int config_parse_bus_policy(
1662 const char *unit,
1663 const char *filename,
1664 unsigned line,
1665 const char *section,
1666 unsigned section_line,
1667 const char *lvalue,
1668 int ltype,
1669 const char *rvalue,
1670 void *data,
1671 void *userdata) {
1672
1673 _cleanup_free_ BusNamePolicy *p = NULL;
1674 _cleanup_free_ char *id_str = NULL;
1675 BusName *busname = data;
1676 char *access_str;
54d76c92
DM
1677
1678 assert(filename);
1679 assert(lvalue);
1680 assert(rvalue);
1681 assert(data);
1682
1683 p = new0(BusNamePolicy, 1);
1684 if (!p)
1685 return log_oom();
1686
1687 if (streq(lvalue, "AllowUser"))
1688 p->type = BUSNAME_POLICY_TYPE_USER;
1689 else if (streq(lvalue, "AllowGroup"))
1690 p->type = BUSNAME_POLICY_TYPE_GROUP;
54d76c92
DM
1691 else
1692 assert_not_reached("Unknown lvalue");
1693
1694 id_str = strdup(rvalue);
1695 if (!id_str)
1696 return log_oom();
1697
a4152e3f
LP
1698 access_str = strpbrk(id_str, WHITESPACE);
1699 if (!access_str) {
1700 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1701 return 0;
54d76c92
DM
1702 }
1703
a4152e3f
LP
1704 *access_str = '\0';
1705 access_str++;
1706 access_str += strspn(access_str, WHITESPACE);
1707
54d76c92
DM
1708 p->access = busname_policy_access_from_string(access_str);
1709 if (p->access < 0) {
1710 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1711 return 0;
1712 }
1713
a4152e3f
LP
1714 p->name = id_str;
1715 id_str = NULL;
1716
54d76c92
DM
1717 LIST_PREPEND(policy, busname->policy, p);
1718 p = NULL;
1719
1720 return 0;
1721}
1722
e8e581bf
ZJS
1723int config_parse_unit_env_file(const char *unit,
1724 const char *filename,
1725 unsigned line,
1726 const char *section,
71a61510 1727 unsigned section_line,
e8e581bf
ZJS
1728 const char *lvalue,
1729 int ltype,
1730 const char *rvalue,
1731 void *data,
1732 void *userdata) {
ddb26e18 1733
853b8397 1734 char ***env = data;
8fef7659 1735 Unit *u = userdata;
19f6d710
LP
1736 _cleanup_free_ char *n = NULL;
1737 const char *s;
853b8397 1738 int r;
ddb26e18
LP
1739
1740 assert(filename);
1741 assert(lvalue);
1742 assert(rvalue);
1743 assert(data);
1744
74051b9b
LP
1745 if (isempty(rvalue)) {
1746 /* Empty assignment frees the list */
74051b9b
LP
1747 strv_free(*env);
1748 *env = NULL;
1749 return 0;
1750 }
1751
19f6d710
LP
1752 r = unit_full_printf(u, rvalue, &n);
1753 if (r < 0)
1754 log_syntax(unit, LOG_ERR, filename, line, r,
1755 "Failed to resolve specifiers, ignoring: %s", rvalue);
8fef7659 1756
19f6d710 1757 s = n ?: rvalue;
8fef7659 1758 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
e8e581bf
ZJS
1759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1760 "Path '%s' is not absolute, ignoring.", s);
afe4bfe2
LP
1761 return 0;
1762 }
1763
853b8397
LP
1764 r = strv_extend(env, s);
1765 if (r < 0)
1766 return log_oom();
1767
1768 return 0;
1769}
1770
e8e581bf
ZJS
1771int config_parse_environ(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) {
853b8397
LP
1781
1782 Unit *u = userdata;
1783 char*** env = data, *w, *state;
1784 size_t l;
1785 _cleanup_free_ char *k = NULL;
19f6d710 1786 int r;
853b8397
LP
1787
1788 assert(filename);
1789 assert(lvalue);
1790 assert(rvalue);
97d0e5f8 1791 assert(data);
853b8397
LP
1792
1793 if (isempty(rvalue)) {
1794 /* Empty assignment resets the list */
1795 strv_free(*env);
1796 *env = NULL;
1797 return 0;
1798 }
1799
19f6d710
LP
1800 if (u) {
1801 r = unit_full_printf(u, rvalue, &k);
1802 if (r < 0)
1803 log_syntax(unit, LOG_ERR, filename, line, -r,
1804 "Failed to resolve specifiers, ignoring: %s", rvalue);
1805 }
97d0e5f8 1806
19f6d710
LP
1807 if (!k)
1808 k = strdup(rvalue);
8fef7659 1809 if (!k)
74051b9b 1810 return log_oom();
ddb26e18 1811
853b8397
LP
1812 FOREACH_WORD_QUOTED(w, l, k, state) {
1813 _cleanup_free_ char *n;
1814 char **x;
1815
1816 n = cunescape_length(w, l);
1817 if (!n)
1818 return log_oom();
1819
1820 if (!env_assignment_is_valid(n)) {
e8e581bf
ZJS
1821 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1822 "Invalid environment assignment, ignoring: %s", rvalue);
853b8397
LP
1823 continue;
1824 }
1825
1826 x = strv_env_set(*env, n);
1827 if (!x)
1828 return log_oom();
1829
1830 strv_free(*env);
1831 *env = x;
1832 }
ddb26e18 1833
8c7be95e 1834 return 0;
ddb26e18
LP
1835}
1836
e8e581bf
ZJS
1837int config_parse_ip_tos(const char *unit,
1838 const char *filename,
1839 unsigned line,
1840 const char *section,
71a61510 1841 unsigned section_line,
e8e581bf
ZJS
1842 const char *lvalue,
1843 int ltype,
1844 const char *rvalue,
1845 void *data,
1846 void *userdata) {
4fd5948e
LP
1847
1848 int *ip_tos = data, x;
4fd5948e
LP
1849
1850 assert(filename);
1851 assert(lvalue);
1852 assert(rvalue);
1853 assert(data);
1854
f8b69d1d
MS
1855 x = ip_tos_from_string(rvalue);
1856 if (x < 0) {
e8e581bf
ZJS
1857 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1858 "Failed to parse IP TOS value, ignoring: %s", rvalue);
f8b69d1d
MS
1859 return 0;
1860 }
4fd5948e
LP
1861
1862 *ip_tos = x;
1863 return 0;
1864}
1865
e8e581bf
ZJS
1866int config_parse_unit_condition_path(const char *unit,
1867 const char *filename,
1868 unsigned line,
1869 const char *section,
71a61510 1870 unsigned section_line,
e8e581bf
ZJS
1871 const char *lvalue,
1872 int ltype,
1873 const char *rvalue,
1874 void *data,
1875 void *userdata) {
52661efd 1876
2b583ce6 1877 ConditionType cond = ltype;
52661efd 1878 Unit *u = data;
267632f0 1879 bool trigger, negate;
52661efd 1880 Condition *c;
2fbe635a 1881 _cleanup_free_ char *p = NULL;
19f6d710 1882 int r;
52661efd
LP
1883
1884 assert(filename);
1885 assert(lvalue);
1886 assert(rvalue);
1887 assert(data);
1888
74051b9b
LP
1889 if (isempty(rvalue)) {
1890 /* Empty assignment resets the list */
1891 condition_free_list(u->conditions);
1892 u->conditions = NULL;
1893 return 0;
1894 }
1895
ab7f148f
LP
1896 trigger = rvalue[0] == '|';
1897 if (trigger)
267632f0
LP
1898 rvalue++;
1899
ab7f148f
LP
1900 negate = rvalue[0] == '!';
1901 if (negate)
52661efd
LP
1902 rvalue++;
1903
19f6d710
LP
1904 r = unit_full_printf(u, rvalue, &p);
1905 if (r < 0)
1906 log_syntax(unit, LOG_ERR, filename, line, -r,
1907 "Failed to resolve specifiers, ignoring: %s", rvalue);
1908 if (!p) {
1909 p = strdup(rvalue);
1910 if (!p)
1911 return log_oom();
1912 }
095b2d7a
AK
1913
1914 if (!path_is_absolute(p)) {
e8e581bf
ZJS
1915 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1916 "Path in condition not absolute, ignoring: %s", p);
52661efd
LP
1917 return 0;
1918 }
1919
095b2d7a 1920 c = condition_new(cond, p, trigger, negate);
ab7f148f 1921 if (!c)
74051b9b 1922 return log_oom();
52661efd 1923
71fda00f 1924 LIST_PREPEND(conditions, u->conditions, c);
52661efd
LP
1925 return 0;
1926}
1927
e8e581bf
ZJS
1928int config_parse_unit_condition_string(const char *unit,
1929 const char *filename,
1930 unsigned line,
1931 const char *section,
71a61510 1932 unsigned section_line,
e8e581bf
ZJS
1933 const char *lvalue,
1934 int ltype,
1935 const char *rvalue,
1936 void *data,
1937 void *userdata) {
039655a4 1938
41584525 1939 ConditionType cond = ltype;
039655a4 1940 Unit *u = data;
267632f0 1941 bool trigger, negate;
039655a4 1942 Condition *c;
2fbe635a 1943 _cleanup_free_ char *s = NULL;
19f6d710 1944 int r;
039655a4
LP
1945
1946 assert(filename);
1947 assert(lvalue);
1948 assert(rvalue);
1949 assert(data);
1950
74051b9b
LP
1951 if (isempty(rvalue)) {
1952 /* Empty assignment resets the list */
1953 condition_free_list(u->conditions);
1954 u->conditions = NULL;
1955 return 0;
1956 }
1957
c0d6e764
LP
1958 trigger = rvalue[0] == '|';
1959 if (trigger)
267632f0
LP
1960 rvalue++;
1961
c0d6e764
LP
1962 negate = rvalue[0] == '!';
1963 if (negate)
039655a4
LP
1964 rvalue++;
1965
19f6d710
LP
1966 r = unit_full_printf(u, rvalue, &s);
1967 if (r < 0)
1968 log_syntax(unit, LOG_ERR, filename, line, -r,
1969 "Failed to resolve specifiers, ignoring: %s", rvalue);
1970 if (!s) {
1971 s = strdup(rvalue);
1972 if (!s)
1973 return log_oom();
1974 }
095b2d7a
AK
1975
1976 c = condition_new(cond, s, trigger, negate);
c0d6e764
LP
1977 if (!c)
1978 return log_oom();
039655a4 1979
71fda00f 1980 LIST_PREPEND(conditions, u->conditions, c);
039655a4
LP
1981 return 0;
1982}
1983
e8e581bf
ZJS
1984int config_parse_unit_condition_null(const char *unit,
1985 const char *filename,
1986 unsigned line,
1987 const char *section,
71a61510 1988 unsigned section_line,
e8e581bf
ZJS
1989 const char *lvalue,
1990 int ltype,
1991 const char *rvalue,
1992 void *data,
1993 void *userdata) {
d257ddef
LP
1994
1995 Unit *u = data;
1996 Condition *c;
267632f0 1997 bool trigger, negate;
d257ddef
LP
1998 int b;
1999
2000 assert(filename);
2001 assert(lvalue);
2002 assert(rvalue);
2003 assert(data);
2004
74051b9b
LP
2005 if (isempty(rvalue)) {
2006 /* Empty assignment resets the list */
2007 condition_free_list(u->conditions);
2008 u->conditions = NULL;
2009 return 0;
2010 }
2011
2012 trigger = rvalue[0] == '|';
2013 if (trigger)
267632f0
LP
2014 rvalue++;
2015
74051b9b
LP
2016 negate = rvalue[0] == '!';
2017 if (negate)
d257ddef
LP
2018 rvalue++;
2019
74051b9b
LP
2020 b = parse_boolean(rvalue);
2021 if (b < 0) {
e8e581bf
ZJS
2022 log_syntax(unit, LOG_ERR, filename, line, -b,
2023 "Failed to parse boolean value in condition, ignoring: %s",
2024 rvalue);
d257ddef
LP
2025 return 0;
2026 }
2027
2028 if (!b)
2029 negate = !negate;
2030
74051b9b
LP
2031 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2032 if (!c)
2033 return log_oom();
d257ddef 2034
71fda00f 2035 LIST_PREPEND(conditions, u->conditions, c);
d257ddef
LP
2036 return 0;
2037}
2038
f975e971 2039DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
bf500566 2040DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
c952c6ec 2041
a57f7e2c
LP
2042int config_parse_unit_requires_mounts_for(
2043 const char *unit,
2044 const char *filename,
2045 unsigned line,
2046 const char *section,
71a61510 2047 unsigned section_line,
a57f7e2c
LP
2048 const char *lvalue,
2049 int ltype,
2050 const char *rvalue,
2051 void *data,
2052 void *userdata) {
7c8fa05c
LP
2053
2054 Unit *u = userdata;
a57f7e2c
LP
2055 char *state;
2056 size_t l;
2057 char *w;
7c8fa05c
LP
2058
2059 assert(filename);
2060 assert(lvalue);
2061 assert(rvalue);
2062 assert(data);
2063
a57f7e2c 2064 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
8a7935a2 2065 int r;
a57f7e2c
LP
2066 _cleanup_free_ char *n;
2067
2068 n = strndup(w, l);
2069 if (!n)
2070 return log_oom();
7c8fa05c 2071
a57f7e2c 2072 if (!utf8_is_valid(n)) {
b5d74213 2073 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
a57f7e2c
LP
2074 continue;
2075 }
7c8fa05c 2076
a57f7e2c
LP
2077 r = unit_require_mounts_for(u, n);
2078 if (r < 0) {
2079 log_syntax(unit, LOG_ERR, filename, line, r,
2080 "Failed to add required mount for, ignoring: %s", rvalue);
2081 continue;
2082 }
2083 }
7c8fa05c 2084
8a7935a2 2085 return 0;
7c8fa05c 2086}
9e372868 2087
e8e581bf
ZJS
2088int config_parse_documentation(const char *unit,
2089 const char *filename,
2090 unsigned line,
2091 const char *section,
71a61510 2092 unsigned section_line,
e8e581bf
ZJS
2093 const char *lvalue,
2094 int ltype,
2095 const char *rvalue,
2096 void *data,
2097 void *userdata) {
49dbfa7b
LP
2098
2099 Unit *u = userdata;
2100 int r;
2101 char **a, **b;
2102
2103 assert(filename);
2104 assert(lvalue);
2105 assert(rvalue);
2106 assert(u);
2107
74051b9b
LP
2108 if (isempty(rvalue)) {
2109 /* Empty assignment resets the list */
2110 strv_free(u->documentation);
2111 u->documentation = NULL;
2112 return 0;
2113 }
2114
71a61510 2115 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
e8e581bf 2116 rvalue, data, userdata);
49dbfa7b
LP
2117 if (r < 0)
2118 return r;
2119
2120 for (a = b = u->documentation; a && *a; a++) {
2121
2122 if (is_valid_documentation_url(*a))
2123 *(b++) = *a;
2124 else {
e8e581bf
ZJS
2125 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2126 "Invalid URL, ignoring: %s", *a);
49dbfa7b
LP
2127 free(*a);
2128 }
2129 }
f6d2d421
ZJS
2130 if (b)
2131 *b = NULL;
49dbfa7b
LP
2132
2133 return r;
2134}
2135
c0467cf3 2136#ifdef HAVE_SECCOMP
17df7223
LP
2137int config_parse_syscall_filter(
2138 const char *unit,
2139 const char *filename,
2140 unsigned line,
2141 const char *section,
2142 unsigned section_line,
2143 const char *lvalue,
2144 int ltype,
2145 const char *rvalue,
2146 void *data,
2147 void *userdata) {
2148
2149 static const char default_syscalls[] =
2150 "execve\0"
2151 "exit\0"
2152 "exit_group\0"
2153 "rt_sigreturn\0"
2154 "sigreturn\0";
2155
8351ceae
LP
2156 ExecContext *c = data;
2157 Unit *u = userdata;
b5fb3789 2158 bool invert = false;
17df7223 2159 char *w, *state;
8351ceae 2160 size_t l;
17df7223 2161 int r;
8351ceae
LP
2162
2163 assert(filename);
2164 assert(lvalue);
2165 assert(rvalue);
2166 assert(u);
2167
74051b9b
LP
2168 if (isempty(rvalue)) {
2169 /* Empty assignment resets the list */
17df7223
LP
2170 set_free(c->syscall_filter);
2171 c->syscall_filter = NULL;
2172 c->syscall_whitelist = false;
74051b9b
LP
2173 return 0;
2174 }
2175
8351ceae
LP
2176 if (rvalue[0] == '~') {
2177 invert = true;
2178 rvalue++;
2179 }
2180
17df7223
LP
2181 if (!c->syscall_filter) {
2182 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2183 if (!c->syscall_filter)
2184 return log_oom();
2185
c0467cf3 2186 if (invert)
17df7223
LP
2187 /* Allow everything but the ones listed */
2188 c->syscall_whitelist = false;
c0467cf3 2189 else {
17df7223
LP
2190 const char *i;
2191
2192 /* Allow nothing but the ones listed */
2193 c->syscall_whitelist = true;
8351ceae 2194
17df7223
LP
2195 /* Accept default syscalls if we are on a whitelist */
2196 NULSTR_FOREACH(i, default_syscalls) {
2197 int id;
8351ceae 2198
17df7223 2199 id = seccomp_syscall_resolve_name(i);
c0467cf3
RC
2200 if (id < 0)
2201 continue;
8351ceae 2202
17df7223
LP
2203 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2204 if (r == -EEXIST)
2205 continue;
2206 if (r < 0)
2207 return log_oom();
c0467cf3
RC
2208 }
2209 }
8351ceae
LP
2210 }
2211
2212 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 2213 _cleanup_free_ char *t = NULL;
17df7223 2214 int id;
8351ceae
LP
2215
2216 t = strndup(w, l);
2217 if (!t)
74051b9b 2218 return log_oom();
8351ceae 2219
c0467cf3 2220 id = seccomp_syscall_resolve_name(t);
8351ceae 2221 if (id < 0) {
17df7223 2222 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
8351ceae
LP
2223 continue;
2224 }
2225
17df7223
LP
2226 /* If we previously wanted to forbid a syscall and now
2227 * we want to allow it, then remove it from the list
c0467cf3 2228 */
17df7223
LP
2229 if (!invert == c->syscall_whitelist) {
2230 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2231 if (r == -EEXIST)
2232 continue;
2233 if (r < 0)
2234 return log_oom();
2235 } else
2236 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
c0467cf3
RC
2237 }
2238
760b9d7c
LP
2239 /* Turn on NNP, but only if it wasn't configured explicitly
2240 * before, and only if we are in user mode. */
2241 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2242 c->no_new_privileges = true;
17df7223
LP
2243
2244 return 0;
2245}
2246
57183d11
LP
2247int config_parse_syscall_archs(
2248 const char *unit,
2249 const char *filename,
2250 unsigned line,
2251 const char *section,
2252 unsigned section_line,
2253 const char *lvalue,
2254 int ltype,
2255 const char *rvalue,
2256 void *data,
2257 void *userdata) {
2258
d3b1c508 2259 Set **archs = data;
57183d11
LP
2260 char *w, *state;
2261 size_t l;
2262 int r;
2263
2264 if (isempty(rvalue)) {
d3b1c508
LP
2265 set_free(*archs);
2266 *archs = NULL;
57183d11
LP
2267 return 0;
2268 }
2269
d3b1c508 2270 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
57183d11
LP
2271 if (r < 0)
2272 return log_oom();
2273
2274 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2275 _cleanup_free_ char *t = NULL;
2276 uint32_t a;
2277
2278 t = strndup(w, l);
2279 if (!t)
2280 return log_oom();
2281
2282 r = seccomp_arch_from_string(t, &a);
2283 if (r < 0) {
2284 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2285 continue;
2286 }
2287
d3b1c508 2288 r = set_put(*archs, UINT32_TO_PTR(a + 1));
57183d11
LP
2289 if (r == -EEXIST)
2290 continue;
2291 if (r < 0)
2292 return log_oom();
2293 }
2294
2295 return 0;
2296}
2297
17df7223
LP
2298int config_parse_syscall_errno(
2299 const char *unit,
2300 const char *filename,
2301 unsigned line,
2302 const char *section,
2303 unsigned section_line,
2304 const char *lvalue,
2305 int ltype,
2306 const char *rvalue,
2307 void *data,
2308 void *userdata) {
2309
2310 ExecContext *c = data;
2311 int e;
2312
2313 assert(filename);
2314 assert(lvalue);
2315 assert(rvalue);
2316
2317 if (isempty(rvalue)) {
2318 /* Empty assignment resets to KILL */
2319 c->syscall_errno = 0;
2320 return 0;
8351ceae
LP
2321 }
2322
17df7223
LP
2323 e = errno_from_name(rvalue);
2324 if (e < 0) {
2325 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2326 return 0;
2327 }
8351ceae 2328
17df7223 2329 c->syscall_errno = e;
8351ceae
LP
2330 return 0;
2331}
4298d0b5
LP
2332
2333int config_parse_address_families(
2334 const char *unit,
2335 const char *filename,
2336 unsigned line,
2337 const char *section,
2338 unsigned section_line,
2339 const char *lvalue,
2340 int ltype,
2341 const char *rvalue,
2342 void *data,
2343 void *userdata) {
2344
2345 ExecContext *c = data;
2346 Unit *u = userdata;
2347 bool invert = false;
2348 char *w, *state;
2349 size_t l;
2350 int r;
2351
2352 assert(filename);
2353 assert(lvalue);
2354 assert(rvalue);
2355 assert(u);
2356
2357 if (isempty(rvalue)) {
2358 /* Empty assignment resets the list */
2359 set_free(c->address_families);
2360 c->address_families = NULL;
2361 c->address_families_whitelist = false;
2362 return 0;
2363 }
2364
2365 if (rvalue[0] == '~') {
2366 invert = true;
2367 rvalue++;
2368 }
2369
2370 if (!c->address_families) {
2371 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2372 if (!c->address_families)
2373 return log_oom();
2374
2375 c->address_families_whitelist = !invert;
2376 }
2377
2378 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2379 _cleanup_free_ char *t = NULL;
2380 int af;
2381
2382 t = strndup(w, l);
2383 if (!t)
2384 return log_oom();
2385
2386 af = af_from_name(t);
2387 if (af <= 0) {
2388 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2389 continue;
2390 }
2391
2392 /* If we previously wanted to forbid an address family and now
2393 * we want to allow it, then remove it from the list
2394 */
2395 if (!invert == c->address_families_whitelist) {
2396 r = set_put(c->address_families, INT_TO_PTR(af));
2397 if (r == -EEXIST)
2398 continue;
2399 if (r < 0)
2400 return log_oom();
2401 } else
2402 set_remove(c->address_families, INT_TO_PTR(af));
2403 }
2404
2405 return 0;
2406}
c0467cf3 2407#endif
8351ceae 2408
a016b922
LP
2409int config_parse_unit_slice(
2410 const char *unit,
2411 const char *filename,
2412 unsigned line,
2413 const char *section,
71a61510 2414 unsigned section_line,
a016b922
LP
2415 const char *lvalue,
2416 int ltype,
2417 const char *rvalue,
2418 void *data,
2419 void *userdata) {
2420
2421 _cleanup_free_ char *k = NULL;
2422 Unit *u = userdata, *slice;
2423 int r;
2424
2425 assert(filename);
2426 assert(lvalue);
2427 assert(rvalue);
2428 assert(u);
2429
19f6d710
LP
2430 r = unit_name_printf(u, rvalue, &k);
2431 if (r < 0)
2432 log_syntax(unit, LOG_ERR, filename, line, -r,
a016b922 2433 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
19f6d710
LP
2434 if (!k) {
2435 k = strdup(rvalue);
2436 if (!k)
2437 return log_oom();
2438 }
a016b922 2439
19f6d710 2440 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
a016b922
LP
2441 if (r < 0) {
2442 log_syntax(unit, LOG_ERR, filename, line, -r,
19f6d710 2443 "Failed to load slice unit %s. Ignoring.", k);
a016b922
LP
2444 return 0;
2445 }
2446
2447 if (slice->type != UNIT_SLICE) {
2448 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
19f6d710 2449 "Slice unit %s is not a slice. Ignoring.", k);
a016b922
LP
2450 return 0;
2451 }
2452
2453 unit_ref_set(&u->slice, slice);
2454 return 0;
2455}
2456
4ad49000
LP
2457DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2458
2459int config_parse_cpu_shares(
2460 const char *unit,
2461 const char *filename,
2462 unsigned line,
2463 const char *section,
71a61510 2464 unsigned section_line,
4ad49000
LP
2465 const char *lvalue,
2466 int ltype,
2467 const char *rvalue,
2468 void *data,
2469 void *userdata) {
2470
db785129 2471 unsigned long *shares = data, lu;
95ae05c0
WC
2472 int r;
2473
2474 assert(filename);
2475 assert(lvalue);
2476 assert(rvalue);
2477
2478 if (isempty(rvalue)) {
db785129 2479 *shares = (unsigned long) -1;
95ae05c0
WC
2480 return 0;
2481 }
2482
2483 r = safe_atolu(rvalue, &lu);
2484 if (r < 0 || lu <= 0) {
db785129 2485 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU shares '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
2486 return 0;
2487 }
2488
db785129 2489 *shares = lu;
4ad49000
LP
2490 return 0;
2491}
2492
b2f8b02e
LP
2493int config_parse_cpu_quota(
2494 const char *unit,
2495 const char *filename,
2496 unsigned line,
2497 const char *section,
2498 unsigned section_line,
2499 const char *lvalue,
2500 int ltype,
2501 const char *rvalue,
2502 void *data,
2503 void *userdata) {
2504
2505 CGroupContext *c = data;
9a054909 2506 double percent;
b2f8b02e
LP
2507
2508 assert(filename);
2509 assert(lvalue);
2510 assert(rvalue);
2511
2512 if (isempty(rvalue)) {
2513 c->cpu_quota_per_sec_usec = (usec_t) -1;
b2f8b02e
LP
2514 return 0;
2515 }
2516
9a054909 2517 if (!endswith(rvalue, "%")) {
b2f8b02e 2518
9a054909
LP
2519 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2520 return 0;
2521 }
b2f8b02e 2522
9a054909
LP
2523 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2524 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2525 return 0;
b2f8b02e
LP
2526 }
2527
9a054909
LP
2528 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2529
b2f8b02e
LP
2530 return 0;
2531}
2532
4ad49000
LP
2533int config_parse_memory_limit(
2534 const char *unit,
2535 const char *filename,
2536 unsigned line,
2537 const char *section,
71a61510 2538 unsigned section_line,
4ad49000
LP
2539 const char *lvalue,
2540 int ltype,
2541 const char *rvalue,
2542 void *data,
2543 void *userdata) {
2544
2545 CGroupContext *c = data;
4ad49000
LP
2546 off_t bytes;
2547 int r;
2548
4ad49000 2549 if (isempty(rvalue)) {
ddca82ac 2550 c->memory_limit = (uint64_t) -1;
4ad49000
LP
2551 return 0;
2552 }
2553
2554 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2555
5556b5fe 2556 r = parse_size(rvalue, 1024, &bytes);
4ad49000 2557 if (r < 0) {
5556b5fe 2558 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
2559 return 0;
2560 }
2561
ddca82ac 2562 c->memory_limit = (uint64_t) bytes;
4ad49000
LP
2563 return 0;
2564}
2565
2566int config_parse_device_allow(
2567 const char *unit,
2568 const char *filename,
2569 unsigned line,
2570 const char *section,
71a61510 2571 unsigned section_line,
4ad49000
LP
2572 const char *lvalue,
2573 int ltype,
2574 const char *rvalue,
2575 void *data,
2576 void *userdata) {
2577
2578 _cleanup_free_ char *path = NULL;
2579 CGroupContext *c = data;
2580 CGroupDeviceAllow *a;
2581 const char *m;
2582 size_t n;
2583
2584 if (isempty(rvalue)) {
2585 while (c->device_allow)
2586 cgroup_context_free_device_allow(c, c->device_allow);
2587
2588 return 0;
2589 }
2590
2591 n = strcspn(rvalue, WHITESPACE);
2592 path = strndup(rvalue, n);
2593 if (!path)
2594 return log_oom();
2595
90060676
LP
2596 if (!startswith(path, "/dev/") &&
2597 !startswith(path, "block-") &&
2598 !startswith(path, "char-")) {
2599 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
4ad49000
LP
2600 return 0;
2601 }
2602
2603 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2604 if (isempty(m))
2605 m = "rwm";
2606
2607 if (!in_charset(m, "rwm")) {
90060676 2608 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
4ad49000
LP
2609 return 0;
2610 }
2611
2612 a = new0(CGroupDeviceAllow, 1);
2613 if (!a)
2614 return log_oom();
2615
2616 a->path = path;
2617 path = NULL;
2618 a->r = !!strchr(m, 'r');
2619 a->w = !!strchr(m, 'w');
2620 a->m = !!strchr(m, 'm');
2621
71fda00f 2622 LIST_PREPEND(device_allow, c->device_allow, a);
4ad49000
LP
2623 return 0;
2624}
2625
2626int config_parse_blockio_weight(
2627 const char *unit,
2628 const char *filename,
2629 unsigned line,
2630 const char *section,
71a61510 2631 unsigned section_line,
4ad49000
LP
2632 const char *lvalue,
2633 int ltype,
2634 const char *rvalue,
2635 void *data,
2636 void *userdata) {
2637
db785129 2638 unsigned long *weight = data, lu;
95ae05c0
WC
2639 int r;
2640
2641 assert(filename);
2642 assert(lvalue);
2643 assert(rvalue);
2644
2645 if (isempty(rvalue)) {
db785129 2646 *weight = (unsigned long) -1;
95ae05c0
WC
2647 return 0;
2648 }
2649
2650 r = safe_atolu(rvalue, &lu);
2651 if (r < 0 || lu < 10 || lu > 1000) {
db785129 2652 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
95ae05c0
WC
2653 return 0;
2654 }
2655
db785129 2656 *weight = lu;
8e7076ca
LP
2657 return 0;
2658}
2659
2660int config_parse_blockio_device_weight(
2661 const char *unit,
2662 const char *filename,
2663 unsigned line,
2664 const char *section,
71a61510 2665 unsigned section_line,
8e7076ca
LP
2666 const char *lvalue,
2667 int ltype,
2668 const char *rvalue,
2669 void *data,
2670 void *userdata) {
2671
4ad49000 2672 _cleanup_free_ char *path = NULL;
8e7076ca 2673 CGroupBlockIODeviceWeight *w;
4ad49000
LP
2674 CGroupContext *c = data;
2675 unsigned long lu;
2676 const char *weight;
2677 size_t n;
2678 int r;
2679
2680 assert(filename);
2681 assert(lvalue);
2682 assert(rvalue);
2683
2684 if (isempty(rvalue)) {
4ad49000
LP
2685 while (c->blockio_device_weights)
2686 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2687
2688 return 0;
2689 }
2690
2691 n = strcspn(rvalue, WHITESPACE);
2692 weight = rvalue + n;
8e7076ca 2693 if (!*weight) {
db785129 2694 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
8e7076ca
LP
2695 return 0;
2696 }
4ad49000 2697
8e7076ca
LP
2698 path = strndup(rvalue, n);
2699 if (!path)
2700 return log_oom();
4ad49000 2701
8e7076ca 2702 if (!path_startswith(path, "/dev")) {
db785129 2703 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
8e7076ca
LP
2704 return 0;
2705 }
4ad49000 2706
8e7076ca 2707 weight += strspn(weight, WHITESPACE);
4ad49000
LP
2708 r = safe_atolu(weight, &lu);
2709 if (r < 0 || lu < 10 || lu > 1000) {
db785129 2710 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
2711 return 0;
2712 }
2713
8e7076ca
LP
2714 w = new0(CGroupBlockIODeviceWeight, 1);
2715 if (!w)
2716 return log_oom();
4ad49000 2717
8e7076ca
LP
2718 w->path = path;
2719 path = NULL;
4ad49000 2720
8e7076ca 2721 w->weight = lu;
4ad49000 2722
71fda00f 2723 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
4ad49000
LP
2724 return 0;
2725}
2726
2727int config_parse_blockio_bandwidth(
2728 const char *unit,
2729 const char *filename,
2730 unsigned line,
2731 const char *section,
71a61510 2732 unsigned section_line,
4ad49000
LP
2733 const char *lvalue,
2734 int ltype,
2735 const char *rvalue,
2736 void *data,
2737 void *userdata) {
2738
2739 _cleanup_free_ char *path = NULL;
2740 CGroupBlockIODeviceBandwidth *b;
2741 CGroupContext *c = data;
2742 const char *bandwidth;
2743 off_t bytes;
47c0980d 2744 bool read;
4ad49000
LP
2745 size_t n;
2746 int r;
2747
2748 assert(filename);
2749 assert(lvalue);
2750 assert(rvalue);
2751
47c0980d
G
2752 read = streq("BlockIOReadBandwidth", lvalue);
2753
4ad49000 2754 if (isempty(rvalue)) {
47c0980d
G
2755 CGroupBlockIODeviceBandwidth *next;
2756
2757 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2758 if (b->read == read)
2759 cgroup_context_free_blockio_device_bandwidth(c, b);
4ad49000
LP
2760
2761 return 0;
2762 }
2763
2764 n = strcspn(rvalue, WHITESPACE);
2765 bandwidth = rvalue + n;
2766 bandwidth += strspn(bandwidth, WHITESPACE);
2767
2768 if (!*bandwidth) {
2769 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2770 "Expected space separated pair of device node and bandwidth. Ignoring.");
2771 return 0;
2772 }
2773
2774 path = strndup(rvalue, n);
2775 if (!path)
2776 return log_oom();
2777
2778 if (!path_startswith(path, "/dev")) {
2779 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2780 "Invalid device node path '%s'. Ignoring.", path);
2781 return 0;
2782 }
2783
5556b5fe 2784 r = parse_size(bandwidth, 1000, &bytes);
4ad49000 2785 if (r < 0 || bytes <= 0) {
5556b5fe 2786 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
4ad49000
LP
2787 return 0;
2788 }
2789
2790 b = new0(CGroupBlockIODeviceBandwidth, 1);
2791 if (!b)
2792 return log_oom();
2793
2794 b->path = path;
2795 path = NULL;
2796 b->bandwidth = (uint64_t) bytes;
47c0980d 2797 b->read = read;
4ad49000 2798
71fda00f 2799 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
4ad49000
LP
2800
2801 return 0;
2802}
2803
d420282b
LP
2804DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2805
2806int config_parse_job_mode_isolate(
2807 const char *unit,
2808 const char *filename,
2809 unsigned line,
2810 const char *section,
2811 unsigned section_line,
2812 const char *lvalue,
2813 int ltype,
2814 const char *rvalue,
2815 void *data,
2816 void *userdata) {
2817
2818 JobMode *m = data;
2819 int r;
2820
2821 assert(filename);
2822 assert(lvalue);
2823 assert(rvalue);
2824
2825 r = parse_boolean(rvalue);
2826 if (r < 0) {
2827 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2828 return 0;
2829 }
2830
2831 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2832 return 0;
2833}
2834
ac45f971
LP
2835int config_parse_personality(
2836 const char *unit,
2837 const char *filename,
2838 unsigned line,
2839 const char *section,
2840 unsigned section_line,
2841 const char *lvalue,
2842 int ltype,
2843 const char *rvalue,
2844 void *data,
2845 void *userdata) {
2846
2847 unsigned long *personality = data, p;
2848
2849 assert(filename);
2850 assert(lvalue);
2851 assert(rvalue);
2852 assert(personality);
2853
2854 p = personality_from_string(rvalue);
2855 if (p == 0xffffffffUL) {
2856 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2857 "Failed to parse personality, ignoring: %s", rvalue);
2858 return 0;
2859 }
2860
2861 *personality = p;
2862 return 0;
2863}
2864
e66cf1a3
LP
2865int config_parse_runtime_directory(
2866 const char *unit,
2867 const char *filename,
2868 unsigned line,
2869 const char *section,
2870 unsigned section_line,
2871 const char *lvalue,
2872 int ltype,
2873 const char *rvalue,
2874 void *data,
2875 void *userdata) {
2876
2877 char***rt = data, *w, *state;
2878 size_t l;
2879 int r;
2880
2881 assert(filename);
2882 assert(lvalue);
2883 assert(rvalue);
2884 assert(data);
2885
2886 if (isempty(rvalue)) {
2887 /* Empty assignment resets the list */
2888 strv_free(*rt);
2889 *rt = NULL;
2890 return 0;
2891 }
2892
2893 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2894 _cleanup_free_ char *n;
2895
2896 n = strndup(w, l);
2897 if (!n)
2898 return log_oom();
2899
2900 if (!filename_is_safe(n)) {
2901 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2902 continue;
2903 }
2904
2905 r = strv_push(rt, n);
2906 if (r < 0)
2907 return log_oom();
2908
2909 n = NULL;
2910 }
2911
2912 return 0;
2913}
2914
3af00fb8
LP
2915int config_parse_set_status(
2916 const char *unit,
2917 const char *filename,
2918 unsigned line,
2919 const char *section,
2920 unsigned section_line,
2921 const char *lvalue,
2922 int ltype,
2923 const char *rvalue,
2924 void *data,
2925 void *userdata) {
2926
2927 char *w;
2928 size_t l;
2929 char *state;
2930 int r;
2931 ExitStatusSet *status_set = data;
2932
2933 assert(filename);
2934 assert(lvalue);
2935 assert(rvalue);
2936 assert(data);
2937
3e2d435b 2938 /* Empty assignment resets the list */
3af00fb8 2939 if (isempty(rvalue)) {
3e2d435b 2940 exit_status_set_free(status_set);
3af00fb8
LP
2941 return 0;
2942 }
2943
2944 FOREACH_WORD(w, l, rvalue, state) {
2945 _cleanup_free_ char *temp;
2946 int val;
2947
2948 temp = strndup(w, l);
2949 if (!temp)
2950 return log_oom();
2951
2952 r = safe_atoi(temp, &val);
2953 if (r < 0) {
2954 val = signal_from_string_try_harder(temp);
2955
2956 if (val > 0) {
3e2d435b 2957 r = set_ensure_allocated(&status_set->signal, NULL, NULL);
3af00fb8
LP
2958 if (r < 0)
2959 return log_oom();
2960
2961 r = set_put(status_set->signal, INT_TO_PTR(val));
2962 if (r < 0) {
2963 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2964 return r;
2965 }
2966 } else {
2967 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2968 return 0;
2969 }
2970 } else {
2971 if (val < 0 || val > 255)
2972 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2973 else {
3e2d435b 2974 r = set_ensure_allocated(&status_set->status, NULL, NULL);
3af00fb8
LP
2975 if (r < 0)
2976 return log_oom();
2977
3e2d435b 2978 r = set_put(status_set->status, INT_TO_PTR(val));
3af00fb8
LP
2979 if (r < 0) {
2980 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2981 return r;
2982 }
2983 }
2984 }
2985 }
2986
2987 return 0;
2988}
2989
94828d2d
LP
2990int config_parse_namespace_path_strv(
2991 const char *unit,
2992 const char *filename,
2993 unsigned line,
2994 const char *section,
2995 unsigned section_line,
2996 const char *lvalue,
2997 int ltype,
2998 const char *rvalue,
2999 void *data,
3000 void *userdata) {
3001
3002 char*** sv = data, *w, *state;
3003 size_t l;
3004 int r;
3005
3006 assert(filename);
3007 assert(lvalue);
3008 assert(rvalue);
3009 assert(data);
3010
3011 if (isempty(rvalue)) {
3012 /* Empty assignment resets the list */
3013 strv_free(*sv);
3014 *sv = NULL;
3015 return 0;
3016 }
3017
3018 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
3019 _cleanup_free_ char *n;
3020 int offset;
3021
3022 n = strndup(w, l);
3023 if (!n)
3024 return log_oom();
3025
3026 if (!utf8_is_valid(n)) {
b5d74213 3027 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
94828d2d
LP
3028 continue;
3029 }
3030
3031 offset = n[0] == '-';
3032 if (!path_is_absolute(n + offset)) {
3033 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3034 continue;
3035 }
3036
3037 path_kill_slashes(n);
3038
3039 r = strv_push(sv, n);
3040 if (r < 0)
3041 return log_oom();
3042
3043 n = NULL;
3044 }
3045
3046 return 0;
3047}
3048
f1721625 3049int config_parse_no_new_privileges(
760b9d7c
LP
3050 const char* unit,
3051 const char *filename,
3052 unsigned line,
3053 const char *section,
3054 unsigned section_line,
3055 const char *lvalue,
3056 int ltype,
3057 const char *rvalue,
3058 void *data,
3059 void *userdata) {
3060
3061 ExecContext *c = data;
3062 int k;
3063
3064 assert(filename);
3065 assert(lvalue);
3066 assert(rvalue);
3067 assert(data);
3068
3069 k = parse_boolean(rvalue);
3070 if (k < 0) {
3071 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3072 return 0;
3073 }
3074
3075 c->no_new_privileges = !!k;
3076 c->no_new_privileges_set = true;
3077
3078 return 0;
3079}
3080
1b8689f9 3081int config_parse_protect_home(
417116f2
LP
3082 const char* unit,
3083 const char *filename,
3084 unsigned line,
3085 const char *section,
3086 unsigned section_line,
3087 const char *lvalue,
3088 int ltype,
3089 const char *rvalue,
3090 void *data,
3091 void *userdata) {
3092
3093 ExecContext *c = data;
3094 int k;
3095
3096 assert(filename);
3097 assert(lvalue);
3098 assert(rvalue);
3099 assert(data);
3100
3101 /* Our enum shall be a superset of booleans, hence first try
3102 * to parse as as boolean, and then as enum */
3103
3104 k = parse_boolean(rvalue);
3105 if (k > 0)
1b8689f9 3106 c->protect_home = PROTECT_HOME_YES;
417116f2 3107 else if (k == 0)
1b8689f9 3108 c->protect_home = PROTECT_HOME_NO;
417116f2 3109 else {
1b8689f9 3110 ProtectHome h;
417116f2 3111
1b8689f9 3112 h = protect_home_from_string(rvalue);
417116f2 3113 if (h < 0){
1b8689f9 3114 log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protect home value, ignoring: %s", rvalue);
417116f2
LP
3115 return 0;
3116 }
3117
1b8689f9
LP
3118 c->protect_home = h;
3119 }
3120
3121 return 0;
3122}
3123
3124int config_parse_protect_system(
3125 const char* unit,
3126 const char *filename,
3127 unsigned line,
3128 const char *section,
3129 unsigned section_line,
3130 const char *lvalue,
3131 int ltype,
3132 const char *rvalue,
3133 void *data,
3134 void *userdata) {
3135
3136 ExecContext *c = data;
3137 int k;
3138
3139 assert(filename);
3140 assert(lvalue);
3141 assert(rvalue);
3142 assert(data);
3143
3144 /* Our enum shall be a superset of booleans, hence first try
3145 * to parse as as boolean, and then as enum */
3146
3147 k = parse_boolean(rvalue);
3148 if (k > 0)
3149 c->protect_system = PROTECT_SYSTEM_YES;
3150 else if (k == 0)
3151 c->protect_system = PROTECT_SYSTEM_NO;
3152 else {
3153 ProtectSystem s;
3154
3155 s = protect_system_from_string(rvalue);
3156 if (s < 0){
3157 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse protect system value, ignoring: %s", rvalue);
3158 return 0;
3159 }
3160
3161 c->protect_system = s;
417116f2
LP
3162 }
3163
3164 return 0;
3165}
3166
071830ff 3167#define FOLLOW_MAX 8
87f0e418 3168
9e2f7c11 3169static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
0301abf4 3170 unsigned c = 0;
87f0e418
LP
3171 int fd, r;
3172 FILE *f;
0301abf4 3173 char *id = NULL;
87f0e418
LP
3174
3175 assert(filename);
3176 assert(*filename);
3177 assert(_f);
3178 assert(names);
3179
0301abf4
LP
3180 /* This will update the filename pointer if the loaded file is
3181 * reached by a symlink. The old string will be freed. */
87f0e418 3182
0301abf4 3183 for (;;) {
2c7108c4 3184 char *target, *name;
87f0e418 3185
0301abf4
LP
3186 if (c++ >= FOLLOW_MAX)
3187 return -ELOOP;
3188
b08d03ff
LP
3189 path_kill_slashes(*filename);
3190
87f0e418 3191 /* Add the file name we are currently looking at to
8f05424d
LP
3192 * the names of this unit, but only if it is a valid
3193 * unit name. */
2b6bf07d 3194 name = basename(*filename);
87f0e418 3195
f78e6385 3196 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
8f05424d 3197
15e11d81
LP
3198 id = set_get(names, name);
3199 if (!id) {
3200 id = strdup(name);
3201 if (!id)
8f05424d 3202 return -ENOMEM;
87f0e418 3203
ef42202a
ZJS
3204 r = set_consume(names, id);
3205 if (r < 0)
8f05424d 3206 return r;
87f0e418 3207 }
87f0e418
LP
3208 }
3209
0301abf4 3210 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
3211 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3212 if (fd >= 0)
87f0e418
LP
3213 break;
3214
0301abf4
LP
3215 if (errno != ELOOP)
3216 return -errno;
3217
87f0e418 3218 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
3219 r = readlink_and_make_absolute(*filename, &target);
3220 if (r < 0)
0301abf4 3221 return r;
87f0e418 3222
0301abf4 3223 free(*filename);
2c7108c4 3224 *filename = target;
87f0e418
LP
3225 }
3226
9946996c
LP
3227 f = fdopen(fd, "re");
3228 if (!f) {
87f0e418 3229 r = -errno;
03e334a1 3230 safe_close(fd);
0301abf4 3231 return r;
87f0e418
LP
3232 }
3233
3234 *_f = f;
9e2f7c11 3235 *_final = id;
0301abf4 3236 return 0;
87f0e418
LP
3237}
3238
23a177ef
LP
3239static int merge_by_names(Unit **u, Set *names, const char *id) {
3240 char *k;
3241 int r;
3242
3243 assert(u);
3244 assert(*u);
3245 assert(names);
3246
3247 /* Let's try to add in all symlink names we found */
3248 while ((k = set_steal_first(names))) {
3249
3250 /* First try to merge in the other name into our
3251 * unit */
9946996c
LP
3252 r = unit_merge_by_name(*u, k);
3253 if (r < 0) {
23a177ef
LP
3254 Unit *other;
3255
3256 /* Hmm, we couldn't merge the other unit into
3257 * ours? Then let's try it the other way
3258 * round */
3259
ac155bb8 3260 other = manager_get_unit((*u)->manager, k);
23a177ef
LP
3261 free(k);
3262
9946996c
LP
3263 if (other) {
3264 r = unit_merge(other, *u);
3265 if (r >= 0) {
23a177ef
LP
3266 *u = other;
3267 return merge_by_names(u, names, NULL);
3268 }
9946996c 3269 }
23a177ef
LP
3270
3271 return r;
3272 }
3273
3274 if (id == k)
3275 unit_choose_id(*u, id);
3276
3277 free(k);
3278 }
3279
3280 return 0;
3281}
3282
e537352b 3283static int load_from_path(Unit *u, const char *path) {
0301abf4 3284 int r;
e48614c4
ZJS
3285 _cleanup_set_free_free_ Set *symlink_names = NULL;
3286 _cleanup_fclose_ FILE *f = NULL;
3287 _cleanup_free_ char *filename = NULL;
3288 char *id = NULL;
23a177ef 3289 Unit *merged;
45fb0699 3290 struct stat st;
23a177ef
LP
3291
3292 assert(u);
e537352b 3293 assert(path);
3efd4195 3294
f975e971
LP
3295 symlink_names = set_new(string_hash_func, string_compare_func);
3296 if (!symlink_names)
87f0e418 3297 return -ENOMEM;
3efd4195 3298
036643a2
LP
3299 if (path_is_absolute(path)) {
3300
9946996c 3301 filename = strdup(path);
e48614c4
ZJS
3302 if (!filename)
3303 return -ENOMEM;
036643a2 3304
9946996c
LP
3305 r = open_follow(&filename, &f, symlink_names, &id);
3306 if (r < 0) {
036643a2
LP
3307 free(filename);
3308 filename = NULL;
3309
3310 if (r != -ENOENT)
e48614c4 3311 return r;
036643a2
LP
3312 }
3313
3314 } else {
3315 char **p;
3316
ac155bb8 3317 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
036643a2
LP
3318
3319 /* Instead of opening the path right away, we manually
3320 * follow all symlinks and add their name to our unit
3321 * name set while doing so */
9946996c 3322 filename = path_make_absolute(path, *p);
e48614c4
ZJS
3323 if (!filename)
3324 return -ENOMEM;
036643a2 3325
ac155bb8
MS
3326 if (u->manager->unit_path_cache &&
3327 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
3328 r = -ENOENT;
3329 else
3330 r = open_follow(&filename, &f, symlink_names, &id);
3331
3332 if (r < 0) {
036643a2
LP
3333 free(filename);
3334 filename = NULL;
3335
3336 if (r != -ENOENT)
e48614c4 3337 return r;
036643a2
LP
3338
3339 /* Empty the symlink names for the next run */
9946996c 3340 set_clear_free(symlink_names);
036643a2
LP
3341 continue;
3342 }
3343
3344 break;
3345 }
3346 }
034c6ed7 3347
e48614c4 3348 if (!filename)
8f05424d 3349 /* Hmm, no suitable file found? */
e48614c4 3350 return 0;
87f0e418 3351
23a177ef 3352 merged = u;
9946996c
LP
3353 r = merge_by_names(&merged, symlink_names, id);
3354 if (r < 0)
e48614c4 3355 return r;
87f0e418 3356
23a177ef 3357 if (merged != u) {
ac155bb8 3358 u->load_state = UNIT_MERGED;
e48614c4 3359 return 0;
034c6ed7
LP
3360 }
3361
e48614c4
ZJS
3362 if (fstat(fileno(f), &st) < 0)
3363 return -errno;
45fb0699 3364
00dc5d76 3365 if (null_or_empty(&st))
ac155bb8 3366 u->load_state = UNIT_MASKED;
00dc5d76 3367 else {
c2756a68
LP
3368 u->load_state = UNIT_LOADED;
3369
00dc5d76 3370 /* Now, parse the file contents */
e8e581bf
ZJS
3371 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3372 config_item_perf_lookup,
e9f3d2d5 3373 load_fragment_gperf_lookup, false, true, u);
f975e971 3374 if (r < 0)
e48614c4 3375 return r;
00dc5d76 3376 }
b08d03ff 3377
ac155bb8
MS
3378 free(u->fragment_path);
3379 u->fragment_path = filename;
0301abf4 3380 filename = NULL;
87f0e418 3381
ac155bb8 3382 u->fragment_mtime = timespec_load(&st.st_mtim);
45fb0699 3383
1b64d026
LP
3384 if (u->source_path) {
3385 if (stat(u->source_path, &st) >= 0)
3386 u->source_mtime = timespec_load(&st.st_mtim);
3387 else
3388 u->source_mtime = 0;
3389 }
3390
e48614c4 3391 return 0;
0301abf4
LP
3392}
3393
e537352b 3394int unit_load_fragment(Unit *u) {
23a177ef 3395 int r;
294d81f1
LP
3396 Iterator i;
3397 const char *t;
0301abf4
LP
3398
3399 assert(u);
ac155bb8
MS
3400 assert(u->load_state == UNIT_STUB);
3401 assert(u->id);
23a177ef 3402
294d81f1
LP
3403 /* First, try to find the unit under its id. We always look
3404 * for unit files in the default directories, to make it easy
3405 * to override things by placing things in /etc/systemd/system */
9946996c
LP
3406 r = load_from_path(u, u->id);
3407 if (r < 0)
294d81f1
LP
3408 return r;
3409
3410 /* Try to find an alias we can load this with */
ac155bb8
MS
3411 if (u->load_state == UNIT_STUB)
3412 SET_FOREACH(t, u->names, i) {
294d81f1 3413
ac155bb8 3414 if (t == u->id)
294d81f1
LP
3415 continue;
3416
9946996c
LP
3417 r = load_from_path(u, t);
3418 if (r < 0)
294d81f1
LP
3419 return r;
3420
ac155bb8 3421 if (u->load_state != UNIT_STUB)
294d81f1
LP
3422 break;
3423 }
23a177ef 3424
294d81f1 3425 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 3426 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 3427
9946996c
LP
3428 r = load_from_path(u, u->fragment_path);
3429 if (r < 0)
23a177ef 3430 return r;
0301abf4 3431
ac155bb8 3432 if (u->load_state == UNIT_STUB) {
6ccb1b44
LP
3433 /* Hmm, this didn't work? Then let's get rid
3434 * of the fragment path stored for us, so that
3435 * we don't point to an invalid location. */
ac155bb8
MS
3436 free(u->fragment_path);
3437 u->fragment_path = NULL;
6ccb1b44
LP
3438 }
3439 }
3440
294d81f1 3441 /* Look for a template */
ac155bb8 3442 if (u->load_state == UNIT_STUB && u->instance) {
bc9fd78c 3443 _cleanup_free_ char *k;
294d81f1 3444
9946996c
LP
3445 k = unit_name_template(u->id);
3446 if (!k)
294d81f1
LP
3447 return -ENOMEM;
3448
3449 r = load_from_path(u, k);
294d81f1 3450 if (r < 0)
9e2f7c11 3451 return r;
890f434c 3452
ac155bb8
MS
3453 if (u->load_state == UNIT_STUB)
3454 SET_FOREACH(t, u->names, i) {
bc9fd78c 3455 _cleanup_free_ char *z = NULL;
87f0e418 3456
ac155bb8 3457 if (t == u->id)
23a177ef 3458 continue;
071830ff 3459
bc9fd78c
LP
3460 z = unit_name_template(t);
3461 if (!z)
294d81f1
LP
3462 return -ENOMEM;
3463
bc9fd78c 3464 r = load_from_path(u, z);
294d81f1 3465 if (r < 0)
23a177ef 3466 return r;
890f434c 3467
ac155bb8 3468 if (u->load_state != UNIT_STUB)
23a177ef
LP
3469 break;
3470 }
071830ff
LP
3471 }
3472
23a177ef 3473 return 0;
3efd4195 3474}
e537352b
LP
3475
3476void unit_dump_config_items(FILE *f) {
f975e971
LP
3477 static const struct {
3478 const ConfigParserCallback callback;
3479 const char *rvalue;
3480 } table[] = {
7f8aa671 3481#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
17df7223
LP
3482 { config_parse_warn_compat, "NOTSUPPORTED" },
3483#endif
f975e971
LP
3484 { config_parse_int, "INTEGER" },
3485 { config_parse_unsigned, "UNSIGNED" },
5556b5fe
LP
3486 { config_parse_iec_size, "SIZE" },
3487 { config_parse_iec_off, "SIZE" },
3488 { config_parse_si_size, "SIZE" },
f975e971
LP
3489 { config_parse_bool, "BOOLEAN" },
3490 { config_parse_string, "STRING" },
3491 { config_parse_path, "PATH" },
3492 { config_parse_unit_path_printf, "PATH" },
3493 { config_parse_strv, "STRING [...]" },
3494 { config_parse_exec_nice, "NICE" },
3495 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3496 { config_parse_exec_io_class, "IOCLASS" },
3497 { config_parse_exec_io_priority, "IOPRIORITY" },
3498 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3499 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3500 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3501 { config_parse_mode, "MODE" },
3502 { config_parse_unit_env_file, "FILE" },
3503 { config_parse_output, "OUTPUT" },
3504 { config_parse_input, "INPUT" },
ca37242e
LP
3505 { config_parse_log_facility, "FACILITY" },
3506 { config_parse_log_level, "LEVEL" },
f975e971
LP
3507 { config_parse_exec_capabilities, "CAPABILITIES" },
3508 { config_parse_exec_secure_bits, "SECUREBITS" },
ec8927ca 3509 { config_parse_bounding_set, "BOUNDINGSET" },
f975e971 3510 { config_parse_limit, "LIMIT" },
f975e971 3511 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
3512 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3513 { config_parse_service_type, "SERVICETYPE" },
3514 { config_parse_service_restart, "SERVICERESTART" },
3515#ifdef HAVE_SYSV_COMPAT
3516 { config_parse_sysv_priority, "SYSVPRIORITY" },
f975e971
LP
3517#endif
3518 { config_parse_kill_mode, "KILLMODE" },
3519 { config_parse_kill_signal, "SIGNAL" },
3520 { config_parse_socket_listen, "SOCKET [...]" },
3521 { config_parse_socket_bind, "SOCKETBIND" },
3522 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
7f602784 3523 { config_parse_sec, "SECONDS" },
d88a251b 3524 { config_parse_nsec, "NANOSECONDS" },
94828d2d 3525 { config_parse_namespace_path_strv, "PATH [...]" },
7c8fa05c 3526 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
3527 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3528 { config_parse_unit_string_printf, "STRING" },
3ecaa09b 3529 { config_parse_trigger_unit, "UNIT" },
f975e971 3530 { config_parse_timer, "TIMER" },
f975e971 3531 { config_parse_path_spec, "PATH" },
f975e971
LP
3532 { config_parse_notify_access, "ACCESS" },
3533 { config_parse_ip_tos, "TOS" },
3534 { config_parse_unit_condition_path, "CONDITION" },
3535 { config_parse_unit_condition_string, "CONDITION" },
3536 { config_parse_unit_condition_null, "CONDITION" },
a016b922 3537 { config_parse_unit_slice, "SLICE" },
7f0386f6
LP
3538 { config_parse_documentation, "URL" },
3539 { config_parse_service_timeout, "SECONDS" },
bf500566 3540 { config_parse_failure_action, "ACTION" },
7f0386f6
LP
3541 { config_parse_set_status, "STATUS" },
3542 { config_parse_service_sockets, "SOCKETS" },
7f0386f6 3543 { config_parse_environ, "ENVIRON" },
c0467cf3 3544#ifdef HAVE_SECCOMP
17df7223 3545 { config_parse_syscall_filter, "SYSCALLS" },
6a6751fe 3546 { config_parse_syscall_archs, "ARCHS" },
17df7223 3547 { config_parse_syscall_errno, "ERRNO" },
4298d0b5 3548 { config_parse_address_families, "FAMILIES" },
c0467cf3 3549#endif
7f0386f6
LP
3550 { config_parse_cpu_shares, "SHARES" },
3551 { config_parse_memory_limit, "LIMIT" },
3552 { config_parse_device_allow, "DEVICE" },
3553 { config_parse_device_policy, "POLICY" },
3554 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3555 { config_parse_blockio_weight, "WEIGHT" },
3556 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3557 { config_parse_long, "LONG" },
3558 { config_parse_socket_service, "SERVICE" },
6a6751fe
LP
3559#ifdef HAVE_SELINUX
3560 { config_parse_exec_selinux_context, "LABEL" },
3561#endif
3562 { config_parse_job_mode, "MODE" },
3563 { config_parse_job_mode_isolate, "BOOLEAN" },
4298d0b5 3564 { config_parse_personality, "PERSONALITY" },
f975e971
LP
3565 };
3566
3567 const char *prev = NULL;
3568 const char *i;
3569
3570 assert(f);
e537352b 3571
f975e971
LP
3572 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3573 const char *rvalue = "OTHER", *lvalue;
3574 unsigned j;
3575 size_t prefix_len;
3576 const char *dot;
3577 const ConfigPerfItem *p;
3578
3579 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3580
3581 dot = strchr(i, '.');
3582 lvalue = dot ? dot + 1 : i;
3583 prefix_len = dot-i;
3584
3585 if (dot)
641906e9 3586 if (!prev || !strneq(prev, i, prefix_len+1)) {
f975e971
LP
3587 if (prev)
3588 fputc('\n', f);
3589
3590 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3591 }
3592
3593 for (j = 0; j < ELEMENTSOF(table); j++)
3594 if (p->parse == table[j].callback) {
3595 rvalue = table[j].rvalue;
3596 break;
3597 }
3598
3599 fprintf(f, "%s=%s\n", lvalue, rvalue);
3600 prev = i;
3601 }
e537352b 3602}