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