]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
systemd: introduced new timeout types
[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 if ((trigger = rvalue[0] == '|'))
1520 rvalue++;
1521
1522 if ((negate = rvalue[0] == '!'))
1523 rvalue++;
1524
1525 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1526 return -ENOMEM;
1527
1528 LIST_PREPEND(Condition, conditions, u->conditions, c);
1529 return 0;
1530 }
1531
1532 int config_parse_unit_condition_null(
1533 const char *filename,
1534 unsigned line,
1535 const char *section,
1536 const char *lvalue,
1537 int ltype,
1538 const char *rvalue,
1539 void *data,
1540 void *userdata) {
1541
1542 Unit *u = data;
1543 Condition *c;
1544 bool trigger, negate;
1545 int b;
1546
1547 assert(filename);
1548 assert(lvalue);
1549 assert(rvalue);
1550 assert(data);
1551
1552 if ((trigger = rvalue[0] == '|'))
1553 rvalue++;
1554
1555 if ((negate = rvalue[0] == '!'))
1556 rvalue++;
1557
1558 if ((b = parse_boolean(rvalue)) < 0) {
1559 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1560 return 0;
1561 }
1562
1563 if (!b)
1564 negate = !negate;
1565
1566 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1567 return -ENOMEM;
1568
1569 LIST_PREPEND(Condition, conditions, u->conditions, c);
1570 return 0;
1571 }
1572
1573 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1574 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1575
1576 int config_parse_unit_cgroup_attr(
1577 const char *filename,
1578 unsigned line,
1579 const char *section,
1580 const char *lvalue,
1581 int ltype,
1582 const char *rvalue,
1583 void *data,
1584 void *userdata) {
1585
1586 Unit *u = data;
1587 char **l;
1588 int r;
1589
1590 assert(filename);
1591 assert(lvalue);
1592 assert(rvalue);
1593 assert(data);
1594
1595 l = strv_split_quoted(rvalue);
1596 if (!l)
1597 return -ENOMEM;
1598
1599 if (strv_length(l) != 2) {
1600 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1601 strv_free(l);
1602 return 0;
1603 }
1604
1605 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1606 strv_free(l);
1607
1608 if (r < 0) {
1609 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1610 return 0;
1611 }
1612
1613 return 0;
1614 }
1615
1616 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) {
1617 Unit *u = data;
1618 int r;
1619 unsigned long ul;
1620 char *t;
1621
1622 assert(filename);
1623 assert(lvalue);
1624 assert(rvalue);
1625 assert(data);
1626
1627 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1628 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1629 return 0;
1630 }
1631
1632 if (asprintf(&t, "%lu", ul) < 0)
1633 return -ENOMEM;
1634
1635 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1636 free(t);
1637
1638 if (r < 0) {
1639 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1640 return 0;
1641 }
1642
1643 return 0;
1644 }
1645
1646 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) {
1647 Unit *u = data;
1648 int r;
1649 off_t sz;
1650 char *t;
1651
1652 assert(filename);
1653 assert(lvalue);
1654 assert(rvalue);
1655 assert(data);
1656
1657 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1658 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1659 return 0;
1660 }
1661
1662 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1663 return -ENOMEM;
1664
1665 r = unit_add_cgroup_attribute(u,
1666 "memory",
1667 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1668 t, NULL);
1669 free(t);
1670
1671 if (r < 0) {
1672 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1673 return 0;
1674 }
1675
1676 return 0;
1677 }
1678
1679 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1680 char **l;
1681
1682 assert(controller);
1683 assert(name);
1684 assert(value);
1685 assert(ret);
1686
1687 l = strv_split_quoted(value);
1688 if (!l)
1689 return -ENOMEM;
1690
1691 assert(strv_length(l) >= 1);
1692
1693 if (streq(l[0], "*")) {
1694
1695 if (asprintf(ret, "a *:*%s%s",
1696 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1697 strv_free(l);
1698 return -ENOMEM;
1699 }
1700
1701 } else {
1702 struct stat st;
1703
1704 if (stat(l[0], &st) < 0) {
1705 log_warning("Couldn't stat device %s", l[0]);
1706 strv_free(l);
1707 return -errno;
1708 }
1709
1710 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1711 log_warning("%s is not a device.", l[0]);
1712 strv_free(l);
1713 return -ENODEV;
1714 }
1715
1716 if (asprintf(ret, "%c %u:%u%s%s",
1717 S_ISCHR(st.st_mode) ? 'c' : 'b',
1718 major(st.st_rdev), minor(st.st_rdev),
1719 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1720
1721 strv_free(l);
1722 return -ENOMEM;
1723 }
1724 }
1725
1726 strv_free(l);
1727 return 0;
1728 }
1729
1730 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) {
1731 Unit *u = data;
1732 char **l;
1733 int r;
1734 unsigned k;
1735
1736 assert(filename);
1737 assert(lvalue);
1738 assert(rvalue);
1739 assert(data);
1740
1741 l = strv_split_quoted(rvalue);
1742 if (!l)
1743 return -ENOMEM;
1744
1745 k = strv_length(l);
1746 if (k < 1 || k > 2) {
1747 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1748 strv_free(l);
1749 return 0;
1750 }
1751
1752 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1753 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1754 strv_free(l);
1755 return 0;
1756 }
1757
1758 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1759 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1760 strv_free(l);
1761 return 0;
1762 }
1763 strv_free(l);
1764
1765 r = unit_add_cgroup_attribute(u, "devices",
1766 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1767 rvalue, device_map);
1768
1769 if (r < 0) {
1770 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1771 return 0;
1772 }
1773
1774 return 0;
1775 }
1776
1777 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1778 struct stat st;
1779 char **l;
1780 dev_t d;
1781
1782 assert(controller);
1783 assert(name);
1784 assert(value);
1785 assert(ret);
1786
1787 l = strv_split_quoted(value);
1788 if (!l)
1789 return -ENOMEM;
1790
1791 assert(strv_length(l) == 2);
1792
1793 if (stat(l[0], &st) < 0) {
1794 log_warning("Couldn't stat device %s", l[0]);
1795 strv_free(l);
1796 return -errno;
1797 }
1798
1799 if (S_ISBLK(st.st_mode))
1800 d = st.st_rdev;
1801 else if (major(st.st_dev) != 0) {
1802 /* If this is not a device node then find the block
1803 * device this file is stored on */
1804 d = st.st_dev;
1805
1806 /* If this is a partition, try to get the originating
1807 * block device */
1808 block_get_whole_disk(d, &d);
1809 } else {
1810 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1811 strv_free(l);
1812 return -ENODEV;
1813 }
1814
1815 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1816 strv_free(l);
1817 return -ENOMEM;
1818 }
1819
1820 strv_free(l);
1821 return 0;
1822 }
1823
1824 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) {
1825 Unit *u = data;
1826 int r;
1827 unsigned long ul;
1828 const char *device = NULL, *weight;
1829 unsigned k;
1830 char *t, **l;
1831
1832 assert(filename);
1833 assert(lvalue);
1834 assert(rvalue);
1835 assert(data);
1836
1837 l = strv_split_quoted(rvalue);
1838 if (!l)
1839 return -ENOMEM;
1840
1841 k = strv_length(l);
1842 if (k < 1 || k > 2) {
1843 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1844 strv_free(l);
1845 return 0;
1846 }
1847
1848 if (k == 1)
1849 weight = l[0];
1850 else {
1851 device = l[0];
1852 weight = l[1];
1853 }
1854
1855 if (device && !path_is_absolute(device)) {
1856 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1857 strv_free(l);
1858 return 0;
1859 }
1860
1861 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1862 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1863 strv_free(l);
1864 return 0;
1865 }
1866
1867 if (device)
1868 r = asprintf(&t, "%s %lu", device, ul);
1869 else
1870 r = asprintf(&t, "%lu", ul);
1871 strv_free(l);
1872
1873 if (r < 0)
1874 return -ENOMEM;
1875
1876 if (device)
1877 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1878 else
1879 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1880 free(t);
1881
1882 if (r < 0) {
1883 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1884 return 0;
1885 }
1886
1887 return 0;
1888 }
1889
1890 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) {
1891 Unit *u = data;
1892 int r;
1893 off_t bytes;
1894 unsigned k;
1895 char *t, **l;
1896
1897 assert(filename);
1898 assert(lvalue);
1899 assert(rvalue);
1900 assert(data);
1901
1902 l = strv_split_quoted(rvalue);
1903 if (!l)
1904 return -ENOMEM;
1905
1906 k = strv_length(l);
1907 if (k != 2) {
1908 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1909 strv_free(l);
1910 return 0;
1911 }
1912
1913 if (!path_is_absolute(l[0])) {
1914 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1915 strv_free(l);
1916 return 0;
1917 }
1918
1919 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1920 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1921 strv_free(l);
1922 return 0;
1923 }
1924
1925 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1926 strv_free(l);
1927
1928 if (r < 0)
1929 return -ENOMEM;
1930
1931 r = unit_add_cgroup_attribute(u, "blkio",
1932 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1933 t, blkio_map);
1934 free(t);
1935
1936 if (r < 0) {
1937 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1938 return 0;
1939 }
1940
1941 return 0;
1942 }
1943
1944 int config_parse_unit_requires_mounts_for(
1945 const char *filename,
1946 unsigned line,
1947 const char *section,
1948 const char *lvalue,
1949 int ltype,
1950 const char *rvalue,
1951 void *data,
1952 void *userdata) {
1953
1954 Unit *u = userdata;
1955 int r;
1956 bool empty_before;
1957
1958 assert(filename);
1959 assert(lvalue);
1960 assert(rvalue);
1961 assert(data);
1962
1963 empty_before = !u->requires_mounts_for;
1964
1965 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1966
1967 /* Make it easy to find units with requires_mounts set */
1968 if (empty_before && u->requires_mounts_for)
1969 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1970
1971 return r;
1972 }
1973
1974 int config_parse_documentation(
1975 const char *filename,
1976 unsigned line,
1977 const char *section,
1978 const char *lvalue,
1979 int ltype,
1980 const char *rvalue,
1981 void *data,
1982 void *userdata) {
1983
1984 Unit *u = userdata;
1985 int r;
1986 char **a, **b;
1987
1988 assert(filename);
1989 assert(lvalue);
1990 assert(rvalue);
1991 assert(u);
1992
1993 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1994 if (r < 0)
1995 return r;
1996
1997 for (a = b = u->documentation; a && *a; a++) {
1998
1999 if (is_valid_documentation_url(*a))
2000 *(b++) = *a;
2001 else {
2002 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2003 free(*a);
2004 }
2005 }
2006 *b = NULL;
2007
2008 return r;
2009 }
2010
2011 static void syscall_set(uint32_t *p, int nr) {
2012 p[nr >> 4] |= 1 << (nr & 31);
2013 }
2014
2015 static void syscall_unset(uint32_t *p, int nr) {
2016 p[nr >> 4] &= ~(1 << (nr & 31));
2017 }
2018
2019 int config_parse_syscall_filter(
2020 const char *filename,
2021 unsigned line,
2022 const char *section,
2023 const char *lvalue,
2024 int ltype,
2025 const char *rvalue,
2026 void *data,
2027 void *userdata) {
2028
2029 ExecContext *c = data;
2030 Unit *u = userdata;
2031 bool invert;
2032 char *w;
2033 size_t l;
2034 char *state;
2035
2036 assert(filename);
2037 assert(lvalue);
2038 assert(rvalue);
2039 assert(u);
2040
2041 if (rvalue[0] == '~') {
2042 invert = true;
2043 rvalue++;
2044 }
2045
2046 if (!c->syscall_filter) {
2047 size_t n;
2048
2049 n = (syscall_max() + 31) >> 4;
2050 c->syscall_filter = new(uint32_t, n);
2051 if (!c->syscall_filter)
2052 return -ENOMEM;
2053
2054 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2055
2056 /* Add these by default */
2057 syscall_set(c->syscall_filter, __NR_execve);
2058 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2059 #ifdef __NR_sigreturn
2060 syscall_set(c->syscall_filter, __NR_sigreturn);
2061 #endif
2062 syscall_set(c->syscall_filter, __NR_exit_group);
2063 syscall_set(c->syscall_filter, __NR_exit);
2064 }
2065
2066 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2067 int id;
2068 char *t;
2069
2070 t = strndup(w, l);
2071 if (!t)
2072 return -ENOMEM;
2073
2074 id = syscall_from_name(t);
2075 free(t);
2076
2077 if (id < 0) {
2078 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2079 continue;
2080 }
2081
2082 if (invert)
2083 syscall_unset(c->syscall_filter, id);
2084 else
2085 syscall_set(c->syscall_filter, id);
2086 }
2087
2088 c->no_new_privileges = true;
2089
2090 return 0;
2091 }
2092
2093 #define FOLLOW_MAX 8
2094
2095 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2096 unsigned c = 0;
2097 int fd, r;
2098 FILE *f;
2099 char *id = NULL;
2100
2101 assert(filename);
2102 assert(*filename);
2103 assert(_f);
2104 assert(names);
2105
2106 /* This will update the filename pointer if the loaded file is
2107 * reached by a symlink. The old string will be freed. */
2108
2109 for (;;) {
2110 char *target, *name;
2111
2112 if (c++ >= FOLLOW_MAX)
2113 return -ELOOP;
2114
2115 path_kill_slashes(*filename);
2116
2117 /* Add the file name we are currently looking at to
2118 * the names of this unit, but only if it is a valid
2119 * unit name. */
2120 name = path_get_file_name(*filename);
2121
2122 if (unit_name_is_valid(name, true)) {
2123
2124 id = set_get(names, name);
2125 if (!id) {
2126 id = strdup(name);
2127 if (!id)
2128 return -ENOMEM;
2129
2130 r = set_put(names, id);
2131 if (r < 0) {
2132 free(id);
2133 return r;
2134 }
2135 }
2136 }
2137
2138 /* Try to open the file name, but don't if its a symlink */
2139 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2140 if (fd >= 0)
2141 break;
2142
2143 if (errno != ELOOP)
2144 return -errno;
2145
2146 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2147 r = readlink_and_make_absolute(*filename, &target);
2148 if (r < 0)
2149 return r;
2150
2151 free(*filename);
2152 *filename = target;
2153 }
2154
2155 f = fdopen(fd, "re");
2156 if (!f) {
2157 r = -errno;
2158 close_nointr_nofail(fd);
2159 return r;
2160 }
2161
2162 *_f = f;
2163 *_final = id;
2164 return 0;
2165 }
2166
2167 static int merge_by_names(Unit **u, Set *names, const char *id) {
2168 char *k;
2169 int r;
2170
2171 assert(u);
2172 assert(*u);
2173 assert(names);
2174
2175 /* Let's try to add in all symlink names we found */
2176 while ((k = set_steal_first(names))) {
2177
2178 /* First try to merge in the other name into our
2179 * unit */
2180 r = unit_merge_by_name(*u, k);
2181 if (r < 0) {
2182 Unit *other;
2183
2184 /* Hmm, we couldn't merge the other unit into
2185 * ours? Then let's try it the other way
2186 * round */
2187
2188 other = manager_get_unit((*u)->manager, k);
2189 free(k);
2190
2191 if (other) {
2192 r = unit_merge(other, *u);
2193 if (r >= 0) {
2194 *u = other;
2195 return merge_by_names(u, names, NULL);
2196 }
2197 }
2198
2199 return r;
2200 }
2201
2202 if (id == k)
2203 unit_choose_id(*u, id);
2204
2205 free(k);
2206 }
2207
2208 return 0;
2209 }
2210
2211 static int load_from_path(Unit *u, const char *path) {
2212 int r;
2213 Set *symlink_names;
2214 FILE *f = NULL;
2215 char *filename = NULL, *id = NULL;
2216 Unit *merged;
2217 struct stat st;
2218
2219 assert(u);
2220 assert(path);
2221
2222 symlink_names = set_new(string_hash_func, string_compare_func);
2223 if (!symlink_names)
2224 return -ENOMEM;
2225
2226 if (path_is_absolute(path)) {
2227
2228 filename = strdup(path);
2229 if (!filename) {
2230 r = -ENOMEM;
2231 goto finish;
2232 }
2233
2234 r = open_follow(&filename, &f, symlink_names, &id);
2235 if (r < 0) {
2236 free(filename);
2237 filename = NULL;
2238
2239 if (r != -ENOENT)
2240 goto finish;
2241 }
2242
2243 } else {
2244 char **p;
2245
2246 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2247
2248 /* Instead of opening the path right away, we manually
2249 * follow all symlinks and add their name to our unit
2250 * name set while doing so */
2251 filename = path_make_absolute(path, *p);
2252 if (!filename) {
2253 r = -ENOMEM;
2254 goto finish;
2255 }
2256
2257 if (u->manager->unit_path_cache &&
2258 !set_get(u->manager->unit_path_cache, filename))
2259 r = -ENOENT;
2260 else
2261 r = open_follow(&filename, &f, symlink_names, &id);
2262
2263 if (r < 0) {
2264 free(filename);
2265 filename = NULL;
2266
2267 if (r != -ENOENT)
2268 goto finish;
2269
2270 /* Empty the symlink names for the next run */
2271 set_clear_free(symlink_names);
2272 continue;
2273 }
2274
2275 break;
2276 }
2277 }
2278
2279 if (!filename) {
2280 /* Hmm, no suitable file found? */
2281 r = 0;
2282 goto finish;
2283 }
2284
2285 merged = u;
2286 r = merge_by_names(&merged, symlink_names, id);
2287 if (r < 0)
2288 goto finish;
2289
2290 if (merged != u) {
2291 u->load_state = UNIT_MERGED;
2292 r = 0;
2293 goto finish;
2294 }
2295
2296 if (fstat(fileno(f), &st) < 0) {
2297 r = -errno;
2298 goto finish;
2299 }
2300
2301 if (null_or_empty(&st))
2302 u->load_state = UNIT_MASKED;
2303 else {
2304 /* Now, parse the file contents */
2305 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2306 if (r < 0)
2307 goto finish;
2308
2309 u->load_state = UNIT_LOADED;
2310 }
2311
2312 free(u->fragment_path);
2313 u->fragment_path = filename;
2314 filename = NULL;
2315
2316 u->fragment_mtime = timespec_load(&st.st_mtim);
2317
2318 if (u->source_path) {
2319 if (stat(u->source_path, &st) >= 0)
2320 u->source_mtime = timespec_load(&st.st_mtim);
2321 else
2322 u->source_mtime = 0;
2323 }
2324
2325 r = 0;
2326
2327 finish:
2328 set_free_free(symlink_names);
2329 free(filename);
2330
2331 if (f)
2332 fclose(f);
2333
2334 return r;
2335 }
2336
2337 int unit_load_fragment(Unit *u) {
2338 int r;
2339 Iterator i;
2340 const char *t;
2341
2342 assert(u);
2343 assert(u->load_state == UNIT_STUB);
2344 assert(u->id);
2345
2346 /* First, try to find the unit under its id. We always look
2347 * for unit files in the default directories, to make it easy
2348 * to override things by placing things in /etc/systemd/system */
2349 r = load_from_path(u, u->id);
2350 if (r < 0)
2351 return r;
2352
2353 /* Try to find an alias we can load this with */
2354 if (u->load_state == UNIT_STUB)
2355 SET_FOREACH(t, u->names, i) {
2356
2357 if (t == u->id)
2358 continue;
2359
2360 r = load_from_path(u, t);
2361 if (r < 0)
2362 return r;
2363
2364 if (u->load_state != UNIT_STUB)
2365 break;
2366 }
2367
2368 /* And now, try looking for it under the suggested (originally linked) path */
2369 if (u->load_state == UNIT_STUB && u->fragment_path) {
2370
2371 r = load_from_path(u, u->fragment_path);
2372 if (r < 0)
2373 return r;
2374
2375 if (u->load_state == UNIT_STUB) {
2376 /* Hmm, this didn't work? Then let's get rid
2377 * of the fragment path stored for us, so that
2378 * we don't point to an invalid location. */
2379 free(u->fragment_path);
2380 u->fragment_path = NULL;
2381 }
2382 }
2383
2384 /* Look for a template */
2385 if (u->load_state == UNIT_STUB && u->instance) {
2386 char *k;
2387
2388 k = unit_name_template(u->id);
2389 if (!k)
2390 return -ENOMEM;
2391
2392 r = load_from_path(u, k);
2393 free(k);
2394
2395 if (r < 0)
2396 return r;
2397
2398 if (u->load_state == UNIT_STUB)
2399 SET_FOREACH(t, u->names, i) {
2400
2401 if (t == u->id)
2402 continue;
2403
2404 k = unit_name_template(t);
2405 if (!k)
2406 return -ENOMEM;
2407
2408 r = load_from_path(u, k);
2409 free(k);
2410
2411 if (r < 0)
2412 return r;
2413
2414 if (u->load_state != UNIT_STUB)
2415 break;
2416 }
2417 }
2418
2419 return 0;
2420 }
2421
2422 void unit_dump_config_items(FILE *f) {
2423 static const struct {
2424 const ConfigParserCallback callback;
2425 const char *rvalue;
2426 } table[] = {
2427 { config_parse_int, "INTEGER" },
2428 { config_parse_unsigned, "UNSIGNED" },
2429 { config_parse_bytes_size, "SIZE" },
2430 { config_parse_bool, "BOOLEAN" },
2431 { config_parse_string, "STRING" },
2432 { config_parse_path, "PATH" },
2433 { config_parse_unit_path_printf, "PATH" },
2434 { config_parse_strv, "STRING [...]" },
2435 { config_parse_exec_nice, "NICE" },
2436 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2437 { config_parse_exec_io_class, "IOCLASS" },
2438 { config_parse_exec_io_priority, "IOPRIORITY" },
2439 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2440 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2441 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2442 { config_parse_mode, "MODE" },
2443 { config_parse_unit_env_file, "FILE" },
2444 { config_parse_output, "OUTPUT" },
2445 { config_parse_input, "INPUT" },
2446 { config_parse_facility, "FACILITY" },
2447 { config_parse_level, "LEVEL" },
2448 { config_parse_exec_capabilities, "CAPABILITIES" },
2449 { config_parse_exec_secure_bits, "SECUREBITS" },
2450 { config_parse_bounding_set, "BOUNDINGSET" },
2451 { config_parse_limit, "LIMIT" },
2452 { config_parse_unit_cgroup, "CGROUP [...]" },
2453 { config_parse_unit_deps, "UNIT [...]" },
2454 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2455 { config_parse_service_type, "SERVICETYPE" },
2456 { config_parse_service_restart, "SERVICERESTART" },
2457 #ifdef HAVE_SYSV_COMPAT
2458 { config_parse_sysv_priority, "SYSVPRIORITY" },
2459 #else
2460 { config_parse_warn_compat, "NOTSUPPORTED" },
2461 #endif
2462 { config_parse_kill_mode, "KILLMODE" },
2463 { config_parse_kill_signal, "SIGNAL" },
2464 { config_parse_socket_listen, "SOCKET [...]" },
2465 { config_parse_socket_bind, "SOCKETBIND" },
2466 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2467 { config_parse_usec, "SECONDS" },
2468 { config_parse_nsec, "NANOSECONDS" },
2469 { config_parse_path_strv, "PATH [...]" },
2470 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2471 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2472 { config_parse_unit_string_printf, "STRING" },
2473 { config_parse_timer, "TIMER" },
2474 { config_parse_timer_unit, "NAME" },
2475 { config_parse_path_spec, "PATH" },
2476 { config_parse_path_unit, "UNIT" },
2477 { config_parse_notify_access, "ACCESS" },
2478 { config_parse_ip_tos, "TOS" },
2479 { config_parse_unit_condition_path, "CONDITION" },
2480 { config_parse_unit_condition_string, "CONDITION" },
2481 { config_parse_unit_condition_null, "CONDITION" },
2482 };
2483
2484 const char *prev = NULL;
2485 const char *i;
2486
2487 assert(f);
2488
2489 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2490 const char *rvalue = "OTHER", *lvalue;
2491 unsigned j;
2492 size_t prefix_len;
2493 const char *dot;
2494 const ConfigPerfItem *p;
2495
2496 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2497
2498 dot = strchr(i, '.');
2499 lvalue = dot ? dot + 1 : i;
2500 prefix_len = dot-i;
2501
2502 if (dot)
2503 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2504 if (prev)
2505 fputc('\n', f);
2506
2507 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2508 }
2509
2510 for (j = 0; j < ELEMENTSOF(table); j++)
2511 if (p->parse == table[j].callback) {
2512 rvalue = table[j].rvalue;
2513 break;
2514 }
2515
2516 fprintf(f, "%s=%s\n", lvalue, rvalue);
2517 prev = i;
2518 }
2519 }