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