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