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