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