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