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