]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/load-fragment.c
PATCH: add missing header include
[thirdparty/systemd.git] / src / 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
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
87f0e418 22#include <linux/oom.h>
3efd4195
LP
23#include <assert.h>
24#include <errno.h>
25#include <string.h>
87f0e418
LP
26#include <unistd.h>
27#include <fcntl.h>
94f04347
LP
28#include <sched.h>
29#include <sys/prctl.h>
15ae422b 30#include <sys/mount.h>
25e870b5 31#include <linux/fs.h>
45fb0699 32#include <sys/stat.h>
3d57c6ab
LP
33#include <sys/time.h>
34#include <sys/resource.h>
3efd4195 35
87f0e418 36#include "unit.h"
3efd4195
LP
37#include "strv.h"
38#include "conf-parser.h"
39#include "load-fragment.h"
16354eff 40#include "log.h"
9eba9da4 41#include "ioprio.h"
94f04347
LP
42#include "securebits.h"
43#include "missing.h"
9e2f7c11 44#include "unit-name.h"
398ef8ba 45#include "bus-errors.h"
3efd4195 46
07459bb6 47#ifndef HAVE_SYSV_COMPAT
f975e971 48int config_parse_warn_compat(
07459bb6
FF
49 const char *filename,
50 unsigned line,
51 const char *section,
52 const char *lvalue,
2b583ce6 53 int ltype,
07459bb6
FF
54 const char *rvalue,
55 void *data,
56 void *userdata) {
57
58 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
59 return 0;
60}
61#endif
62
f975e971 63int config_parse_unit_deps(
3efd4195
LP
64 const char *filename,
65 unsigned line,
66 const char *section,
67 const char *lvalue,
2b583ce6 68 int ltype,
3efd4195
LP
69 const char *rvalue,
70 void *data,
71 void *userdata) {
72
f975e971 73 UnitDependency d = ltype;
87f0e418 74 Unit *u = userdata;
3efd4195
LP
75 char *w;
76 size_t l;
77 char *state;
78
79 assert(filename);
80 assert(lvalue);
81 assert(rvalue);
3efd4195 82
f60f22df 83 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
9e2f7c11 84 char *t, *k;
3efd4195 85 int r;
3efd4195
LP
86
87 if (!(t = strndup(w, l)))
88 return -ENOMEM;
89
9e2f7c11 90 k = unit_name_printf(u, t);
3efd4195
LP
91 free(t);
92
9e2f7c11
LP
93 if (!k)
94 return -ENOMEM;
95
701cc384 96 r = unit_add_dependency_by_name(u, d, k, NULL, true);
9e2f7c11 97
c0b34696
LP
98 if (r < 0) {
99 log_error("Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
100 free(k);
101 return 0;
102 }
103
104 free(k);
3efd4195
LP
105 }
106
107 return 0;
108}
109
f975e971 110int config_parse_unit_names(
87d1515d
LP
111 const char *filename,
112 unsigned line,
113 const char *section,
114 const char *lvalue,
2b583ce6 115 int ltype,
87d1515d
LP
116 const char *rvalue,
117 void *data,
118 void *userdata) {
119
87f0e418 120 Unit *u = userdata;
87d1515d
LP
121 char *w;
122 size_t l;
123 char *state;
124
125 assert(filename);
126 assert(lvalue);
127 assert(rvalue);
128 assert(data);
129
f60f22df 130 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
9e2f7c11 131 char *t, *k;
87d1515d 132 int r;
87d1515d
LP
133
134 if (!(t = strndup(w, l)))
135 return -ENOMEM;
136
9e2f7c11 137 k = unit_name_printf(u, t);
87d1515d 138 free(t);
23a177ef 139
9e2f7c11
LP
140 if (!k)
141 return -ENOMEM;
142
143 r = unit_merge_by_name(u, k);
9e2f7c11 144
c0b34696
LP
145 if (r < 0) {
146 log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
147 free(k);
148 return 0;
149 }
150
151 free(k);
87d1515d
LP
152 }
153
154 return 0;
155}
156
f975e971 157int config_parse_unit_string_printf(
932921b5
LP
158 const char *filename,
159 unsigned line,
160 const char *section,
161 const char *lvalue,
2b583ce6 162 int ltype,
932921b5
LP
163 const char *rvalue,
164 void *data,
165 void *userdata) {
166
167 Unit *u = userdata;
f2d3769a 168 char **s = data;
932921b5
LP
169 char *k;
170
171 assert(filename);
172 assert(lvalue);
173 assert(rvalue);
f2d3769a
LP
174 assert(s);
175 assert(u);
932921b5
LP
176
177 if (!(k = unit_full_printf(u, rvalue)))
178 return -ENOMEM;
179
f2d3769a 180 free(*s);
932921b5 181 if (*k)
f2d3769a 182 *s = k;
932921b5
LP
183 else {
184 free(k);
f2d3769a 185 *s = NULL;
932921b5
LP
186 }
187
188 return 0;
189}
190
f975e971 191int config_parse_unit_strv_printf(
8fef7659
LP
192 const char *filename,
193 unsigned line,
194 const char *section,
195 const char *lvalue,
196 int ltype,
197 const char *rvalue,
198 void *data,
199 void *userdata) {
200
201 Unit *u = userdata;
202 char *k;
203 int r;
204
205 assert(filename);
206 assert(lvalue);
207 assert(rvalue);
208 assert(u);
209
210 k = unit_full_printf(u, rvalue);
211 if (!k)
212 return -ENOMEM;
213
214 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
215 free(k);
216
217 return r;
218}
219
f975e971 220int config_parse_unit_path_printf(
6ea832a2
LP
221 const char *filename,
222 unsigned line,
223 const char *section,
224 const char *lvalue,
225 int ltype,
226 const char *rvalue,
227 void *data,
228 void *userdata) {
229
230 Unit *u = userdata;
231 char **s = data;
232 char *k;
233
234 assert(filename);
235 assert(lvalue);
236 assert(rvalue);
237 assert(s);
238 assert(u);
239
240 if (!(k = unit_full_printf(u, rvalue)))
241 return -ENOMEM;
242
243 if (!path_is_absolute(k)) {
244 log_error("[%s:%u] Not an absolute path: %s", filename, line, k);
245 free(k);
246 return -EINVAL;
247 }
248
249 path_kill_slashes(k);
250
251 free(*s);
252 *s = k;
253
254 return 0;
255}
256
f975e971 257int config_parse_socket_listen(
42f4e3c4
LP
258 const char *filename,
259 unsigned line,
260 const char *section,
261 const char *lvalue,
2b583ce6 262 int ltype,
42f4e3c4
LP
263 const char *rvalue,
264 void *data,
265 void *userdata) {
266
49f91047 267 SocketPort *p, *tail;
542563ba 268 Socket *s;
16354eff 269
42f4e3c4
LP
270 assert(filename);
271 assert(lvalue);
272 assert(rvalue);
273 assert(data);
274
542563ba
LP
275 s = (Socket*) data;
276
277 if (!(p = new0(SocketPort, 1)))
278 return -ENOMEM;
279
280 if (streq(lvalue, "ListenFIFO")) {
281 p->type = SOCKET_FIFO;
282
1fd45a90 283 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
542563ba
LP
284 free(p);
285 return -ENOMEM;
286 }
01f78473
LP
287
288 path_kill_slashes(p->path);
b0a3f2bc
LP
289
290 } else if (streq(lvalue, "ListenSpecial")) {
291 p->type = SOCKET_SPECIAL;
292
1fd45a90 293 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
b0a3f2bc
LP
294 free(p);
295 return -ENOMEM;
296 }
297
298 path_kill_slashes(p->path);
299
916abb21
LP
300 } else if (streq(lvalue, "ListenMessageQueue")) {
301
302 p->type = SOCKET_MQUEUE;
303
1fd45a90 304 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
916abb21
LP
305 free(p);
306 return -ENOMEM;
307 }
308
309 path_kill_slashes(p->path);
310
7a22745a 311 } else if (streq(lvalue, "ListenNetlink")) {
1fd45a90
LP
312 char *k;
313 int r;
314
7a22745a 315 p->type = SOCKET_SOCKET;
1fd45a90
LP
316 k = unit_full_printf(UNIT(s), rvalue);
317 r = socket_address_parse_netlink(&p->address, k);
318 free(k);
7a22745a 319
1fd45a90 320 if (r < 0) {
7a22745a
LP
321 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
322 free(p);
323 return 0;
324 }
325
542563ba 326 } else {
1fd45a90
LP
327 char *k;
328 int r;
329
542563ba 330 p->type = SOCKET_SOCKET;
1fd45a90
LP
331 k = unit_full_printf(UNIT(s), rvalue);
332 r = socket_address_parse(&p->address, k);
333 free(k);
542563ba 334
1fd45a90 335 if (r < 0) {
c0b34696 336 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
542563ba 337 free(p);
c0b34696 338 return 0;
542563ba
LP
339 }
340
341 if (streq(lvalue, "ListenStream"))
342 p->address.type = SOCK_STREAM;
343 else if (streq(lvalue, "ListenDatagram"))
344 p->address.type = SOCK_DGRAM;
345 else {
346 assert(streq(lvalue, "ListenSequentialPacket"));
347 p->address.type = SOCK_SEQPACKET;
348 }
349
350 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
c0b34696 351 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
542563ba 352 free(p);
c0b34696 353 return 0;
542563ba 354 }
16354eff
LP
355 }
356
542563ba 357 p->fd = -1;
49f91047
LP
358
359 if (s->ports) {
360 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
361 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
362 } else
363 LIST_PREPEND(SocketPort, port, s->ports, p);
542563ba 364
16354eff 365 return 0;
42f4e3c4
LP
366}
367
f975e971 368int config_parse_socket_bind(
42f4e3c4
LP
369 const char *filename,
370 unsigned line,
371 const char *section,
372 const char *lvalue,
2b583ce6 373 int ltype,
42f4e3c4
LP
374 const char *rvalue,
375 void *data,
376 void *userdata) {
377
542563ba 378 Socket *s;
c0120d99 379 SocketAddressBindIPv6Only b;
42f4e3c4
LP
380
381 assert(filename);
382 assert(lvalue);
383 assert(rvalue);
384 assert(data);
385
542563ba
LP
386 s = (Socket*) data;
387
c0120d99
LP
388 if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
389 int r;
390
391 if ((r = parse_boolean(rvalue)) < 0) {
c0b34696
LP
392 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
393 return 0;
c0120d99 394 }
42f4e3c4 395
c0120d99
LP
396 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
397 } else
398 s->bind_ipv6_only = b;
542563ba 399
42f4e3c4
LP
400 return 0;
401}
402
f975e971 403int config_parse_exec_nice(
034c6ed7
LP
404 const char *filename,
405 unsigned line,
406 const char *section,
407 const char *lvalue,
2b583ce6 408 int ltype,
034c6ed7
LP
409 const char *rvalue,
410 void *data,
411 void *userdata) {
412
fb33a393 413 ExecContext *c = data;
bd40a2d8 414 int priority;
034c6ed7
LP
415
416 assert(filename);
417 assert(lvalue);
418 assert(rvalue);
419 assert(data);
420
bd40a2d8 421 if (safe_atoi(rvalue, &priority) < 0) {
c0b34696
LP
422 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
423 return 0;
034c6ed7
LP
424 }
425
426 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
c0b34696
LP
427 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
428 return 0;
034c6ed7
LP
429 }
430
fb33a393 431 c->nice = priority;
71155933 432 c->nice_set = true;
fb33a393 433
034c6ed7
LP
434 return 0;
435}
436
f975e971 437int config_parse_exec_oom_score_adjust(
034c6ed7
LP
438 const char *filename,
439 unsigned line,
440 const char *section,
441 const char *lvalue,
2b583ce6 442 int ltype,
034c6ed7
LP
443 const char *rvalue,
444 void *data,
445 void *userdata) {
446
fb33a393 447 ExecContext *c = data;
bd40a2d8 448 int oa;
034c6ed7
LP
449
450 assert(filename);
451 assert(lvalue);
452 assert(rvalue);
453 assert(data);
454
bd40a2d8 455 if (safe_atoi(rvalue, &oa) < 0) {
dd6c17b1 456 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
c0b34696 457 return 0;
034c6ed7
LP
458 }
459
dd6c17b1
LP
460 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
461 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
c0b34696 462 return 0;
034c6ed7
LP
463 }
464
dd6c17b1
LP
465 c->oom_score_adjust = oa;
466 c->oom_score_adjust_set = true;
fb33a393 467
034c6ed7
LP
468 return 0;
469}
470
f975e971 471int config_parse_exec(
034c6ed7
LP
472 const char *filename,
473 unsigned line,
474 const char *section,
475 const char *lvalue,
2b583ce6 476 int ltype,
034c6ed7
LP
477 const char *rvalue,
478 void *data,
479 void *userdata) {
480
61e5d8ed
LP
481 ExecCommand **e = data, *nce;
482 char *path, **n;
034c6ed7 483 unsigned k;
034c6ed7
LP
484
485 assert(filename);
486 assert(lvalue);
487 assert(rvalue);
61e5d8ed 488 assert(e);
034c6ed7 489
6c666e26
LP
490 /* We accept an absolute path as first argument, or
491 * alternatively an absolute prefixed with @ to allow
492 * overriding of argv[0]. */
493
f975e971
LP
494 e += ltype;
495
61e5d8ed
LP
496 for (;;) {
497 char *w;
498 size_t l;
499 char *state;
b708e7ce 500 bool honour_argv0 = false, ignore = false;
6c666e26 501
61e5d8ed
LP
502 path = NULL;
503 nce = NULL;
504 n = NULL;
6c666e26 505
61e5d8ed 506 rvalue += strspn(rvalue, WHITESPACE);
034c6ed7 507
61e5d8ed
LP
508 if (rvalue[0] == 0)
509 break;
034c6ed7 510
b708e7ce
LP
511 if (rvalue[0] == '-') {
512 ignore = true;
513 rvalue ++;
514 }
515
516 if (rvalue[0] == '@') {
517 honour_argv0 = true;
518 rvalue ++;
519 }
61e5d8ed 520
b708e7ce 521 if (*rvalue != '/') {
c0b34696
LP
522 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
523 return 0;
6c666e26 524 }
034c6ed7 525
61e5d8ed
LP
526 k = 0;
527 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
f90cf44c 528 if (strncmp(w, ";", MAX(l, 1U)) == 0)
61e5d8ed 529 break;
034c6ed7 530
61e5d8ed
LP
531 k++;
532 }
034c6ed7 533
b708e7ce 534 if (!(n = new(char*, k + !honour_argv0)))
61e5d8ed
LP
535 return -ENOMEM;
536
537 k = 0;
61e5d8ed 538 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
f90cf44c 539 if (strncmp(w, ";", MAX(l, 1U)) == 0)
61e5d8ed
LP
540 break;
541
b708e7ce
LP
542 if (honour_argv0 && w == rvalue) {
543 assert(!path);
544 if (!(path = cunescape_length(w, l)))
61e5d8ed 545 goto fail;
61e5d8ed
LP
546 } else {
547 if (!(n[k++] = cunescape_length(w, l)))
548 goto fail;
549 }
550 }
551
552 n[k] = NULL;
553
554 if (!n[0]) {
c0b34696 555 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
61e5d8ed 556 strv_free(n);
c0b34696 557 return 0;
61e5d8ed
LP
558 }
559
560 if (!path)
561 if (!(path = strdup(n[0])))
562 goto fail;
6c666e26 563
61e5d8ed 564 assert(path_is_absolute(path));
6c666e26 565
61e5d8ed
LP
566 if (!(nce = new0(ExecCommand, 1)))
567 goto fail;
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
588 return -ENOMEM;
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
f975e971 594int config_parse_socket_bindtodevice(
acbb0225
LP
595 const char *filename,
596 unsigned line,
597 const char *section,
598 const char *lvalue,
2b583ce6 599 int ltype,
acbb0225
LP
600 const char *rvalue,
601 void *data,
602 void *userdata) {
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, "*")) {
613 if (!(n = strdup(rvalue)))
614 return -ENOMEM;
615 } else
616 n = NULL;
617
618 free(s->bind_to_device);
619 s->bind_to_device = n;
620
621 return 0;
622}
623
f975e971
LP
624DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
625DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
87f0e418 626
f975e971 627int config_parse_facility(
071830ff
LP
628 const char *filename,
629 unsigned line,
630 const char *section,
631 const char *lvalue,
2b583ce6 632 int ltype,
071830ff
LP
633 const char *rvalue,
634 void *data,
635 void *userdata) {
636
071830ff 637
94f04347 638 int *o = data, x;
071830ff
LP
639
640 assert(filename);
641 assert(lvalue);
642 assert(rvalue);
643 assert(data);
644
7d76f312 645 if ((x = log_facility_unshifted_from_string(rvalue)) < 0) {
c0b34696
LP
646 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
647 return 0;
0d87eb42 648 }
94f04347 649
7d76f312 650 *o = (x << 3) | LOG_PRI(*o);
071830ff
LP
651
652 return 0;
653}
654
f975e971 655int config_parse_level(
071830ff
LP
656 const char *filename,
657 unsigned line,
658 const char *section,
659 const char *lvalue,
2b583ce6 660 int ltype,
071830ff
LP
661 const char *rvalue,
662 void *data,
663 void *userdata) {
664
071830ff 665
94f04347 666 int *o = data, x;
071830ff
LP
667
668 assert(filename);
669 assert(lvalue);
670 assert(rvalue);
671 assert(data);
672
0d87eb42 673 if ((x = log_level_from_string(rvalue)) < 0) {
c0b34696
LP
674 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
675 return 0;
0d87eb42 676 }
071830ff 677
7d76f312 678 *o = (*o & LOG_FACMASK) | x;
94f04347
LP
679 return 0;
680}
681
f975e971 682int config_parse_exec_io_class(
94f04347
LP
683 const char *filename,
684 unsigned line,
685 const char *section,
686 const char *lvalue,
2b583ce6 687 int ltype,
94f04347
LP
688 const char *rvalue,
689 void *data,
690 void *userdata) {
691
692 ExecContext *c = data;
693 int x;
694
695 assert(filename);
696 assert(lvalue);
697 assert(rvalue);
698 assert(data);
699
0d87eb42 700 if ((x = ioprio_class_from_string(rvalue)) < 0) {
c0b34696
LP
701 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
702 return 0;
0d87eb42 703 }
94f04347
LP
704
705 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
706 c->ioprio_set = true;
707
708 return 0;
709}
710
f975e971 711int config_parse_exec_io_priority(
94f04347
LP
712 const char *filename,
713 unsigned line,
714 const char *section,
715 const char *lvalue,
2b583ce6 716 int ltype,
94f04347
LP
717 const char *rvalue,
718 void *data,
719 void *userdata) {
720
721 ExecContext *c = data;
722 int i;
723
724 assert(filename);
725 assert(lvalue);
726 assert(rvalue);
727 assert(data);
728
729 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
c0b34696
LP
730 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
731 return 0;
071830ff
LP
732 }
733
94f04347
LP
734 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
735 c->ioprio_set = true;
736
071830ff
LP
737 return 0;
738}
739
f975e971 740int config_parse_exec_cpu_sched_policy(
9eba9da4
LP
741 const char *filename,
742 unsigned line,
743 const char *section,
744 const char *lvalue,
2b583ce6 745 int ltype,
9eba9da4
LP
746 const char *rvalue,
747 void *data,
748 void *userdata) {
749
94f04347
LP
750
751 ExecContext *c = data;
752 int x;
753
754 assert(filename);
755 assert(lvalue);
756 assert(rvalue);
757 assert(data);
758
0d87eb42 759 if ((x = sched_policy_from_string(rvalue)) < 0) {
c0b34696
LP
760 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
761 return 0;
0d87eb42 762 }
94f04347
LP
763
764 c->cpu_sched_policy = x;
765 c->cpu_sched_set = true;
766
767 return 0;
768}
769
f975e971 770int config_parse_exec_cpu_sched_prio(
94f04347
LP
771 const char *filename,
772 unsigned line,
773 const char *section,
774 const char *lvalue,
2b583ce6 775 int ltype,
94f04347
LP
776 const char *rvalue,
777 void *data,
778 void *userdata) {
9eba9da4
LP
779
780 ExecContext *c = data;
781 int i;
782
783 assert(filename);
784 assert(lvalue);
785 assert(rvalue);
786 assert(data);
787
94f04347
LP
788 /* On Linux RR/FIFO have the same range */
789 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
c0b34696
LP
790 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
791 return 0;
94f04347 792 }
9eba9da4 793
94f04347
LP
794 c->cpu_sched_priority = i;
795 c->cpu_sched_set = true;
796
797 return 0;
798}
799
f975e971 800int config_parse_exec_cpu_affinity(
94f04347
LP
801 const char *filename,
802 unsigned line,
803 const char *section,
804 const char *lvalue,
2b583ce6 805 int ltype,
94f04347
LP
806 const char *rvalue,
807 void *data,
808 void *userdata) {
809
810 ExecContext *c = data;
811 char *w;
812 size_t l;
813 char *state;
814
815 assert(filename);
816 assert(lvalue);
817 assert(rvalue);
818 assert(data);
819
f60f22df 820 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94f04347
LP
821 char *t;
822 int r;
823 unsigned cpu;
824
825 if (!(t = strndup(w, l)))
826 return -ENOMEM;
827
487393e9
LP
828 r = safe_atou(t, &cpu);
829 free(t);
830
82c121a4
LP
831 if (!(c->cpuset))
832 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
833 return -ENOMEM;
834
82c121a4 835 if (r < 0 || cpu >= c->cpuset_ncpus) {
c0b34696
LP
836 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
837 return 0;
9eba9da4 838 }
94f04347 839
82c121a4 840 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
9eba9da4
LP
841 }
842
94f04347
LP
843 return 0;
844}
845
f975e971 846int config_parse_exec_capabilities(
94f04347
LP
847 const char *filename,
848 unsigned line,
849 const char *section,
850 const char *lvalue,
2b583ce6 851 int ltype,
94f04347
LP
852 const char *rvalue,
853 void *data,
854 void *userdata) {
855
856 ExecContext *c = data;
857 cap_t cap;
858
859 assert(filename);
860 assert(lvalue);
861 assert(rvalue);
862 assert(data);
863
864 if (!(cap = cap_from_text(rvalue))) {
865 if (errno == ENOMEM)
866 return -ENOMEM;
867
c0b34696
LP
868 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
869 return 0;
94f04347
LP
870 }
871
872 if (c->capabilities)
873 cap_free(c->capabilities);
874 c->capabilities = cap;
875
876 return 0;
877}
878
f975e971 879int config_parse_exec_secure_bits(
94f04347
LP
880 const char *filename,
881 unsigned line,
882 const char *section,
883 const char *lvalue,
2b583ce6 884 int ltype,
94f04347
LP
885 const char *rvalue,
886 void *data,
887 void *userdata) {
888
889 ExecContext *c = data;
890 char *w;
891 size_t l;
892 char *state;
893
894 assert(filename);
895 assert(lvalue);
896 assert(rvalue);
897 assert(data);
898
f60f22df 899 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94f04347
LP
900 if (first_word(w, "keep-caps"))
901 c->secure_bits |= SECURE_KEEP_CAPS;
902 else if (first_word(w, "keep-caps-locked"))
903 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
904 else if (first_word(w, "no-setuid-fixup"))
905 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
906 else if (first_word(w, "no-setuid-fixup-locked"))
907 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
908 else if (first_word(w, "noroot"))
909 c->secure_bits |= SECURE_NOROOT;
910 else if (first_word(w, "noroot-locked"))
911 c->secure_bits |= SECURE_NOROOT_LOCKED;
9eba9da4 912 else {
c0b34696
LP
913 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
914 return 0;
9eba9da4
LP
915 }
916 }
917
94f04347
LP
918 return 0;
919}
920
f975e971 921int config_parse_exec_bounding_set(
94f04347
LP
922 const char *filename,
923 unsigned line,
924 const char *section,
925 const char *lvalue,
2b583ce6 926 int ltype,
94f04347
LP
927 const char *rvalue,
928 void *data,
929 void *userdata) {
930
931 ExecContext *c = data;
932 char *w;
933 size_t l;
934 char *state;
260abb78
LP
935 bool invert = false;
936 uint64_t sum = 0;
94f04347
LP
937
938 assert(filename);
939 assert(lvalue);
940 assert(rvalue);
941 assert(data);
942
260abb78
LP
943 if (rvalue[0] == '~') {
944 invert = true;
945 rvalue++;
946 }
947
948 /* Note that we store this inverted internally, since the
949 * kernel wants it like this. But we actually expose it
950 * non-inverted everywhere to have a fully normalized
951 * interface. */
952
f60f22df 953 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94f04347
LP
954 char *t;
955 int r;
956 cap_value_t cap;
957
958 if (!(t = strndup(w, l)))
959 return -ENOMEM;
960
961 r = cap_from_name(t, &cap);
962 free(t);
963
964 if (r < 0) {
c0b34696
LP
965 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
966 return 0;
94f04347
LP
967 }
968
260abb78 969 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
94f04347 970 }
9eba9da4 971
260abb78
LP
972 if (invert)
973 c->capability_bounding_set_drop |= sum;
974 else
975 c->capability_bounding_set_drop |= ~sum;
976
9eba9da4
LP
977 return 0;
978}
979
f975e971 980int config_parse_exec_timer_slack_nsec(
9eba9da4
LP
981 const char *filename,
982 unsigned line,
983 const char *section,
984 const char *lvalue,
2b583ce6 985 int ltype,
9eba9da4
LP
986 const char *rvalue,
987 void *data,
988 void *userdata) {
989
990 ExecContext *c = data;
94f04347 991 unsigned long u;
9eba9da4
LP
992
993 assert(filename);
994 assert(lvalue);
995 assert(rvalue);
996 assert(data);
997
bd40a2d8 998 if (safe_atolu(rvalue, &u) < 0) {
c0b34696
LP
999 log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue);
1000 return 0;
9eba9da4
LP
1001 }
1002
03fae018 1003 c->timer_slack_nsec = u;
94f04347
LP
1004
1005 return 0;
1006}
1007
f975e971 1008int config_parse_limit(
94f04347
LP
1009 const char *filename,
1010 unsigned line,
1011 const char *section,
1012 const char *lvalue,
2b583ce6 1013 int ltype,
94f04347
LP
1014 const char *rvalue,
1015 void *data,
1016 void *userdata) {
1017
1018 struct rlimit **rl = data;
1019 unsigned long long u;
94f04347
LP
1020
1021 assert(filename);
1022 assert(lvalue);
1023 assert(rvalue);
1024 assert(data);
1025
f975e971
LP
1026 rl += ltype;
1027
3d57c6ab
LP
1028 if (streq(rvalue, "infinity"))
1029 u = (unsigned long long) RLIM_INFINITY;
1030 else if (safe_atollu(rvalue, &u) < 0) {
c0b34696
LP
1031 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
1032 return 0;
94f04347
LP
1033 }
1034
1035 if (!*rl)
1036 if (!(*rl = new(struct rlimit, 1)))
1037 return -ENOMEM;
9eba9da4 1038
94f04347 1039 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
9eba9da4
LP
1040 return 0;
1041}
1042
f975e971 1043int config_parse_unit_cgroup(
8e274523
LP
1044 const char *filename,
1045 unsigned line,
1046 const char *section,
1047 const char *lvalue,
2b583ce6 1048 int ltype,
8e274523
LP
1049 const char *rvalue,
1050 void *data,
1051 void *userdata) {
1052
1053 Unit *u = userdata;
1054 char *w;
1055 size_t l;
1056 char *state;
1057
f60f22df 1058 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
f284f69a 1059 char *t, *k;
8e274523
LP
1060 int r;
1061
f284f69a
LP
1062 t = strndup(w, l);
1063 if (!t)
1064 return -ENOMEM;
1065
1066 k = unit_full_printf(u, t);
1067 free(t);
1068
1069 if (!k)
1070 return -ENOMEM;
1071
1072 t = cunescape(k);
1073 free(k);
1074
1075 if (!t)
8e274523
LP
1076 return -ENOMEM;
1077
1078 r = unit_add_cgroup_from_text(u, t);
1079 free(t);
1080
c0b34696
LP
1081 if (r < 0) {
1082 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
1083 return 0;
1084 }
8e274523
LP
1085 }
1086
1087 return 0;
1088}
1089
07459bb6 1090#ifdef HAVE_SYSV_COMPAT
f975e971 1091int config_parse_sysv_priority(
a9a1e00a
LP
1092 const char *filename,
1093 unsigned line,
1094 const char *section,
1095 const char *lvalue,
2b583ce6 1096 int ltype,
a9a1e00a
LP
1097 const char *rvalue,
1098 void *data,
1099 void *userdata) {
1100
1101 int *priority = data;
bd40a2d8 1102 int i;
a9a1e00a
LP
1103
1104 assert(filename);
1105 assert(lvalue);
1106 assert(rvalue);
1107 assert(data);
1108
bd40a2d8 1109 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
c0b34696
LP
1110 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1111 return 0;
a9a1e00a
LP
1112 }
1113
1114 *priority = (int) i;
1115 return 0;
1116}
07459bb6 1117#endif
a9a1e00a 1118
f975e971 1119int config_parse_fsck_passno(
2ba545f1
LP
1120 const char *filename,
1121 unsigned line,
1122 const char *section,
1123 const char *lvalue,
2b583ce6 1124 int ltype,
2ba545f1
LP
1125 const char *rvalue,
1126 void *data,
1127 void *userdata) {
1128
1129 int *passno = data;
bd40a2d8 1130 int i;
2ba545f1
LP
1131
1132 assert(filename);
1133 assert(lvalue);
1134 assert(rvalue);
1135 assert(data);
1136
bd40a2d8 1137 if (safe_atoi(rvalue, &i) || i < 0) {
2ba545f1
LP
1138 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1139 return 0;
1140 }
1141
1142 *passno = (int) i;
1143 return 0;
1144}
1145
f975e971 1146DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
50159e6a 1147
f975e971 1148int config_parse_kill_signal(
2e22afe9
LP
1149 const char *filename,
1150 unsigned line,
1151 const char *section,
1152 const char *lvalue,
2b583ce6 1153 int ltype,
2e22afe9
LP
1154 const char *rvalue,
1155 void *data,
1156 void *userdata) {
1157
1158 int *sig = data;
1159 int r;
1160
1161 assert(filename);
1162 assert(lvalue);
1163 assert(rvalue);
1164 assert(sig);
1165
8a0867d6 1166 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
c0b34696
LP
1167 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1168 return 0;
2e22afe9
LP
1169 }
1170
1171 *sig = r;
1172 return 0;
1173}
1174
f975e971 1175int config_parse_exec_mount_flags(
15ae422b
LP
1176 const char *filename,
1177 unsigned line,
1178 const char *section,
1179 const char *lvalue,
2b583ce6 1180 int ltype,
15ae422b
LP
1181 const char *rvalue,
1182 void *data,
1183 void *userdata) {
1184
1185 ExecContext *c = data;
1186 char *w;
1187 size_t l;
1188 char *state;
1189 unsigned long flags = 0;
1190
1191 assert(filename);
1192 assert(lvalue);
1193 assert(rvalue);
1194 assert(data);
1195
f60f22df 1196 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
f90cf44c 1197 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
15ae422b 1198 flags |= MS_SHARED;
f90cf44c 1199 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
15ae422b 1200 flags |= MS_SLAVE;
f90cf44c 1201 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
15ae422b
LP
1202 flags |= MS_PRIVATE;
1203 else {
c0b34696
LP
1204 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1205 return 0;
15ae422b
LP
1206 }
1207 }
1208
1209 c->mount_flags = flags;
1210 return 0;
1211}
1212
f975e971 1213int config_parse_timer(
871d7de4
LP
1214 const char *filename,
1215 unsigned line,
1216 const char *section,
1217 const char *lvalue,
2b583ce6 1218 int ltype,
871d7de4
LP
1219 const char *rvalue,
1220 void *data,
1221 void *userdata) {
1222
1223 Timer *t = data;
1224 usec_t u;
871d7de4
LP
1225 TimerValue *v;
1226 TimerBase b;
1227
1228 assert(filename);
1229 assert(lvalue);
1230 assert(rvalue);
1231 assert(data);
1232
1233 if ((b = timer_base_from_string(lvalue)) < 0) {
c0b34696
LP
1234 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1235 return 0;
871d7de4
LP
1236 }
1237
bd40a2d8 1238 if (parse_usec(rvalue, &u) < 0) {
c0b34696
LP
1239 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1240 return 0;
871d7de4
LP
1241 }
1242
1243 if (!(v = new0(TimerValue, 1)))
1244 return -ENOMEM;
1245
1246 v->base = b;
1247 v->value = u;
1248
1249 LIST_PREPEND(TimerValue, value, t->values, v);
1250
1251 return 0;
1252}
1253
f975e971 1254int config_parse_timer_unit(
871d7de4
LP
1255 const char *filename,
1256 unsigned line,
1257 const char *section,
1258 const char *lvalue,
2b583ce6 1259 int ltype,
871d7de4
LP
1260 const char *rvalue,
1261 void *data,
1262 void *userdata) {
1263
1264 Timer *t = data;
1265 int r;
398ef8ba
LP
1266 DBusError error;
1267
1268 assert(filename);
1269 assert(lvalue);
1270 assert(rvalue);
1271 assert(data);
1272
1273 dbus_error_init(&error);
871d7de4
LP
1274
1275 if (endswith(rvalue, ".timer")) {
c0b34696
LP
1276 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1277 return 0;
871d7de4
LP
1278 }
1279
398ef8ba 1280 if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, NULL, &t->unit)) < 0) {
c0b34696 1281 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
398ef8ba 1282 dbus_error_free(&error);
c0b34696 1283 return 0;
871d7de4
LP
1284 }
1285
1286 return 0;
1287}
1288
f975e971 1289int config_parse_path_spec(
01f78473
LP
1290 const char *filename,
1291 unsigned line,
1292 const char *section,
1293 const char *lvalue,
2b583ce6 1294 int ltype,
01f78473
LP
1295 const char *rvalue,
1296 void *data,
1297 void *userdata) {
1298
1299 Path *p = data;
1300 PathSpec *s;
1301 PathType b;
1302
1303 assert(filename);
1304 assert(lvalue);
1305 assert(rvalue);
1306 assert(data);
1307
1308 if ((b = path_type_from_string(lvalue)) < 0) {
c0b34696
LP
1309 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1310 return 0;
01f78473
LP
1311 }
1312
1313 if (!path_is_absolute(rvalue)) {
c0b34696
LP
1314 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1315 return 0;
01f78473
LP
1316 }
1317
1318 if (!(s = new0(PathSpec, 1)))
1319 return -ENOMEM;
1320
1321 if (!(s->path = strdup(rvalue))) {
1322 free(s);
1323 return -ENOMEM;
1324 }
1325
1326 path_kill_slashes(s->path);
1327
1328 s->type = b;
1329 s->inotify_fd = -1;
1330
1331 LIST_PREPEND(PathSpec, spec, p->specs, s);
1332
1333 return 0;
1334}
1335
f975e971 1336int config_parse_path_unit(
01f78473
LP
1337 const char *filename,
1338 unsigned line,
1339 const char *section,
1340 const char *lvalue,
2b583ce6 1341 int ltype,
01f78473
LP
1342 const char *rvalue,
1343 void *data,
1344 void *userdata) {
1345
1346 Path *t = data;
1347 int r;
398ef8ba
LP
1348 DBusError error;
1349
1350 assert(filename);
1351 assert(lvalue);
1352 assert(rvalue);
1353 assert(data);
1354
1355 dbus_error_init(&error);
01f78473
LP
1356
1357 if (endswith(rvalue, ".path")) {
c0b34696
LP
1358 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1359 return 0;
01f78473
LP
1360 }
1361
398ef8ba 1362 if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &error, &t->unit)) < 0) {
c0b34696 1363 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
398ef8ba 1364 dbus_error_free(&error);
c0b34696 1365 return 0;
01f78473
LP
1366 }
1367
1368 return 0;
1369}
1370
f975e971 1371int config_parse_socket_service(
d9ff321a
LP
1372 const char *filename,
1373 unsigned line,
1374 const char *section,
1375 const char *lvalue,
2b583ce6 1376 int ltype,
d9ff321a
LP
1377 const char *rvalue,
1378 void *data,
1379 void *userdata) {
1380
1381 Socket *s = data;
1382 int r;
1383 DBusError error;
1384
1385 assert(filename);
1386 assert(lvalue);
1387 assert(rvalue);
1388 assert(data);
1389
1390 dbus_error_init(&error);
1391
f976f3f6
LP
1392 if (!endswith(rvalue, ".service")) {
1393 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
d9ff321a
LP
1394 return 0;
1395 }
1396
1397 if ((r = manager_load_unit(s->meta.manager, rvalue, NULL, &error, (Unit**) &s->service)) < 0) {
1398 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1399 dbus_error_free(&error);
1400 return 0;
1401 }
1402
1403 return 0;
1404}
1405
f975e971 1406int config_parse_service_sockets(
f976f3f6
LP
1407 const char *filename,
1408 unsigned line,
1409 const char *section,
1410 const char *lvalue,
2b583ce6 1411 int ltype,
f976f3f6
LP
1412 const char *rvalue,
1413 void *data,
1414 void *userdata) {
1415
1416 Service *s = data;
1417 int r;
1418 DBusError error;
1419 char *state, *w;
1420 size_t l;
1421
1422 assert(filename);
1423 assert(lvalue);
1424 assert(rvalue);
1425 assert(data);
1426
1427 dbus_error_init(&error);
1428
1429 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1430 char *t;
1431 Unit *sock;
1432
1433 if (!(t = strndup(w, l)))
1434 return -ENOMEM;
1435
1436 if (!endswith(t, ".socket")) {
1437 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1438 free(t);
1439 continue;
1440 }
1441
1442 r = manager_load_unit(s->meta.manager, t, NULL, &error, &sock);
1443 free(t);
1444
1445 if (r < 0) {
1446 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1447 dbus_error_free(&error);
1448 continue;
1449 }
1450
1451 if ((r = set_ensure_allocated(&s->configured_sockets, trivial_hash_func, trivial_compare_func)) < 0)
1452 return r;
1453
1454 if ((r = set_put(s->configured_sockets, sock)) < 0)
1455 return r;
1456 }
1457
1458 return 0;
1459}
1460
f975e971 1461int config_parse_unit_env_file(
ddb26e18
LP
1462 const char *filename,
1463 unsigned line,
1464 const char *section,
1465 const char *lvalue,
2b583ce6 1466 int ltype,
ddb26e18
LP
1467 const char *rvalue,
1468 void *data,
1469 void *userdata) {
1470
8c7be95e 1471 char ***env = data, **k;
8fef7659
LP
1472 Unit *u = userdata;
1473 char *s;
ddb26e18
LP
1474
1475 assert(filename);
1476 assert(lvalue);
1477 assert(rvalue);
1478 assert(data);
1479
8fef7659
LP
1480 s = unit_full_printf(u, rvalue);
1481 if (!s)
1482 return -ENOMEM;
1483
1484 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1485 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1486 free(s);
afe4bfe2
LP
1487 return 0;
1488 }
1489
8fef7659
LP
1490 k = strv_append(*env, s);
1491 free(s);
1492 if (!k)
8c7be95e 1493 return -ENOMEM;
ddb26e18 1494
8c7be95e
LP
1495 strv_free(*env);
1496 *env = k;
ddb26e18 1497
8c7be95e 1498 return 0;
ddb26e18
LP
1499}
1500
f975e971 1501int config_parse_ip_tos(
4fd5948e
LP
1502 const char *filename,
1503 unsigned line,
1504 const char *section,
1505 const char *lvalue,
2b583ce6 1506 int ltype,
4fd5948e
LP
1507 const char *rvalue,
1508 void *data,
1509 void *userdata) {
1510
1511 int *ip_tos = data, x;
4fd5948e
LP
1512
1513 assert(filename);
1514 assert(lvalue);
1515 assert(rvalue);
1516 assert(data);
1517
1518 if ((x = ip_tos_from_string(rvalue)) < 0)
bd40a2d8 1519 if (safe_atoi(rvalue, &x) < 0) {
c0b34696
LP
1520 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1521 return 0;
4fd5948e
LP
1522 }
1523
1524 *ip_tos = x;
1525 return 0;
1526}
1527
f975e971 1528int config_parse_unit_condition_path(
52661efd
LP
1529 const char *filename,
1530 unsigned line,
1531 const char *section,
1532 const char *lvalue,
2b583ce6 1533 int ltype,
52661efd
LP
1534 const char *rvalue,
1535 void *data,
1536 void *userdata) {
1537
2b583ce6 1538 ConditionType cond = ltype;
52661efd 1539 Unit *u = data;
267632f0 1540 bool trigger, negate;
52661efd
LP
1541 Condition *c;
1542
1543 assert(filename);
1544 assert(lvalue);
1545 assert(rvalue);
1546 assert(data);
1547
267632f0
LP
1548 if ((trigger = rvalue[0] == '|'))
1549 rvalue++;
1550
52661efd
LP
1551 if ((negate = rvalue[0] == '!'))
1552 rvalue++;
1553
1554 if (!path_is_absolute(rvalue)) {
d257ddef 1555 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
52661efd
LP
1556 return 0;
1557 }
1558
2b583ce6 1559 if (!(c = condition_new(cond, rvalue, trigger, negate)))
52661efd
LP
1560 return -ENOMEM;
1561
1562 LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
1563 return 0;
1564}
1565
f975e971 1566int config_parse_unit_condition_string(
039655a4
LP
1567 const char *filename,
1568 unsigned line,
1569 const char *section,
1570 const char *lvalue,
2b583ce6 1571 int ltype,
039655a4
LP
1572 const char *rvalue,
1573 void *data,
1574 void *userdata) {
1575
41584525 1576 ConditionType cond = ltype;
039655a4 1577 Unit *u = data;
267632f0 1578 bool trigger, negate;
039655a4
LP
1579 Condition *c;
1580
1581 assert(filename);
1582 assert(lvalue);
1583 assert(rvalue);
1584 assert(data);
1585
267632f0
LP
1586 if ((trigger = rvalue[0] == '|'))
1587 rvalue++;
1588
039655a4
LP
1589 if ((negate = rvalue[0] == '!'))
1590 rvalue++;
1591
41584525 1592 if (!(c = condition_new(cond, rvalue, trigger, negate)))
039655a4
LP
1593 return -ENOMEM;
1594
1595 LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
1596 return 0;
1597}
1598
f975e971 1599int config_parse_unit_condition_null(
d257ddef
LP
1600 const char *filename,
1601 unsigned line,
1602 const char *section,
1603 const char *lvalue,
2b583ce6 1604 int ltype,
d257ddef
LP
1605 const char *rvalue,
1606 void *data,
1607 void *userdata) {
1608
1609 Unit *u = data;
1610 Condition *c;
267632f0 1611 bool trigger, negate;
d257ddef
LP
1612 int b;
1613
1614 assert(filename);
1615 assert(lvalue);
1616 assert(rvalue);
1617 assert(data);
1618
267632f0
LP
1619 if ((trigger = rvalue[0] == '|'))
1620 rvalue++;
1621
d257ddef
LP
1622 if ((negate = rvalue[0] == '!'))
1623 rvalue++;
1624
1625 if ((b = parse_boolean(rvalue)) < 0) {
1626 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1627 return 0;
1628 }
1629
1630 if (!b)
1631 negate = !negate;
1632
267632f0 1633 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
d257ddef
LP
1634 return -ENOMEM;
1635
1636 LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
1637 return 0;
1638}
1639
f975e971 1640DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
c952c6ec 1641
071830ff 1642#define FOLLOW_MAX 8
87f0e418 1643
9e2f7c11 1644static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
0301abf4 1645 unsigned c = 0;
87f0e418
LP
1646 int fd, r;
1647 FILE *f;
0301abf4 1648 char *id = NULL;
87f0e418
LP
1649
1650 assert(filename);
1651 assert(*filename);
1652 assert(_f);
1653 assert(names);
1654
0301abf4
LP
1655 /* This will update the filename pointer if the loaded file is
1656 * reached by a symlink. The old string will be freed. */
87f0e418 1657
0301abf4 1658 for (;;) {
2c7108c4 1659 char *target, *name;
87f0e418 1660
0301abf4
LP
1661 if (c++ >= FOLLOW_MAX)
1662 return -ELOOP;
1663
b08d03ff
LP
1664 path_kill_slashes(*filename);
1665
87f0e418 1666 /* Add the file name we are currently looking at to
8f05424d
LP
1667 * the names of this unit, but only if it is a valid
1668 * unit name. */
0301abf4 1669 name = file_name_from_path(*filename);
87f0e418 1670
15e11d81 1671 if (unit_name_is_valid(name, true)) {
8f05424d 1672
15e11d81
LP
1673 id = set_get(names, name);
1674 if (!id) {
1675 id = strdup(name);
1676 if (!id)
8f05424d 1677 return -ENOMEM;
87f0e418 1678
15e11d81
LP
1679 r = set_put(names, id);
1680 if (r < 0) {
8f05424d
LP
1681 free(id);
1682 return r;
1683 }
87f0e418 1684 }
87f0e418
LP
1685 }
1686
0301abf4
LP
1687 /* Try to open the file name, but don't if its a symlink */
1688 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
87f0e418
LP
1689 break;
1690
0301abf4
LP
1691 if (errno != ELOOP)
1692 return -errno;
1693
87f0e418 1694 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2c7108c4 1695 if ((r = readlink_and_make_absolute(*filename, &target)) < 0)
0301abf4 1696 return r;
87f0e418 1697
0301abf4 1698 free(*filename);
2c7108c4 1699 *filename = target;
87f0e418
LP
1700 }
1701
8f05424d 1702 if (!(f = fdopen(fd, "re"))) {
87f0e418 1703 r = -errno;
9e2f7c11 1704 close_nointr_nofail(fd);
0301abf4 1705 return r;
87f0e418
LP
1706 }
1707
1708 *_f = f;
9e2f7c11 1709 *_final = id;
0301abf4 1710 return 0;
87f0e418
LP
1711}
1712
23a177ef
LP
1713static int merge_by_names(Unit **u, Set *names, const char *id) {
1714 char *k;
1715 int r;
1716
1717 assert(u);
1718 assert(*u);
1719 assert(names);
1720
1721 /* Let's try to add in all symlink names we found */
1722 while ((k = set_steal_first(names))) {
1723
1724 /* First try to merge in the other name into our
1725 * unit */
1726 if ((r = unit_merge_by_name(*u, k)) < 0) {
1727 Unit *other;
1728
1729 /* Hmm, we couldn't merge the other unit into
1730 * ours? Then let's try it the other way
1731 * round */
1732
1733 other = manager_get_unit((*u)->meta.manager, k);
1734 free(k);
1735
1736 if (other)
1737 if ((r = unit_merge(other, *u)) >= 0) {
1738 *u = other;
1739 return merge_by_names(u, names, NULL);
1740 }
1741
1742 return r;
1743 }
1744
1745 if (id == k)
1746 unit_choose_id(*u, id);
1747
1748 free(k);
1749 }
1750
1751 return 0;
1752}
1753
e537352b 1754static int load_from_path(Unit *u, const char *path) {
0301abf4 1755 int r;
87f0e418 1756 Set *symlink_names;
23a177ef
LP
1757 FILE *f = NULL;
1758 char *filename = NULL, *id = NULL;
1759 Unit *merged;
45fb0699 1760 struct stat st;
23a177ef
LP
1761
1762 assert(u);
e537352b 1763 assert(path);
3efd4195 1764
f975e971
LP
1765 symlink_names = set_new(string_hash_func, string_compare_func);
1766 if (!symlink_names)
87f0e418 1767 return -ENOMEM;
3efd4195 1768
036643a2
LP
1769 if (path_is_absolute(path)) {
1770
1771 if (!(filename = strdup(path))) {
1772 r = -ENOMEM;
1773 goto finish;
1774 }
1775
1776 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
1777 free(filename);
1778 filename = NULL;
1779
1780 if (r != -ENOENT)
1781 goto finish;
1782 }
1783
1784 } else {
1785 char **p;
1786
84e3543e 1787 STRV_FOREACH(p, u->meta.manager->lookup_paths.unit_path) {
036643a2
LP
1788
1789 /* Instead of opening the path right away, we manually
1790 * follow all symlinks and add their name to our unit
1791 * name set while doing so */
1792 if (!(filename = path_make_absolute(path, *p))) {
1793 r = -ENOMEM;
1794 goto finish;
1795 }
1796
fe51822e
LP
1797 if (u->meta.manager->unit_path_cache &&
1798 !set_get(u->meta.manager->unit_path_cache, filename))
1799 r = -ENOENT;
1800 else
1801 r = open_follow(&filename, &f, symlink_names, &id);
1802
1803 if (r < 0) {
036643a2
LP
1804 char *sn;
1805
1806 free(filename);
1807 filename = NULL;
1808
1809 if (r != -ENOENT)
1810 goto finish;
1811
1812 /* Empty the symlink names for the next run */
1813 while ((sn = set_steal_first(symlink_names)))
1814 free(sn);
3efd4195 1815
036643a2
LP
1816 continue;
1817 }
1818
1819 break;
1820 }
1821 }
034c6ed7 1822
036643a2 1823 if (!filename) {
8f05424d 1824 /* Hmm, no suitable file found? */
23a177ef 1825 r = 0;
0301abf4
LP
1826 goto finish;
1827 }
87f0e418 1828
23a177ef
LP
1829 merged = u;
1830 if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
0301abf4 1831 goto finish;
87f0e418 1832
23a177ef 1833 if (merged != u) {
e537352b 1834 u->meta.load_state = UNIT_MERGED;
23a177ef
LP
1835 r = 0;
1836 goto finish;
034c6ed7
LP
1837 }
1838
45fb0699
LP
1839 zero(st);
1840 if (fstat(fileno(f), &st) < 0) {
1841 r = -errno;
1842 goto finish;
1843 }
1844
00dc5d76 1845 if (null_or_empty(&st))
6daf4f90 1846 u->meta.load_state = UNIT_MASKED;
00dc5d76
LP
1847 else {
1848 /* Now, parse the file contents */
f975e971
LP
1849 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
1850 if (r < 0)
00dc5d76
LP
1851 goto finish;
1852
1853 u->meta.load_state = UNIT_LOADED;
1854 }
b08d03ff 1855
6be1e7d5
LP
1856 free(u->meta.fragment_path);
1857 u->meta.fragment_path = filename;
0301abf4 1858 filename = NULL;
87f0e418 1859
45fb0699
LP
1860 u->meta.fragment_mtime = timespec_load(&st.st_mtim);
1861
23a177ef 1862 r = 0;
87f0e418
LP
1863
1864finish:
53ec43c6 1865 set_free_free(symlink_names);
0301abf4
LP
1866 free(filename);
1867
23a177ef
LP
1868 if (f)
1869 fclose(f);
1870
0301abf4
LP
1871 return r;
1872}
1873
e537352b 1874int unit_load_fragment(Unit *u) {
23a177ef 1875 int r;
294d81f1
LP
1876 Iterator i;
1877 const char *t;
0301abf4
LP
1878
1879 assert(u);
294d81f1
LP
1880 assert(u->meta.load_state == UNIT_STUB);
1881 assert(u->meta.id);
23a177ef 1882
294d81f1
LP
1883 /* First, try to find the unit under its id. We always look
1884 * for unit files in the default directories, to make it easy
1885 * to override things by placing things in /etc/systemd/system */
1886 if ((r = load_from_path(u, u->meta.id)) < 0)
1887 return r;
1888
1889 /* Try to find an alias we can load this with */
1890 if (u->meta.load_state == UNIT_STUB)
1891 SET_FOREACH(t, u->meta.names, i) {
1892
1893 if (t == u->meta.id)
1894 continue;
1895
1896 if ((r = load_from_path(u, t)) < 0)
1897 return r;
1898
1899 if (u->meta.load_state != UNIT_STUB)
1900 break;
1901 }
23a177ef 1902
294d81f1 1903 /* And now, try looking for it under the suggested (originally linked) path */
6ccb1b44
LP
1904 if (u->meta.load_state == UNIT_STUB && u->meta.fragment_path) {
1905
e537352b 1906 if ((r = load_from_path(u, u->meta.fragment_path)) < 0)
23a177ef 1907 return r;
0301abf4 1908
6ccb1b44
LP
1909 if (u->meta.load_state == UNIT_STUB) {
1910 /* Hmm, this didn't work? Then let's get rid
1911 * of the fragment path stored for us, so that
1912 * we don't point to an invalid location. */
1913 free(u->meta.fragment_path);
1914 u->meta.fragment_path = NULL;
1915 }
1916 }
1917
294d81f1
LP
1918 /* Look for a template */
1919 if (u->meta.load_state == UNIT_STUB && u->meta.instance) {
1920 char *k;
1921
1922 if (!(k = unit_name_template(u->meta.id)))
1923 return -ENOMEM;
1924
1925 r = load_from_path(u, k);
1926 free(k);
0301abf4 1927
294d81f1 1928 if (r < 0)
9e2f7c11 1929 return r;
890f434c 1930
e537352b 1931 if (u->meta.load_state == UNIT_STUB)
23a177ef 1932 SET_FOREACH(t, u->meta.names, i) {
87f0e418 1933
9e2f7c11 1934 if (t == u->meta.id)
23a177ef 1935 continue;
071830ff 1936
294d81f1
LP
1937 if (!(k = unit_name_template(t)))
1938 return -ENOMEM;
1939
1940 r = load_from_path(u, k);
1941 free(k);
1942
1943 if (r < 0)
23a177ef 1944 return r;
890f434c 1945
e537352b 1946 if (u->meta.load_state != UNIT_STUB)
23a177ef
LP
1947 break;
1948 }
071830ff
LP
1949 }
1950
23a177ef 1951 return 0;
3efd4195 1952}
e537352b
LP
1953
1954void unit_dump_config_items(FILE *f) {
f975e971
LP
1955 static const struct {
1956 const ConfigParserCallback callback;
1957 const char *rvalue;
1958 } table[] = {
1959 { config_parse_int, "INTEGER" },
1960 { config_parse_unsigned, "UNSIGNED" },
1961 { config_parse_size, "SIZE" },
1962 { config_parse_bool, "BOOLEAN" },
1963 { config_parse_string, "STRING" },
1964 { config_parse_path, "PATH" },
1965 { config_parse_unit_path_printf, "PATH" },
1966 { config_parse_strv, "STRING [...]" },
1967 { config_parse_exec_nice, "NICE" },
1968 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
1969 { config_parse_exec_io_class, "IOCLASS" },
1970 { config_parse_exec_io_priority, "IOPRIORITY" },
1971 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
1972 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
1973 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
1974 { config_parse_mode, "MODE" },
1975 { config_parse_unit_env_file, "FILE" },
1976 { config_parse_output, "OUTPUT" },
1977 { config_parse_input, "INPUT" },
1978 { config_parse_facility, "FACILITY" },
1979 { config_parse_level, "LEVEL" },
1980 { config_parse_exec_capabilities, "CAPABILITIES" },
1981 { config_parse_exec_secure_bits, "SECUREBITS" },
1982 { config_parse_exec_bounding_set, "BOUNDINGSET" },
1983 { config_parse_exec_timer_slack_nsec, "TIMERSLACK" },
1984 { config_parse_limit, "LIMIT" },
1985 { config_parse_unit_cgroup, "CGROUP [...]" },
1986 { config_parse_unit_deps, "UNIT [...]" },
1987 { config_parse_unit_names, "UNIT [...]" },
1988 { config_parse_exec, "PATH [ARGUMENT [...]]" },
1989 { config_parse_service_type, "SERVICETYPE" },
1990 { config_parse_service_restart, "SERVICERESTART" },
1991#ifdef HAVE_SYSV_COMPAT
1992 { config_parse_sysv_priority, "SYSVPRIORITY" },
1993#else
1994 { config_parse_warn_compat, "NOTSUPPORTED" },
1995#endif
1996 { config_parse_kill_mode, "KILLMODE" },
1997 { config_parse_kill_signal, "SIGNAL" },
1998 { config_parse_socket_listen, "SOCKET [...]" },
1999 { config_parse_socket_bind, "SOCKETBIND" },
2000 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2001 { config_parse_usec, "SECONDS" },
2002 { config_parse_path_strv, "PATH [...]" },
2003 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2004 { config_parse_unit_string_printf, "STRING" },
2005 { config_parse_timer, "TIMER" },
2006 { config_parse_timer_unit, "NAME" },
2007 { config_parse_path_spec, "PATH" },
2008 { config_parse_path_unit, "UNIT" },
2009 { config_parse_notify_access, "ACCESS" },
2010 { config_parse_ip_tos, "TOS" },
2011 { config_parse_unit_condition_path, "CONDITION" },
2012 { config_parse_unit_condition_string, "CONDITION" },
2013 { config_parse_unit_condition_null, "CONDITION" },
2014 };
2015
2016 const char *prev = NULL;
2017 const char *i;
2018
2019 assert(f);
e537352b 2020
f975e971
LP
2021 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2022 const char *rvalue = "OTHER", *lvalue;
2023 unsigned j;
2024 size_t prefix_len;
2025 const char *dot;
2026 const ConfigPerfItem *p;
2027
2028 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2029
2030 dot = strchr(i, '.');
2031 lvalue = dot ? dot + 1 : i;
2032 prefix_len = dot-i;
2033
2034 if (dot)
2035 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2036 if (prev)
2037 fputc('\n', f);
2038
2039 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2040 }
2041
2042 for (j = 0; j < ELEMENTSOF(table); j++)
2043 if (p->parse == table[j].callback) {
2044 rvalue = table[j].rvalue;
2045 break;
2046 }
2047
2048 fprintf(f, "%s=%s\n", lvalue, rvalue);
2049 prev = i;
2050 }
e537352b 2051}