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