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