]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
systemd: introduced new timeout types
[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
267632f0
LP
1519 if ((trigger = rvalue[0] == '|'))
1520 rvalue++;
1521
039655a4
LP
1522 if ((negate = rvalue[0] == '!'))
1523 rvalue++;
1524
41584525 1525 if (!(c = condition_new(cond, rvalue, trigger, negate)))
039655a4
LP
1526 return -ENOMEM;
1527
ac155bb8 1528 LIST_PREPEND(Condition, conditions, u->conditions, c);
039655a4
LP
1529 return 0;
1530}
1531
f975e971 1532int config_parse_unit_condition_null(
d257ddef
LP
1533 const char *filename,
1534 unsigned line,
1535 const char *section,
1536 const char *lvalue,
2b583ce6 1537 int ltype,
d257ddef
LP
1538 const char *rvalue,
1539 void *data,
1540 void *userdata) {
1541
1542 Unit *u = data;
1543 Condition *c;
267632f0 1544 bool trigger, negate;
d257ddef
LP
1545 int b;
1546
1547 assert(filename);
1548 assert(lvalue);
1549 assert(rvalue);
1550 assert(data);
1551
267632f0
LP
1552 if ((trigger = rvalue[0] == '|'))
1553 rvalue++;
1554
d257ddef
LP
1555 if ((negate = rvalue[0] == '!'))
1556 rvalue++;
1557
1558 if ((b = parse_boolean(rvalue)) < 0) {
1559 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1560 return 0;
1561 }
1562
1563 if (!b)
1564 negate = !negate;
1565
267632f0 1566 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
d257ddef
LP
1567 return -ENOMEM;
1568
ac155bb8 1569 LIST_PREPEND(Condition, conditions, u->conditions, c);
d257ddef
LP
1570 return 0;
1571}
1572
f975e971 1573DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
4b939747 1574DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
c952c6ec 1575
ab1f0633
LP
1576int config_parse_unit_cgroup_attr(
1577 const char *filename,
1578 unsigned line,
1579 const char *section,
1580 const char *lvalue,
1581 int ltype,
1582 const char *rvalue,
1583 void *data,
1584 void *userdata) {
1585
1586 Unit *u = data;
1587 char **l;
1588 int r;
1589
1590 assert(filename);
1591 assert(lvalue);
1592 assert(rvalue);
1593 assert(data);
1594
1595 l = strv_split_quoted(rvalue);
1596 if (!l)
1597 return -ENOMEM;
1598
1599 if (strv_length(l) != 2) {
1600 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1601 strv_free(l);
1602 return 0;
1603 }
1604
1605 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1606 strv_free(l);
1607
1608 if (r < 0) {
1609 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1610 return 0;
1611 }
1612
1613 return 0;
1614}
1615
1616int 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) {
1617 Unit *u = data;
1618 int r;
1619 unsigned long ul;
1620 char *t;
1621
1622 assert(filename);
1623 assert(lvalue);
1624 assert(rvalue);
1625 assert(data);
1626
1627 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1628 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1629 return 0;
1630 }
1631
1632 if (asprintf(&t, "%lu", ul) < 0)
1633 return -ENOMEM;
1634
1635 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1636 free(t);
1637
1638 if (r < 0) {
1639 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1640 return 0;
1641 }
1642
1643 return 0;
1644}
1645
1646int 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) {
1647 Unit *u = data;
1648 int r;
1649 off_t sz;
1650 char *t;
1651
1652 assert(filename);
1653 assert(lvalue);
1654 assert(rvalue);
1655 assert(data);
1656
1657 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1658 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1659 return 0;
1660 }
1661
1662 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1663 return -ENOMEM;
1664
1665 r = unit_add_cgroup_attribute(u,
1666 "memory",
1667 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1668 t, NULL);
1669 free(t);
1670
1671 if (r < 0) {
1672 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1673 return 0;
1674 }
1675
1676 return 0;
1677}
1678
1679static int device_map(const char *controller, const char *name, const char *value, char **ret) {
ab1f0633
LP
1680 char **l;
1681
9e372868
LP
1682 assert(controller);
1683 assert(name);
1684 assert(value);
1685 assert(ret);
1686
ab1f0633
LP
1687 l = strv_split_quoted(value);
1688 if (!l)
1689 return -ENOMEM;
1690
1691 assert(strv_length(l) >= 1);
1692
1693 if (streq(l[0], "*")) {
1694
1695 if (asprintf(ret, "a *:*%s%s",
1696 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1697 strv_free(l);
1698 return -ENOMEM;
1699 }
1700
1701 } else {
9e372868
LP
1702 struct stat st;
1703
1704 if (stat(l[0], &st) < 0) {
ab1f0633
LP
1705 log_warning("Couldn't stat device %s", l[0]);
1706 strv_free(l);
1707 return -errno;
1708 }
1709
1710 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1711 log_warning("%s is not a device.", l[0]);
1712 strv_free(l);
1713 return -ENODEV;
1714 }
1715
1716 if (asprintf(ret, "%c %u:%u%s%s",
1717 S_ISCHR(st.st_mode) ? 'c' : 'b',
1718 major(st.st_rdev), minor(st.st_rdev),
1719 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1720
1721 strv_free(l);
1722 return -ENOMEM;
1723 }
1724 }
1725
1726 strv_free(l);
1727 return 0;
1728}
1729
1730int 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) {
1731 Unit *u = data;
1732 char **l;
1733 int r;
1734 unsigned k;
1735
1736 assert(filename);
1737 assert(lvalue);
1738 assert(rvalue);
1739 assert(data);
1740
1741 l = strv_split_quoted(rvalue);
1742 if (!l)
1743 return -ENOMEM;
1744
1745 k = strv_length(l);
1746 if (k < 1 || k > 2) {
1747 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1748 strv_free(l);
1749 return 0;
1750 }
1751
1752 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1753 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1754 strv_free(l);
1755 return 0;
1756 }
1757
1758 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1759 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1760 strv_free(l);
1761 return 0;
1762 }
1763 strv_free(l);
1764
1765 r = unit_add_cgroup_attribute(u, "devices",
1766 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1767 rvalue, device_map);
1768
1769 if (r < 0) {
1770 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1771 return 0;
1772 }
1773
1774 return 0;
1775}
1776
9e372868
LP
1777static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1778 struct stat st;
1779 char **l;
94959f0f 1780 dev_t d;
9e372868
LP
1781
1782 assert(controller);
1783 assert(name);
1784 assert(value);
1785 assert(ret);
1786
1787 l = strv_split_quoted(value);
1788 if (!l)
1789 return -ENOMEM;
1790
1791 assert(strv_length(l) == 2);
1792
1793 if (stat(l[0], &st) < 0) {
1794 log_warning("Couldn't stat device %s", l[0]);
1795 strv_free(l);
1796 return -errno;
1797 }
1798
94959f0f
LP
1799 if (S_ISBLK(st.st_mode))
1800 d = st.st_rdev;
1801 else if (major(st.st_dev) != 0) {
1802 /* If this is not a device node then find the block
1803 * device this file is stored on */
1804 d = st.st_dev;
1805
1806 /* If this is a partition, try to get the originating
1807 * block device */
1808 block_get_whole_disk(d, &d);
1809 } else {
1810 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
9e372868
LP
1811 strv_free(l);
1812 return -ENODEV;
1813 }
1814
94959f0f 1815 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
9e372868
LP
1816 strv_free(l);
1817 return -ENOMEM;
1818 }
1819
1820 strv_free(l);
1821 return 0;
1822}
1823
1824int 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) {
1825 Unit *u = data;
1826 int r;
1827 unsigned long ul;
1828 const char *device = NULL, *weight;
1829 unsigned k;
1830 char *t, **l;
1831
1832 assert(filename);
1833 assert(lvalue);
1834 assert(rvalue);
1835 assert(data);
1836
1837 l = strv_split_quoted(rvalue);
1838 if (!l)
1839 return -ENOMEM;
1840
1841 k = strv_length(l);
1842 if (k < 1 || k > 2) {
1843 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1844 strv_free(l);
1845 return 0;
1846 }
1847
1848 if (k == 1)
1849 weight = l[0];
1850 else {
1851 device = l[0];
1852 weight = l[1];
1853 }
1854
94959f0f 1855 if (device && !path_is_absolute(device)) {
9e372868
LP
1856 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1857 strv_free(l);
1858 return 0;
1859 }
1860
1861 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1862 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1863 strv_free(l);
1864 return 0;
1865 }
1866
1867 if (device)
1868 r = asprintf(&t, "%s %lu", device, ul);
1869 else
1870 r = asprintf(&t, "%lu", ul);
1871 strv_free(l);
1872
1873 if (r < 0)
1874 return -ENOMEM;
1875
1876 if (device)
1877 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1878 else
1879 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1880 free(t);
1881
1882 if (r < 0) {
1883 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1884 return 0;
1885 }
1886
1887 return 0;
1888}
1889
1890int 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) {
1891 Unit *u = data;
1892 int r;
1893 off_t bytes;
1894 unsigned k;
1895 char *t, **l;
1896
1897 assert(filename);
1898 assert(lvalue);
1899 assert(rvalue);
1900 assert(data);
1901
1902 l = strv_split_quoted(rvalue);
1903 if (!l)
1904 return -ENOMEM;
1905
1906 k = strv_length(l);
1907 if (k != 2) {
1908 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1909 strv_free(l);
1910 return 0;
1911 }
1912
94959f0f 1913 if (!path_is_absolute(l[0])) {
9e372868
LP
1914 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1915 strv_free(l);
1916 return 0;
1917 }
1918
1919 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
49f43d5f 1920 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
9e372868
LP
1921 strv_free(l);
1922 return 0;
1923 }
1924
1925 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1926 strv_free(l);
1927
1928 if (r < 0)
1929 return -ENOMEM;
1930
1931 r = unit_add_cgroup_attribute(u, "blkio",
1932 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1933 t, blkio_map);
1934 free(t);
1935
1936 if (r < 0) {
1937 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1938 return 0;
1939 }
1940
1941 return 0;
1942}
1943
7c8fa05c
LP
1944int config_parse_unit_requires_mounts_for(
1945 const char *filename,
1946 unsigned line,
1947 const char *section,
1948 const char *lvalue,
1949 int ltype,
1950 const char *rvalue,
1951 void *data,
1952 void *userdata) {
1953
1954 Unit *u = userdata;
1955 int r;
1956 bool empty_before;
1957
1958 assert(filename);
1959 assert(lvalue);
1960 assert(rvalue);
1961 assert(data);
1962
1963 empty_before = !u->requires_mounts_for;
1964
1965 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1966
1967 /* Make it easy to find units with requires_mounts set */
1968 if (empty_before && u->requires_mounts_for)
1969 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1970
1971 return r;
1972}
9e372868 1973
49dbfa7b
LP
1974int config_parse_documentation(
1975 const char *filename,
1976 unsigned line,
1977 const char *section,
1978 const char *lvalue,
1979 int ltype,
1980 const char *rvalue,
1981 void *data,
1982 void *userdata) {
1983
1984 Unit *u = userdata;
1985 int r;
1986 char **a, **b;
1987
1988 assert(filename);
1989 assert(lvalue);
1990 assert(rvalue);
1991 assert(u);
1992
1993 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1994 if (r < 0)
1995 return r;
1996
1997 for (a = b = u->documentation; a && *a; a++) {
1998
1999 if (is_valid_documentation_url(*a))
2000 *(b++) = *a;
2001 else {
2002 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2003 free(*a);
2004 }
2005 }
2006 *b = NULL;
2007
2008 return r;
2009}
2010
8351ceae
LP
2011static void syscall_set(uint32_t *p, int nr) {
2012 p[nr >> 4] |= 1 << (nr & 31);
2013}
2014
2015static void syscall_unset(uint32_t *p, int nr) {
2016 p[nr >> 4] &= ~(1 << (nr & 31));
2017}
2018
2019int config_parse_syscall_filter(
2020 const char *filename,
2021 unsigned line,
2022 const char *section,
2023 const char *lvalue,
2024 int ltype,
2025 const char *rvalue,
2026 void *data,
2027 void *userdata) {
2028
2029 ExecContext *c = data;
2030 Unit *u = userdata;
2031 bool invert;
2032 char *w;
2033 size_t l;
2034 char *state;
2035
2036 assert(filename);
2037 assert(lvalue);
2038 assert(rvalue);
2039 assert(u);
2040
2041 if (rvalue[0] == '~') {
2042 invert = true;
2043 rvalue++;
2044 }
2045
2046 if (!c->syscall_filter) {
2047 size_t n;
2048
2049 n = (syscall_max() + 31) >> 4;
2050 c->syscall_filter = new(uint32_t, n);
2051 if (!c->syscall_filter)
2052 return -ENOMEM;
2053
2054 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2055
2056 /* Add these by default */
2057 syscall_set(c->syscall_filter, __NR_execve);
2058 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2059#ifdef __NR_sigreturn
2060 syscall_set(c->syscall_filter, __NR_sigreturn);
2061#endif
2062 syscall_set(c->syscall_filter, __NR_exit_group);
2063 syscall_set(c->syscall_filter, __NR_exit);
2064 }
2065
2066 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2067 int id;
2068 char *t;
2069
2070 t = strndup(w, l);
2071 if (!t)
2072 return -ENOMEM;
2073
2074 id = syscall_from_name(t);
2075 free(t);
2076
2077 if (id < 0) {
2078 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2079 continue;
2080 }
2081
2082 if (invert)
2083 syscall_unset(c->syscall_filter, id);
2084 else
2085 syscall_set(c->syscall_filter, id);
2086 }
2087
2088 c->no_new_privileges = true;
2089
2090 return 0;
2091}
2092
071830ff 2093#define FOLLOW_MAX 8
87f0e418 2094
9e2f7c11 2095static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
0301abf4 2096 unsigned c = 0;
87f0e418
LP
2097 int fd, r;
2098 FILE *f;
0301abf4 2099 char *id = NULL;
87f0e418
LP
2100
2101 assert(filename);
2102 assert(*filename);
2103 assert(_f);
2104 assert(names);
2105
0301abf4
LP
2106 /* This will update the filename pointer if the loaded file is
2107 * reached by a symlink. The old string will be freed. */
87f0e418 2108
0301abf4 2109 for (;;) {
2c7108c4 2110 char *target, *name;
87f0e418 2111
0301abf4
LP
2112 if (c++ >= FOLLOW_MAX)
2113 return -ELOOP;
2114
b08d03ff
LP
2115 path_kill_slashes(*filename);
2116
87f0e418 2117 /* Add the file name we are currently looking at to
8f05424d
LP
2118 * the names of this unit, but only if it is a valid
2119 * unit name. */
9eb977db 2120 name = path_get_file_name(*filename);
87f0e418 2121
15e11d81 2122 if (unit_name_is_valid(name, true)) {
8f05424d 2123
15e11d81
LP
2124 id = set_get(names, name);
2125 if (!id) {
2126 id = strdup(name);
2127 if (!id)
8f05424d 2128 return -ENOMEM;
87f0e418 2129
15e11d81
LP
2130 r = set_put(names, id);
2131 if (r < 0) {
8f05424d
LP
2132 free(id);
2133 return r;
2134 }
87f0e418 2135 }
87f0e418
LP
2136 }
2137
0301abf4 2138 /* Try to open the file name, but don't if its a symlink */
9946996c
LP
2139 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2140 if (fd >= 0)
87f0e418
LP
2141 break;
2142
0301abf4
LP
2143 if (errno != ELOOP)
2144 return -errno;
2145
87f0e418 2146 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
9946996c
LP
2147 r = readlink_and_make_absolute(*filename, &target);
2148 if (r < 0)
0301abf4 2149 return r;
87f0e418 2150
0301abf4 2151 free(*filename);
2c7108c4 2152 *filename = target;
87f0e418
LP
2153 }
2154
9946996c
LP
2155 f = fdopen(fd, "re");
2156 if (!f) {
87f0e418 2157 r = -errno;
9e2f7c11 2158 close_nointr_nofail(fd);
0301abf4 2159 return r;
87f0e418
LP
2160 }
2161
2162 *_f = f;
9e2f7c11 2163 *_final = id;
0301abf4 2164 return 0;
87f0e418
LP
2165}
2166
23a177ef
LP
2167static int merge_by_names(Unit **u, Set *names, const char *id) {
2168 char *k;
2169 int r;
2170
2171 assert(u);
2172 assert(*u);
2173 assert(names);
2174
2175 /* Let's try to add in all symlink names we found */
2176 while ((k = set_steal_first(names))) {
2177
2178 /* First try to merge in the other name into our
2179 * unit */
9946996c
LP
2180 r = unit_merge_by_name(*u, k);
2181 if (r < 0) {
23a177ef
LP
2182 Unit *other;
2183
2184 /* Hmm, we couldn't merge the other unit into
2185 * ours? Then let's try it the other way
2186 * round */
2187
ac155bb8 2188 other = manager_get_unit((*u)->manager, k);
23a177ef
LP
2189 free(k);
2190
9946996c
LP
2191 if (other) {
2192 r = unit_merge(other, *u);
2193 if (r >= 0) {
23a177ef
LP
2194 *u = other;
2195 return merge_by_names(u, names, NULL);
2196 }
9946996c 2197 }
23a177ef
LP
2198
2199 return r;
2200 }
2201
2202 if (id == k)
2203 unit_choose_id(*u, id);
2204
2205 free(k);
2206 }
2207
2208 return 0;
2209}
2210
e537352b 2211static int load_from_path(Unit *u, const char *path) {
0301abf4 2212 int r;
87f0e418 2213 Set *symlink_names;
23a177ef
LP
2214 FILE *f = NULL;
2215 char *filename = NULL, *id = NULL;
2216 Unit *merged;
45fb0699 2217 struct stat st;
23a177ef
LP
2218
2219 assert(u);
e537352b 2220 assert(path);
3efd4195 2221
f975e971
LP
2222 symlink_names = set_new(string_hash_func, string_compare_func);
2223 if (!symlink_names)
87f0e418 2224 return -ENOMEM;
3efd4195 2225
036643a2
LP
2226 if (path_is_absolute(path)) {
2227
9946996c
LP
2228 filename = strdup(path);
2229 if (!filename) {
036643a2
LP
2230 r = -ENOMEM;
2231 goto finish;
2232 }
2233
9946996c
LP
2234 r = open_follow(&filename, &f, symlink_names, &id);
2235 if (r < 0) {
036643a2
LP
2236 free(filename);
2237 filename = NULL;
2238
2239 if (r != -ENOENT)
2240 goto finish;
2241 }
2242
2243 } else {
2244 char **p;
2245
ac155bb8 2246 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
036643a2
LP
2247
2248 /* Instead of opening the path right away, we manually
2249 * follow all symlinks and add their name to our unit
2250 * name set while doing so */
9946996c
LP
2251 filename = path_make_absolute(path, *p);
2252 if (!filename) {
036643a2
LP
2253 r = -ENOMEM;
2254 goto finish;
2255 }
2256
ac155bb8
MS
2257 if (u->manager->unit_path_cache &&
2258 !set_get(u->manager->unit_path_cache, filename))
fe51822e
LP
2259 r = -ENOENT;
2260 else
2261 r = open_follow(&filename, &f, symlink_names, &id);
2262
2263 if (r < 0) {
036643a2
LP
2264 free(filename);
2265 filename = NULL;
2266
2267 if (r != -ENOENT)
2268 goto finish;
2269
2270 /* Empty the symlink names for the next run */
9946996c 2271 set_clear_free(symlink_names);
036643a2
LP
2272 continue;
2273 }
2274
2275 break;
2276 }
2277 }
034c6ed7 2278
036643a2 2279 if (!filename) {
8f05424d 2280 /* Hmm, no suitable file found? */
23a177ef 2281 r = 0;
0301abf4
LP
2282 goto finish;
2283 }
87f0e418 2284
23a177ef 2285 merged = u;
9946996c
LP
2286 r = merge_by_names(&merged, symlink_names, id);
2287 if (r < 0)
0301abf4 2288 goto finish;
87f0e418 2289
23a177ef 2290 if (merged != u) {
ac155bb8 2291 u->load_state = UNIT_MERGED;
23a177ef
LP
2292 r = 0;
2293 goto finish;
034c6ed7
LP
2294 }
2295
45fb0699
LP
2296 if (fstat(fileno(f), &st) < 0) {
2297 r = -errno;
2298 goto finish;
2299 }
2300
00dc5d76 2301 if (null_or_empty(&st))
ac155bb8 2302 u->load_state = UNIT_MASKED;
00dc5d76
LP
2303 else {
2304 /* Now, parse the file contents */
f975e971
LP
2305 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2306 if (r < 0)
00dc5d76
LP
2307 goto finish;
2308
ac155bb8 2309 u->load_state = UNIT_LOADED;
00dc5d76 2310 }
b08d03ff 2311
ac155bb8
MS
2312 free(u->fragment_path);
2313 u->fragment_path = filename;
0301abf4 2314 filename = NULL;
87f0e418 2315
ac155bb8 2316 u->fragment_mtime = timespec_load(&st.st_mtim);
45fb0699 2317
1b64d026
LP
2318 if (u->source_path) {
2319 if (stat(u->source_path, &st) >= 0)
2320 u->source_mtime = timespec_load(&st.st_mtim);
2321 else
2322 u->source_mtime = 0;
2323 }
2324
23a177ef 2325 r = 0;
87f0e418
LP
2326
2327finish:
53ec43c6 2328 set_free_free(symlink_names);
0301abf4
LP
2329 free(filename);
2330
23a177ef
LP
2331 if (f)
2332 fclose(f);
2333
0301abf4
LP
2334 return r;
2335}
2336
e537352b 2337int unit_load_fragment(Unit *u) {
23a177ef 2338 int r;
294d81f1
LP
2339 Iterator i;
2340 const char *t;
0301abf4
LP
2341
2342 assert(u);
ac155bb8
MS
2343 assert(u->load_state == UNIT_STUB);
2344 assert(u->id);
23a177ef 2345
294d81f1
LP
2346 /* First, try to find the unit under its id. We always look
2347 * for unit files in the default directories, to make it easy
2348 * to override things by placing things in /etc/systemd/system */
9946996c
LP
2349 r = load_from_path(u, u->id);
2350 if (r < 0)
294d81f1
LP
2351 return r;
2352
2353 /* Try to find an alias we can load this with */
ac155bb8
MS
2354 if (u->load_state == UNIT_STUB)
2355 SET_FOREACH(t, u->names, i) {
294d81f1 2356
ac155bb8 2357 if (t == u->id)
294d81f1
LP
2358 continue;
2359
9946996c
LP
2360 r = load_from_path(u, t);
2361 if (r < 0)
294d81f1
LP
2362 return r;
2363
ac155bb8 2364 if (u->load_state != UNIT_STUB)
294d81f1
LP
2365 break;
2366 }
23a177ef 2367
294d81f1 2368 /* And now, try looking for it under the suggested (originally linked) path */
ac155bb8 2369 if (u->load_state == UNIT_STUB && u->fragment_path) {
6ccb1b44 2370
9946996c
LP
2371 r = load_from_path(u, u->fragment_path);
2372 if (r < 0)
23a177ef 2373 return r;
0301abf4 2374
ac155bb8 2375 if (u->load_state == UNIT_STUB) {
6ccb1b44
LP
2376 /* Hmm, this didn't work? Then let's get rid
2377 * of the fragment path stored for us, so that
2378 * we don't point to an invalid location. */
ac155bb8
MS
2379 free(u->fragment_path);
2380 u->fragment_path = NULL;
6ccb1b44
LP
2381 }
2382 }
2383
294d81f1 2384 /* Look for a template */
ac155bb8 2385 if (u->load_state == UNIT_STUB && u->instance) {
294d81f1
LP
2386 char *k;
2387
9946996c
LP
2388 k = unit_name_template(u->id);
2389 if (!k)
294d81f1
LP
2390 return -ENOMEM;
2391
2392 r = load_from_path(u, k);
2393 free(k);
0301abf4 2394
294d81f1 2395 if (r < 0)
9e2f7c11 2396 return r;
890f434c 2397
ac155bb8
MS
2398 if (u->load_state == UNIT_STUB)
2399 SET_FOREACH(t, u->names, i) {
87f0e418 2400
ac155bb8 2401 if (t == u->id)
23a177ef 2402 continue;
071830ff 2403
9946996c
LP
2404 k = unit_name_template(t);
2405 if (!k)
294d81f1
LP
2406 return -ENOMEM;
2407
2408 r = load_from_path(u, k);
2409 free(k);
2410
2411 if (r < 0)
23a177ef 2412 return r;
890f434c 2413
ac155bb8 2414 if (u->load_state != UNIT_STUB)
23a177ef
LP
2415 break;
2416 }
071830ff
LP
2417 }
2418
23a177ef 2419 return 0;
3efd4195 2420}
e537352b
LP
2421
2422void unit_dump_config_items(FILE *f) {
f975e971
LP
2423 static const struct {
2424 const ConfigParserCallback callback;
2425 const char *rvalue;
2426 } table[] = {
2427 { config_parse_int, "INTEGER" },
2428 { config_parse_unsigned, "UNSIGNED" },
9ba1a159 2429 { config_parse_bytes_size, "SIZE" },
f975e971
LP
2430 { config_parse_bool, "BOOLEAN" },
2431 { config_parse_string, "STRING" },
2432 { config_parse_path, "PATH" },
2433 { config_parse_unit_path_printf, "PATH" },
2434 { config_parse_strv, "STRING [...]" },
2435 { config_parse_exec_nice, "NICE" },
2436 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2437 { config_parse_exec_io_class, "IOCLASS" },
2438 { config_parse_exec_io_priority, "IOPRIORITY" },
2439 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2440 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2441 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2442 { config_parse_mode, "MODE" },
2443 { config_parse_unit_env_file, "FILE" },
2444 { config_parse_output, "OUTPUT" },
2445 { config_parse_input, "INPUT" },
2446 { config_parse_facility, "FACILITY" },
2447 { config_parse_level, "LEVEL" },
2448 { config_parse_exec_capabilities, "CAPABILITIES" },
2449 { config_parse_exec_secure_bits, "SECUREBITS" },
ec8927ca 2450 { config_parse_bounding_set, "BOUNDINGSET" },
f975e971
LP
2451 { config_parse_limit, "LIMIT" },
2452 { config_parse_unit_cgroup, "CGROUP [...]" },
2453 { config_parse_unit_deps, "UNIT [...]" },
f975e971
LP
2454 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2455 { config_parse_service_type, "SERVICETYPE" },
2456 { config_parse_service_restart, "SERVICERESTART" },
2457#ifdef HAVE_SYSV_COMPAT
2458 { config_parse_sysv_priority, "SYSVPRIORITY" },
2459#else
2460 { config_parse_warn_compat, "NOTSUPPORTED" },
2461#endif
2462 { config_parse_kill_mode, "KILLMODE" },
2463 { config_parse_kill_signal, "SIGNAL" },
2464 { config_parse_socket_listen, "SOCKET [...]" },
2465 { config_parse_socket_bind, "SOCKETBIND" },
2466 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2467 { config_parse_usec, "SECONDS" },
d88a251b 2468 { config_parse_nsec, "NANOSECONDS" },
f975e971 2469 { config_parse_path_strv, "PATH [...]" },
7c8fa05c 2470 { config_parse_unit_requires_mounts_for, "PATH [...]" },
f975e971
LP
2471 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2472 { config_parse_unit_string_printf, "STRING" },
2473 { config_parse_timer, "TIMER" },
2474 { config_parse_timer_unit, "NAME" },
2475 { config_parse_path_spec, "PATH" },
2476 { config_parse_path_unit, "UNIT" },
2477 { config_parse_notify_access, "ACCESS" },
2478 { config_parse_ip_tos, "TOS" },
2479 { config_parse_unit_condition_path, "CONDITION" },
2480 { config_parse_unit_condition_string, "CONDITION" },
2481 { config_parse_unit_condition_null, "CONDITION" },
2482 };
2483
2484 const char *prev = NULL;
2485 const char *i;
2486
2487 assert(f);
e537352b 2488
f975e971
LP
2489 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2490 const char *rvalue = "OTHER", *lvalue;
2491 unsigned j;
2492 size_t prefix_len;
2493 const char *dot;
2494 const ConfigPerfItem *p;
2495
2496 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2497
2498 dot = strchr(i, '.');
2499 lvalue = dot ? dot + 1 : i;
2500 prefix_len = dot-i;
2501
2502 if (dot)
2503 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2504 if (prev)
2505 fputc('\n', f);
2506
2507 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2508 }
2509
2510 for (j = 0; j < ELEMENTSOF(table); j++)
2511 if (p->parse == table[j].callback) {
2512 rvalue = table[j].rvalue;
2513 break;
2514 }
2515
2516 fprintf(f, "%s=%s\n", lvalue, rvalue);
2517 prev = i;
2518 }
e537352b 2519}