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