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