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