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