]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/load-fragment.c
conf: enforce UTF8 validty everywhere
[thirdparty/systemd.git] / src / 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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU 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 }