]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/load-fragment.c
service: document new Type=idle
[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"
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}