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