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