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