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