]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
core: Add AppArmor profile switching
[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 Copyright 2012 Holger Hans Peter Freyther
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <linux/oom.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sched.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
32 #include <linux/fs.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36
37 #ifdef HAVE_SECCOMP
38 #include <seccomp.h>
39 #endif
40
41 #include "sd-messages.h"
42 #include "unit.h"
43 #include "strv.h"
44 #include "conf-parser.h"
45 #include "load-fragment.h"
46 #include "log.h"
47 #include "ioprio.h"
48 #include "securebits.h"
49 #include "missing.h"
50 #include "unit-name.h"
51 #include "unit-printf.h"
52 #include "utf8.h"
53 #include "path-util.h"
54 #include "env-util.h"
55 #include "cgroup.h"
56 #include "bus-util.h"
57 #include "bus-error.h"
58 #include "errno-list.h"
59
60 #ifdef HAVE_SECCOMP
61 #include "seccomp-util.h"
62 #endif
63
64 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
65 int config_parse_warn_compat(
66 const char *unit,
67 const char *filename,
68 unsigned line,
69 const char *section,
70 unsigned section_line,
71 const char *lvalue,
72 int ltype,
73 const char *rvalue,
74 void *data,
75 void *userdata) {
76
77 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
78 "Support for option %s= has been disabled at compile time and is ignored",
79 lvalue);
80 return 0;
81 }
82 #endif
83
84 int config_parse_unit_deps(const char* unit,
85 const char *filename,
86 unsigned line,
87 const char *section,
88 unsigned section_line,
89 const char *lvalue,
90 int ltype,
91 const char *rvalue,
92 void *data,
93 void *userdata) {
94
95 UnitDependency d = ltype;
96 Unit *u = userdata;
97 char *w;
98 size_t l;
99 char *state;
100
101 assert(filename);
102 assert(lvalue);
103 assert(rvalue);
104
105 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
106 _cleanup_free_ char *t = NULL, *k = NULL;
107 int r;
108
109 t = strndup(w, l);
110 if (!t)
111 return log_oom();
112
113 r = unit_name_printf(u, t, &k);
114 if (r < 0) {
115 log_syntax(unit, LOG_ERR, filename, line, -r,
116 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
117 continue;
118 }
119
120 r = unit_add_dependency_by_name(u, d, k, NULL, true);
121 if (r < 0)
122 log_syntax(unit, LOG_ERR, filename, line, -r,
123 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
124 }
125
126 return 0;
127 }
128
129 int config_parse_unit_string_printf(const char *unit,
130 const char *filename,
131 unsigned line,
132 const char *section,
133 unsigned section_line,
134 const char *lvalue,
135 int ltype,
136 const char *rvalue,
137 void *data,
138 void *userdata) {
139
140 Unit *u = userdata;
141 _cleanup_free_ char *k = NULL;
142 int r;
143
144 assert(filename);
145 assert(lvalue);
146 assert(rvalue);
147 assert(u);
148
149 r = unit_full_printf(u, rvalue, &k);
150 if (r < 0)
151 log_syntax(unit, LOG_ERR, filename, line, -r,
152 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
153
154 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
155 k ? k : rvalue, data, userdata);
156 }
157
158 int config_parse_unit_strv_printf(const char *unit,
159 const char *filename,
160 unsigned line,
161 const char *section,
162 unsigned section_line,
163 const char *lvalue,
164 int ltype,
165 const char *rvalue,
166 void *data,
167 void *userdata) {
168
169 Unit *u = userdata;
170 _cleanup_free_ char *k = NULL;
171 int r;
172
173 assert(filename);
174 assert(lvalue);
175 assert(rvalue);
176 assert(u);
177
178 r = unit_full_printf(u, rvalue, &k);
179 if (r < 0)
180 log_syntax(unit, LOG_ERR, filename, line, -r,
181 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
182
183 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
184 k ? k : rvalue, data, userdata);
185 }
186
187 int config_parse_unit_path_printf(const char *unit,
188 const char *filename,
189 unsigned line,
190 const char *section,
191 unsigned section_line,
192 const char *lvalue,
193 int ltype,
194 const char *rvalue,
195 void *data,
196 void *userdata) {
197
198 Unit *u = userdata;
199 _cleanup_free_ char *k = NULL;
200 int r;
201
202 assert(filename);
203 assert(lvalue);
204 assert(rvalue);
205 assert(u);
206
207 r = unit_full_printf(u, rvalue, &k);
208 if (r < 0)
209 log_syntax(unit, LOG_ERR, filename, line, -r,
210 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
211
212 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
213 k ? k : rvalue, data, userdata);
214 }
215
216 int config_parse_socket_listen(const char *unit,
217 const char *filename,
218 unsigned line,
219 const char *section,
220 unsigned section_line,
221 const char *lvalue,
222 int ltype,
223 const char *rvalue,
224 void *data,
225 void *userdata) {
226
227 SocketPort *p, *tail;
228 Socket *s;
229 int r;
230
231 assert(filename);
232 assert(lvalue);
233 assert(rvalue);
234 assert(data);
235
236 s = SOCKET(data);
237
238 if (isempty(rvalue)) {
239 /* An empty assignment removes all ports */
240 socket_free_ports(s);
241 return 0;
242 }
243
244 p = new0(SocketPort, 1);
245 if (!p)
246 return log_oom();
247
248 if (ltype != SOCKET_SOCKET) {
249
250 p->type = ltype;
251 r = unit_full_printf(UNIT(s), rvalue, &p->path);
252 if (r < 0) {
253 p->path = strdup(rvalue);
254 if (!p->path) {
255 free(p);
256 return log_oom();
257 } else
258 log_syntax(unit, LOG_ERR, filename, line, -r,
259 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
260 }
261
262 path_kill_slashes(p->path);
263
264 } else if (streq(lvalue, "ListenNetlink")) {
265 _cleanup_free_ char *k = NULL;
266
267 p->type = SOCKET_SOCKET;
268 r = unit_full_printf(UNIT(s), rvalue, &k);
269 if (r < 0)
270 log_syntax(unit, LOG_ERR, filename, line, -r,
271 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
272
273 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
274 if (r < 0) {
275 log_syntax(unit, LOG_ERR, filename, line, -r,
276 "Failed to parse address value, ignoring: %s", rvalue);
277 free(p);
278 return 0;
279 }
280
281 } else {
282 _cleanup_free_ char *k = NULL;
283
284 p->type = SOCKET_SOCKET;
285 r = unit_full_printf(UNIT(s), rvalue, &k);
286 if (r < 0)
287 log_syntax(unit, LOG_ERR, filename, line, -r,
288 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
289
290 r = socket_address_parse(&p->address, k ? k : rvalue);
291 if (r < 0) {
292 log_syntax(unit, LOG_ERR, filename, line, -r,
293 "Failed to parse address value, ignoring: %s", rvalue);
294 free(p);
295 return 0;
296 }
297
298 if (streq(lvalue, "ListenStream"))
299 p->address.type = SOCK_STREAM;
300 else if (streq(lvalue, "ListenDatagram"))
301 p->address.type = SOCK_DGRAM;
302 else {
303 assert(streq(lvalue, "ListenSequentialPacket"));
304 p->address.type = SOCK_SEQPACKET;
305 }
306
307 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
308 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
309 "Address family not supported, ignoring: %s", rvalue);
310 free(p);
311 return 0;
312 }
313 }
314
315 p->fd = -1;
316 p->socket = s;
317
318 if (s->ports) {
319 LIST_FIND_TAIL(port, s->ports, tail);
320 LIST_INSERT_AFTER(port, s->ports, tail, p);
321 } else
322 LIST_PREPEND(port, s->ports, p);
323
324 return 0;
325 }
326
327 int config_parse_socket_bind(const char *unit,
328 const char *filename,
329 unsigned line,
330 const char *section,
331 unsigned section_line,
332 const char *lvalue,
333 int ltype,
334 const char *rvalue,
335 void *data,
336 void *userdata) {
337
338 Socket *s;
339 SocketAddressBindIPv6Only b;
340
341 assert(filename);
342 assert(lvalue);
343 assert(rvalue);
344 assert(data);
345
346 s = SOCKET(data);
347
348 b = socket_address_bind_ipv6_only_from_string(rvalue);
349 if (b < 0) {
350 int r;
351
352 r = parse_boolean(rvalue);
353 if (r < 0) {
354 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
355 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
356 return 0;
357 }
358
359 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
360 } else
361 s->bind_ipv6_only = b;
362
363 return 0;
364 }
365
366 int config_parse_exec_nice(const char *unit,
367 const char *filename,
368 unsigned line,
369 const char *section,
370 unsigned section_line,
371 const char *lvalue,
372 int ltype,
373 const char *rvalue,
374 void *data,
375 void *userdata) {
376
377 ExecContext *c = data;
378 int priority, r;
379
380 assert(filename);
381 assert(lvalue);
382 assert(rvalue);
383 assert(data);
384
385 r = safe_atoi(rvalue, &priority);
386 if (r < 0) {
387 log_syntax(unit, LOG_ERR, filename, line, -r,
388 "Failed to parse nice priority, ignoring: %s. ", rvalue);
389 return 0;
390 }
391
392 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
393 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
394 "Nice priority out of range, ignoring: %s", rvalue);
395 return 0;
396 }
397
398 c->nice = priority;
399 c->nice_set = true;
400
401 return 0;
402 }
403
404 int config_parse_exec_oom_score_adjust(const char* unit,
405 const char *filename,
406 unsigned line,
407 const char *section,
408 unsigned section_line,
409 const char *lvalue,
410 int ltype,
411 const char *rvalue,
412 void *data,
413 void *userdata) {
414
415 ExecContext *c = data;
416 int oa, r;
417
418 assert(filename);
419 assert(lvalue);
420 assert(rvalue);
421 assert(data);
422
423 r = safe_atoi(rvalue, &oa);
424 if (r < 0) {
425 log_syntax(unit, LOG_ERR, filename, line, -r,
426 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
427 return 0;
428 }
429
430 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
431 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
432 "OOM score adjust value out of range, ignoring: %s", rvalue);
433 return 0;
434 }
435
436 c->oom_score_adjust = oa;
437 c->oom_score_adjust_set = true;
438
439 return 0;
440 }
441
442 int config_parse_exec(const char *unit,
443 const char *filename,
444 unsigned line,
445 const char *section,
446 unsigned section_line,
447 const char *lvalue,
448 int ltype,
449 const char *rvalue,
450 void *data,
451 void *userdata) {
452
453 ExecCommand **e = data, *nce;
454 char *path, **n;
455 unsigned k;
456 int r;
457
458 assert(filename);
459 assert(lvalue);
460 assert(rvalue);
461 assert(e);
462
463 e += ltype;
464
465 if (isempty(rvalue)) {
466 /* An empty assignment resets the list */
467 exec_command_free_list(*e);
468 *e = NULL;
469 return 0;
470 }
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 for (;;) {
476 int i;
477 char *w;
478 size_t l;
479 char *state;
480 bool honour_argv0 = false, ignore = false;
481
482 path = NULL;
483 nce = NULL;
484 n = NULL;
485
486 rvalue += strspn(rvalue, WHITESPACE);
487
488 if (rvalue[0] == 0)
489 break;
490
491 for (i = 0; i < 2; i++) {
492 if (rvalue[0] == '-' && !ignore) {
493 ignore = true;
494 rvalue ++;
495 }
496
497 if (rvalue[0] == '@' && !honour_argv0) {
498 honour_argv0 = true;
499 rvalue ++;
500 }
501 }
502
503 if (*rvalue != '/') {
504 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
505 "Executable path is not absolute, ignoring: %s", rvalue);
506 return 0;
507 }
508
509 k = 0;
510 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
511 if (strneq(w, ";", MAX(l, 1U)))
512 break;
513
514 k++;
515 }
516
517 n = new(char*, k + !honour_argv0);
518 if (!n)
519 return log_oom();
520
521 k = 0;
522 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
523 if (strneq(w, ";", MAX(l, 1U)))
524 break;
525 else if (strneq(w, "\\;", MAX(l, 1U)))
526 w ++;
527
528 if (honour_argv0 && w == rvalue) {
529 assert(!path);
530
531 path = strndup(w, l);
532 if (!path) {
533 r = log_oom();
534 goto fail;
535 }
536
537 if (!utf8_is_valid(path)) {
538 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
539 "Path is not UTF-8 clean, ignoring assignment: %s",
540 rvalue);
541 r = 0;
542 goto fail;
543 }
544
545 } else {
546 char *c;
547
548 c = n[k++] = cunescape_length(w, l);
549 if (!c) {
550 r = log_oom();
551 goto fail;
552 }
553
554 if (!utf8_is_valid(c)) {
555 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
556 "Path is not UTF-8 clean, ignoring assignment: %s",
557 rvalue);
558 r = 0;
559 goto fail;
560 }
561 }
562 }
563
564 n[k] = NULL;
565
566 if (!n[0]) {
567 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
568 "Invalid command line, ignoring: %s", rvalue);
569 r = 0;
570 goto fail;
571 }
572
573 if (!path) {
574 path = strdup(n[0]);
575 if (!path) {
576 r = log_oom();
577 goto fail;
578 }
579 }
580
581 assert(path_is_absolute(path));
582
583 nce = new0(ExecCommand, 1);
584 if (!nce) {
585 r = log_oom();
586 goto fail;
587 }
588
589 nce->argv = n;
590 nce->path = path;
591 nce->ignore = ignore;
592
593 path_kill_slashes(nce->path);
594
595 exec_command_append_list(e, nce);
596
597 rvalue = state;
598 }
599
600 return 0;
601
602 fail:
603 n[k] = NULL;
604 strv_free(n);
605 free(path);
606 free(nce);
607
608 return r;
609 }
610
611 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
612 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
613
614 int config_parse_socket_bindtodevice(const char* unit,
615 const char *filename,
616 unsigned line,
617 const char *section,
618 unsigned section_line,
619 const char *lvalue,
620 int ltype,
621 const char *rvalue,
622 void *data,
623 void *userdata) {
624
625 Socket *s = data;
626 char *n;
627
628 assert(filename);
629 assert(lvalue);
630 assert(rvalue);
631 assert(data);
632
633 if (rvalue[0] && !streq(rvalue, "*")) {
634 n = strdup(rvalue);
635 if (!n)
636 return log_oom();
637 } else
638 n = NULL;
639
640 free(s->bind_to_device);
641 s->bind_to_device = n;
642
643 return 0;
644 }
645
646 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
647 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
648
649 int config_parse_exec_io_class(const char *unit,
650 const char *filename,
651 unsigned line,
652 const char *section,
653 unsigned section_line,
654 const char *lvalue,
655 int ltype,
656 const char *rvalue,
657 void *data,
658 void *userdata) {
659
660 ExecContext *c = data;
661 int x;
662
663 assert(filename);
664 assert(lvalue);
665 assert(rvalue);
666 assert(data);
667
668 x = ioprio_class_from_string(rvalue);
669 if (x < 0) {
670 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
671 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
672 return 0;
673 }
674
675 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
676 c->ioprio_set = true;
677
678 return 0;
679 }
680
681 int config_parse_exec_io_priority(const char *unit,
682 const char *filename,
683 unsigned line,
684 const char *section,
685 unsigned section_line,
686 const char *lvalue,
687 int ltype,
688 const char *rvalue,
689 void *data,
690 void *userdata) {
691
692 ExecContext *c = data;
693 int i, r;
694
695 assert(filename);
696 assert(lvalue);
697 assert(rvalue);
698 assert(data);
699
700 r = safe_atoi(rvalue, &i);
701 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
702 log_syntax(unit, LOG_ERR, filename, line, -r,
703 "Failed to parse IO priority, ignoring: %s", rvalue);
704 return 0;
705 }
706
707 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
708 c->ioprio_set = true;
709
710 return 0;
711 }
712
713 int config_parse_exec_cpu_sched_policy(const char *unit,
714 const char *filename,
715 unsigned line,
716 const char *section,
717 unsigned section_line,
718 const char *lvalue,
719 int ltype,
720 const char *rvalue,
721 void *data,
722 void *userdata) {
723
724
725 ExecContext *c = data;
726 int x;
727
728 assert(filename);
729 assert(lvalue);
730 assert(rvalue);
731 assert(data);
732
733 x = sched_policy_from_string(rvalue);
734 if (x < 0) {
735 log_syntax(unit, LOG_ERR, filename, line, -x,
736 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
737 return 0;
738 }
739
740 c->cpu_sched_policy = x;
741 /* Moving to or from real-time policy? We need to adjust the priority */
742 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
743 c->cpu_sched_set = true;
744
745 return 0;
746 }
747
748 int config_parse_exec_cpu_sched_prio(const char *unit,
749 const char *filename,
750 unsigned line,
751 const char *section,
752 unsigned section_line,
753 const char *lvalue,
754 int ltype,
755 const char *rvalue,
756 void *data,
757 void *userdata) {
758
759 ExecContext *c = data;
760 int i, min, max, r;
761
762 assert(filename);
763 assert(lvalue);
764 assert(rvalue);
765 assert(data);
766
767 r = safe_atoi(rvalue, &i);
768 if (r < 0) {
769 log_syntax(unit, LOG_ERR, filename, line, -r,
770 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
771 return 0;
772 }
773
774 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
775 min = sched_get_priority_min(c->cpu_sched_policy);
776 max = sched_get_priority_max(c->cpu_sched_policy);
777
778 if (i < min || i > max) {
779 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
780 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
781 return 0;
782 }
783
784 c->cpu_sched_priority = i;
785 c->cpu_sched_set = true;
786
787 return 0;
788 }
789
790 int config_parse_exec_cpu_affinity(const char *unit,
791 const char *filename,
792 unsigned line,
793 const char *section,
794 unsigned section_line,
795 const char *lvalue,
796 int ltype,
797 const char *rvalue,
798 void *data,
799 void *userdata) {
800
801 ExecContext *c = data;
802 char *w;
803 size_t l;
804 char *state;
805
806 assert(filename);
807 assert(lvalue);
808 assert(rvalue);
809 assert(data);
810
811 if (isempty(rvalue)) {
812 /* An empty assignment resets the CPU list */
813 if (c->cpuset)
814 CPU_FREE(c->cpuset);
815 c->cpuset = NULL;
816 return 0;
817 }
818
819 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
820 _cleanup_free_ char *t = NULL;
821 int r;
822 unsigned cpu;
823
824 t = strndup(w, l);
825 if (!t)
826 return log_oom();
827
828 r = safe_atou(t, &cpu);
829
830 if (!c->cpuset) {
831 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
832 if (!c->cpuset)
833 return log_oom();
834 }
835
836 if (r < 0 || cpu >= c->cpuset_ncpus) {
837 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
838 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
839 return 0;
840 }
841
842 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
843 }
844
845 return 0;
846 }
847
848 int config_parse_exec_capabilities(const char *unit,
849 const char *filename,
850 unsigned line,
851 const char *section,
852 unsigned section_line,
853 const char *lvalue,
854 int ltype,
855 const char *rvalue,
856 void *data,
857 void *userdata) {
858
859 ExecContext *c = data;
860 cap_t cap;
861
862 assert(filename);
863 assert(lvalue);
864 assert(rvalue);
865 assert(data);
866
867 cap = cap_from_text(rvalue);
868 if (!cap) {
869 log_syntax(unit, LOG_ERR, filename, line, errno,
870 "Failed to parse capabilities, ignoring: %s", rvalue);
871 return 0;
872 }
873
874 if (c->capabilities)
875 cap_free(c->capabilities);
876 c->capabilities = cap;
877
878 return 0;
879 }
880
881 int config_parse_exec_secure_bits(const char *unit,
882 const char *filename,
883 unsigned line,
884 const char *section,
885 unsigned section_line,
886 const char *lvalue,
887 int ltype,
888 const char *rvalue,
889 void *data,
890 void *userdata) {
891
892 ExecContext *c = data;
893 char *w;
894 size_t l;
895 char *state;
896
897 assert(filename);
898 assert(lvalue);
899 assert(rvalue);
900 assert(data);
901
902 if (isempty(rvalue)) {
903 /* An empty assignment resets the field */
904 c->secure_bits = 0;
905 return 0;
906 }
907
908 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
909 if (first_word(w, "keep-caps"))
910 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
911 else if (first_word(w, "keep-caps-locked"))
912 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
913 else if (first_word(w, "no-setuid-fixup"))
914 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
915 else if (first_word(w, "no-setuid-fixup-locked"))
916 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
917 else if (first_word(w, "noroot"))
918 c->secure_bits |= 1<<SECURE_NOROOT;
919 else if (first_word(w, "noroot-locked"))
920 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
921 else {
922 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
923 "Failed to parse secure bits, ignoring: %s", rvalue);
924 return 0;
925 }
926 }
927
928 return 0;
929 }
930
931 int config_parse_bounding_set(const char *unit,
932 const char *filename,
933 unsigned line,
934 const char *section,
935 unsigned section_line,
936 const char *lvalue,
937 int ltype,
938 const char *rvalue,
939 void *data,
940 void *userdata) {
941
942 uint64_t *capability_bounding_set_drop = data;
943 char *w;
944 size_t l;
945 char *state;
946 bool invert = false;
947 uint64_t sum = 0;
948
949 assert(filename);
950 assert(lvalue);
951 assert(rvalue);
952 assert(data);
953
954 if (rvalue[0] == '~') {
955 invert = true;
956 rvalue++;
957 }
958
959 /* Note that we store this inverted internally, since the
960 * kernel wants it like this. But we actually expose it
961 * non-inverted everywhere to have a fully normalized
962 * interface. */
963
964 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
965 _cleanup_free_ char *t = NULL;
966 int r;
967 cap_value_t cap;
968
969 t = strndup(w, l);
970 if (!t)
971 return log_oom();
972
973 r = cap_from_name(t, &cap);
974 if (r < 0) {
975 log_syntax(unit, LOG_ERR, filename, line, errno,
976 "Failed to parse capability in bounding set, ignoring: %s", t);
977 continue;
978 }
979
980 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
981 }
982
983 if (invert)
984 *capability_bounding_set_drop |= sum;
985 else
986 *capability_bounding_set_drop |= ~sum;
987
988 return 0;
989 }
990
991 int config_parse_limit(const char *unit,
992 const char *filename,
993 unsigned line,
994 const char *section,
995 unsigned section_line,
996 const char *lvalue,
997 int ltype,
998 const char *rvalue,
999 void *data,
1000 void *userdata) {
1001
1002 struct rlimit **rl = data;
1003 unsigned long long u;
1004
1005 assert(filename);
1006 assert(lvalue);
1007 assert(rvalue);
1008 assert(data);
1009
1010 rl += ltype;
1011
1012 if (streq(rvalue, "infinity"))
1013 u = (unsigned long long) RLIM_INFINITY;
1014 else {
1015 int r;
1016
1017 r = safe_atollu(rvalue, &u);
1018 if (r < 0) {
1019 log_syntax(unit, LOG_ERR, filename, line, -r,
1020 "Failed to parse resource value, ignoring: %s", rvalue);
1021 return 0;
1022 }
1023 }
1024
1025 if (!*rl) {
1026 *rl = new(struct rlimit, 1);
1027 if (!*rl)
1028 return log_oom();
1029 }
1030
1031 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1032 return 0;
1033 }
1034
1035 #ifdef HAVE_SYSV_COMPAT
1036 int config_parse_sysv_priority(const char *unit,
1037 const char *filename,
1038 unsigned line,
1039 const char *section,
1040 unsigned section_line,
1041 const char *lvalue,
1042 int ltype,
1043 const char *rvalue,
1044 void *data,
1045 void *userdata) {
1046
1047 int *priority = data;
1048 int i, r;
1049
1050 assert(filename);
1051 assert(lvalue);
1052 assert(rvalue);
1053 assert(data);
1054
1055 r = safe_atoi(rvalue, &i);
1056 if (r < 0 || i < 0) {
1057 log_syntax(unit, LOG_ERR, filename, line, -r,
1058 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1059 return 0;
1060 }
1061
1062 *priority = (int) i;
1063 return 0;
1064 }
1065 #endif
1066
1067 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1068
1069 int config_parse_kill_signal(const char *unit,
1070 const char *filename,
1071 unsigned line,
1072 const char *section,
1073 unsigned section_line,
1074 const char *lvalue,
1075 int ltype,
1076 const char *rvalue,
1077 void *data,
1078 void *userdata) {
1079
1080 int *sig = data;
1081 int r;
1082
1083 assert(filename);
1084 assert(lvalue);
1085 assert(rvalue);
1086 assert(sig);
1087
1088 r = signal_from_string_try_harder(rvalue);
1089 if (r <= 0) {
1090 log_syntax(unit, LOG_ERR, filename, line, -r,
1091 "Failed to parse kill signal, ignoring: %s", rvalue);
1092 return 0;
1093 }
1094
1095 *sig = r;
1096 return 0;
1097 }
1098
1099 int config_parse_exec_mount_flags(const char *unit,
1100 const char *filename,
1101 unsigned line,
1102 const char *section,
1103 unsigned section_line,
1104 const char *lvalue,
1105 int ltype,
1106 const char *rvalue,
1107 void *data,
1108 void *userdata) {
1109
1110 ExecContext *c = data;
1111 char *w;
1112 size_t l;
1113 char *state;
1114 unsigned long flags = 0;
1115
1116 assert(filename);
1117 assert(lvalue);
1118 assert(rvalue);
1119 assert(data);
1120
1121 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1122 _cleanup_free_ char *t;
1123
1124 t = strndup(w, l);
1125 if (!t)
1126 return log_oom();
1127
1128 if (streq(t, "shared"))
1129 flags |= MS_SHARED;
1130 else if (streq(t, "slave"))
1131 flags |= MS_SLAVE;
1132 else if (streq(w, "private"))
1133 flags |= MS_PRIVATE;
1134 else {
1135 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1136 "Failed to parse mount flag %s, ignoring: %s",
1137 t, rvalue);
1138 return 0;
1139 }
1140 }
1141
1142 c->mount_flags = flags;
1143 return 0;
1144 }
1145
1146 int config_parse_exec_selinux_context(
1147 const char *unit,
1148 const char *filename,
1149 unsigned line,
1150 const char *section,
1151 unsigned section_line,
1152 const char *lvalue,
1153 int ltype,
1154 const char *rvalue,
1155 void *data,
1156 void *userdata) {
1157
1158 ExecContext *c = data;
1159 Unit *u = userdata;
1160 bool ignore;
1161 char *k;
1162 int r;
1163
1164 assert(filename);
1165 assert(lvalue);
1166 assert(rvalue);
1167 assert(data);
1168
1169 if (isempty(rvalue)) {
1170 free(c->selinux_context);
1171 c->selinux_context = NULL;
1172 c->selinux_context_ignore = false;
1173 return 0;
1174 }
1175
1176 if (rvalue[0] == '-') {
1177 ignore = true;
1178 rvalue++;
1179 } else
1180 ignore = false;
1181
1182 r = unit_name_printf(u, rvalue, &k);
1183 if (r < 0) {
1184 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1185 return 0;
1186 }
1187
1188 free(c->selinux_context);
1189 c->selinux_context = k;
1190 c->selinux_context_ignore = ignore;
1191
1192 return 0;
1193 }
1194
1195 int config_parse_exec_apparmor_profile(
1196 const char *unit,
1197 const char *filename,
1198 unsigned line,
1199 const char *section,
1200 unsigned section_line,
1201 const char *lvalue,
1202 int ltype,
1203 const char *rvalue,
1204 void *data,
1205 void *userdata) {
1206
1207 ExecContext *c = data;
1208 Unit *u = userdata;
1209 bool ignore;
1210 char *k;
1211 int r;
1212
1213 assert(filename);
1214 assert(lvalue);
1215 assert(rvalue);
1216 assert(data);
1217
1218 if (isempty(rvalue)) {
1219 free(c->apparmor_profile);
1220 c->apparmor_profile = NULL;
1221 c->apparmor_profile_ignore = false;
1222 return 0;
1223 }
1224
1225 if (rvalue[0] == '-') {
1226 ignore = true;
1227 rvalue++;
1228 } else
1229 ignore = false;
1230
1231 r = unit_name_printf(u, rvalue, &k);
1232 if (r < 0) {
1233 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1234 return 0;
1235 }
1236
1237 free(c->apparmor_profile);
1238 c->apparmor_profile = k;
1239 c->apparmor_profile_ignore = ignore;
1240
1241 return 0;
1242 }
1243
1244 int config_parse_timer(const char *unit,
1245 const char *filename,
1246 unsigned line,
1247 const char *section,
1248 unsigned section_line,
1249 const char *lvalue,
1250 int ltype,
1251 const char *rvalue,
1252 void *data,
1253 void *userdata) {
1254
1255 Timer *t = data;
1256 usec_t u = 0;
1257 TimerValue *v;
1258 TimerBase b;
1259 CalendarSpec *c = NULL;
1260 clockid_t id;
1261
1262 assert(filename);
1263 assert(lvalue);
1264 assert(rvalue);
1265 assert(data);
1266
1267 if (isempty(rvalue)) {
1268 /* Empty assignment resets list */
1269 timer_free_values(t);
1270 return 0;
1271 }
1272
1273 b = timer_base_from_string(lvalue);
1274 if (b < 0) {
1275 log_syntax(unit, LOG_ERR, filename, line, -b,
1276 "Failed to parse timer base, ignoring: %s", lvalue);
1277 return 0;
1278 }
1279
1280 if (b == TIMER_CALENDAR) {
1281 if (calendar_spec_from_string(rvalue, &c) < 0) {
1282 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1283 "Failed to parse calendar specification, ignoring: %s",
1284 rvalue);
1285 return 0;
1286 }
1287
1288 id = CLOCK_REALTIME;
1289 } else {
1290 if (parse_sec(rvalue, &u) < 0) {
1291 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1292 "Failed to parse timer value, ignoring: %s",
1293 rvalue);
1294 return 0;
1295 }
1296
1297 id = CLOCK_MONOTONIC;
1298 }
1299
1300 v = new0(TimerValue, 1);
1301 if (!v)
1302 return log_oom();
1303
1304 v->base = b;
1305 v->clock_id = id;
1306 v->value = u;
1307 v->calendar_spec = c;
1308
1309 LIST_PREPEND(value, t->values, v);
1310
1311 return 0;
1312 }
1313
1314 int config_parse_trigger_unit(
1315 const char *unit,
1316 const char *filename,
1317 unsigned line,
1318 const char *section,
1319 unsigned section_line,
1320 const char *lvalue,
1321 int ltype,
1322 const char *rvalue,
1323 void *data,
1324 void *userdata) {
1325
1326 _cleanup_free_ char *p = NULL;
1327 Unit *u = data;
1328 UnitType type;
1329 int r;
1330
1331 assert(filename);
1332 assert(lvalue);
1333 assert(rvalue);
1334 assert(data);
1335
1336 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1338 "Multiple units to trigger specified, ignoring: %s", rvalue);
1339 return 0;
1340 }
1341
1342 r = unit_name_printf(u, rvalue, &p);
1343 if (r < 0)
1344 log_syntax(unit, LOG_ERR, filename, line, -r,
1345 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1346
1347 type = unit_name_to_type(p ?: rvalue);
1348 if (type < 0) {
1349 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1350 "Unit type not valid, ignoring: %s", rvalue);
1351 return 0;
1352 }
1353
1354 if (type == u->type) {
1355 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1356 "Trigger cannot be of same type, ignoring: %s", rvalue);
1357 return 0;
1358 }
1359
1360 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1361 if (r < 0) {
1362 log_syntax(unit, LOG_ERR, filename, line, -r,
1363 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1364 return 0;
1365 }
1366
1367 return 0;
1368 }
1369
1370 int config_parse_path_spec(const char *unit,
1371 const char *filename,
1372 unsigned line,
1373 const char *section,
1374 unsigned section_line,
1375 const char *lvalue,
1376 int ltype,
1377 const char *rvalue,
1378 void *data,
1379 void *userdata) {
1380
1381 Path *p = data;
1382 PathSpec *s;
1383 PathType b;
1384 _cleanup_free_ char *k = NULL;
1385 int r;
1386
1387 assert(filename);
1388 assert(lvalue);
1389 assert(rvalue);
1390 assert(data);
1391
1392 if (isempty(rvalue)) {
1393 /* Empty assignment clears list */
1394 path_free_specs(p);
1395 return 0;
1396 }
1397
1398 b = path_type_from_string(lvalue);
1399 if (b < 0) {
1400 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1401 "Failed to parse path type, ignoring: %s", lvalue);
1402 return 0;
1403 }
1404
1405 r = unit_full_printf(UNIT(p), rvalue, &k);
1406 if (r < 0) {
1407 k = strdup(rvalue);
1408 if (!k)
1409 return log_oom();
1410 else
1411 log_syntax(unit, LOG_ERR, filename, line, -r,
1412 "Failed to resolve unit specifiers on %s. Ignoring.",
1413 rvalue);
1414 }
1415
1416 if (!path_is_absolute(k)) {
1417 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1418 "Path is not absolute, ignoring: %s", k);
1419 return 0;
1420 }
1421
1422 s = new0(PathSpec, 1);
1423 if (!s)
1424 return log_oom();
1425
1426 s->unit = UNIT(p);
1427 s->path = path_kill_slashes(k);
1428 k = NULL;
1429 s->type = b;
1430 s->inotify_fd = -1;
1431
1432 LIST_PREPEND(spec, p->specs, s);
1433
1434 return 0;
1435 }
1436
1437 int config_parse_socket_service(const char *unit,
1438 const char *filename,
1439 unsigned line,
1440 const char *section,
1441 unsigned section_line,
1442 const char *lvalue,
1443 int ltype,
1444 const char *rvalue,
1445 void *data,
1446 void *userdata) {
1447
1448 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1449 Socket *s = data;
1450 int r;
1451 Unit *x;
1452 _cleanup_free_ char *p = NULL;
1453
1454 assert(filename);
1455 assert(lvalue);
1456 assert(rvalue);
1457 assert(data);
1458
1459 r = unit_name_printf(UNIT(s), rvalue, &p);
1460 if (r < 0) {
1461 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1462 return 0;
1463 }
1464
1465 if (!endswith(p, ".service")) {
1466 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1467 return 0;
1468 }
1469
1470 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1471 if (r < 0) {
1472 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1473 return 0;
1474 }
1475
1476 unit_ref_set(&s->service, x);
1477
1478 return 0;
1479 }
1480
1481 int config_parse_service_sockets(const char *unit,
1482 const char *filename,
1483 unsigned line,
1484 const char *section,
1485 unsigned section_line,
1486 const char *lvalue,
1487 int ltype,
1488 const char *rvalue,
1489 void *data,
1490 void *userdata) {
1491
1492 Service *s = data;
1493 int r;
1494 char *state, *w;
1495 size_t l;
1496
1497 assert(filename);
1498 assert(lvalue);
1499 assert(rvalue);
1500 assert(data);
1501
1502 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1503 _cleanup_free_ char *t = NULL, *k = NULL;
1504
1505 t = strndup(w, l);
1506 if (!t)
1507 return log_oom();
1508
1509 r = unit_name_printf(UNIT(s), t, &k);
1510 if (r < 0)
1511 log_syntax(unit, LOG_ERR, filename, line, -r,
1512 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1513
1514 if (!endswith(k ?: t, ".socket")) {
1515 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1516 "Unit must be of type socket, ignoring: %s", k ?: t);
1517 continue;
1518 }
1519
1520 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1521 if (r < 0)
1522 log_syntax(unit, LOG_ERR, filename, line, -r,
1523 "Failed to add dependency on %s, ignoring: %s",
1524 k ?: t, strerror(-r));
1525
1526 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1527 if (r < 0)
1528 return r;
1529 }
1530
1531 return 0;
1532 }
1533
1534 int config_parse_service_timeout(const char *unit,
1535 const char *filename,
1536 unsigned line,
1537 const char *section,
1538 unsigned section_line,
1539 const char *lvalue,
1540 int ltype,
1541 const char *rvalue,
1542 void *data,
1543 void *userdata) {
1544
1545 Service *s = userdata;
1546 int r;
1547
1548 assert(filename);
1549 assert(lvalue);
1550 assert(rvalue);
1551 assert(s);
1552
1553 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1554 rvalue, data, userdata);
1555 if (r < 0)
1556 return r;
1557
1558 if (streq(lvalue, "TimeoutSec")) {
1559 s->start_timeout_defined = true;
1560 s->timeout_stop_usec = s->timeout_start_usec;
1561 } else if (streq(lvalue, "TimeoutStartSec"))
1562 s->start_timeout_defined = true;
1563
1564 return 0;
1565 }
1566
1567 int config_parse_busname_service(
1568 const char *unit,
1569 const char *filename,
1570 unsigned line,
1571 const char *section,
1572 unsigned section_line,
1573 const char *lvalue,
1574 int ltype,
1575 const char *rvalue,
1576 void *data,
1577 void *userdata) {
1578
1579 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1580 BusName *n = data;
1581 int r;
1582 Unit *x;
1583 _cleanup_free_ char *p = NULL;
1584
1585 assert(filename);
1586 assert(lvalue);
1587 assert(rvalue);
1588 assert(data);
1589
1590 r = unit_name_printf(UNIT(n), rvalue, &p);
1591 if (r < 0) {
1592 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1593 return 0;
1594 }
1595
1596 if (!endswith(p, ".service")) {
1597 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1598 return 0;
1599 }
1600
1601 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1602 if (r < 0) {
1603 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1604 return 0;
1605 }
1606
1607 unit_ref_set(&n->service, x);
1608
1609 return 0;
1610 }
1611
1612 int config_parse_unit_env_file(const char *unit,
1613 const char *filename,
1614 unsigned line,
1615 const char *section,
1616 unsigned section_line,
1617 const char *lvalue,
1618 int ltype,
1619 const char *rvalue,
1620 void *data,
1621 void *userdata) {
1622
1623 char ***env = data;
1624 Unit *u = userdata;
1625 _cleanup_free_ char *n = NULL;
1626 const char *s;
1627 int r;
1628
1629 assert(filename);
1630 assert(lvalue);
1631 assert(rvalue);
1632 assert(data);
1633
1634 if (isempty(rvalue)) {
1635 /* Empty assignment frees the list */
1636 strv_free(*env);
1637 *env = NULL;
1638 return 0;
1639 }
1640
1641 r = unit_full_printf(u, rvalue, &n);
1642 if (r < 0)
1643 log_syntax(unit, LOG_ERR, filename, line, r,
1644 "Failed to resolve specifiers, ignoring: %s", rvalue);
1645
1646 s = n ?: rvalue;
1647 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1648 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1649 "Path '%s' is not absolute, ignoring.", s);
1650 return 0;
1651 }
1652
1653 r = strv_extend(env, s);
1654 if (r < 0)
1655 return log_oom();
1656
1657 return 0;
1658 }
1659
1660 int config_parse_environ(const char *unit,
1661 const char *filename,
1662 unsigned line,
1663 const char *section,
1664 unsigned section_line,
1665 const char *lvalue,
1666 int ltype,
1667 const char *rvalue,
1668 void *data,
1669 void *userdata) {
1670
1671 Unit *u = userdata;
1672 char*** env = data, *w, *state;
1673 size_t l;
1674 _cleanup_free_ char *k = NULL;
1675 int r;
1676
1677 assert(filename);
1678 assert(lvalue);
1679 assert(rvalue);
1680 assert(data);
1681
1682 if (isempty(rvalue)) {
1683 /* Empty assignment resets the list */
1684 strv_free(*env);
1685 *env = NULL;
1686 return 0;
1687 }
1688
1689 if (u) {
1690 r = unit_full_printf(u, rvalue, &k);
1691 if (r < 0)
1692 log_syntax(unit, LOG_ERR, filename, line, -r,
1693 "Failed to resolve specifiers, ignoring: %s", rvalue);
1694 }
1695
1696 if (!k)
1697 k = strdup(rvalue);
1698 if (!k)
1699 return log_oom();
1700
1701 FOREACH_WORD_QUOTED(w, l, k, state) {
1702 _cleanup_free_ char *n;
1703 char **x;
1704
1705 n = cunescape_length(w, l);
1706 if (!n)
1707 return log_oom();
1708
1709 if (!env_assignment_is_valid(n)) {
1710 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1711 "Invalid environment assignment, ignoring: %s", rvalue);
1712 continue;
1713 }
1714
1715 x = strv_env_set(*env, n);
1716 if (!x)
1717 return log_oom();
1718
1719 strv_free(*env);
1720 *env = x;
1721 }
1722
1723 return 0;
1724 }
1725
1726 int config_parse_ip_tos(const char *unit,
1727 const char *filename,
1728 unsigned line,
1729 const char *section,
1730 unsigned section_line,
1731 const char *lvalue,
1732 int ltype,
1733 const char *rvalue,
1734 void *data,
1735 void *userdata) {
1736
1737 int *ip_tos = data, x;
1738
1739 assert(filename);
1740 assert(lvalue);
1741 assert(rvalue);
1742 assert(data);
1743
1744 x = ip_tos_from_string(rvalue);
1745 if (x < 0) {
1746 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1747 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1748 return 0;
1749 }
1750
1751 *ip_tos = x;
1752 return 0;
1753 }
1754
1755 int config_parse_unit_condition_path(const char *unit,
1756 const char *filename,
1757 unsigned line,
1758 const char *section,
1759 unsigned section_line,
1760 const char *lvalue,
1761 int ltype,
1762 const char *rvalue,
1763 void *data,
1764 void *userdata) {
1765
1766 ConditionType cond = ltype;
1767 Unit *u = data;
1768 bool trigger, negate;
1769 Condition *c;
1770 _cleanup_free_ char *p = NULL;
1771 int r;
1772
1773 assert(filename);
1774 assert(lvalue);
1775 assert(rvalue);
1776 assert(data);
1777
1778 if (isempty(rvalue)) {
1779 /* Empty assignment resets the list */
1780 condition_free_list(u->conditions);
1781 u->conditions = NULL;
1782 return 0;
1783 }
1784
1785 trigger = rvalue[0] == '|';
1786 if (trigger)
1787 rvalue++;
1788
1789 negate = rvalue[0] == '!';
1790 if (negate)
1791 rvalue++;
1792
1793 r = unit_full_printf(u, rvalue, &p);
1794 if (r < 0)
1795 log_syntax(unit, LOG_ERR, filename, line, -r,
1796 "Failed to resolve specifiers, ignoring: %s", rvalue);
1797 if (!p) {
1798 p = strdup(rvalue);
1799 if (!p)
1800 return log_oom();
1801 }
1802
1803 if (!path_is_absolute(p)) {
1804 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1805 "Path in condition not absolute, ignoring: %s", p);
1806 return 0;
1807 }
1808
1809 c = condition_new(cond, p, trigger, negate);
1810 if (!c)
1811 return log_oom();
1812
1813 LIST_PREPEND(conditions, u->conditions, c);
1814 return 0;
1815 }
1816
1817 int config_parse_unit_condition_string(const char *unit,
1818 const char *filename,
1819 unsigned line,
1820 const char *section,
1821 unsigned section_line,
1822 const char *lvalue,
1823 int ltype,
1824 const char *rvalue,
1825 void *data,
1826 void *userdata) {
1827
1828 ConditionType cond = ltype;
1829 Unit *u = data;
1830 bool trigger, negate;
1831 Condition *c;
1832 _cleanup_free_ char *s = NULL;
1833 int r;
1834
1835 assert(filename);
1836 assert(lvalue);
1837 assert(rvalue);
1838 assert(data);
1839
1840 if (isempty(rvalue)) {
1841 /* Empty assignment resets the list */
1842 condition_free_list(u->conditions);
1843 u->conditions = NULL;
1844 return 0;
1845 }
1846
1847 trigger = rvalue[0] == '|';
1848 if (trigger)
1849 rvalue++;
1850
1851 negate = rvalue[0] == '!';
1852 if (negate)
1853 rvalue++;
1854
1855 r = unit_full_printf(u, rvalue, &s);
1856 if (r < 0)
1857 log_syntax(unit, LOG_ERR, filename, line, -r,
1858 "Failed to resolve specifiers, ignoring: %s", rvalue);
1859 if (!s) {
1860 s = strdup(rvalue);
1861 if (!s)
1862 return log_oom();
1863 }
1864
1865 c = condition_new(cond, s, trigger, negate);
1866 if (!c)
1867 return log_oom();
1868
1869 LIST_PREPEND(conditions, u->conditions, c);
1870 return 0;
1871 }
1872
1873 int config_parse_unit_condition_null(const char *unit,
1874 const char *filename,
1875 unsigned line,
1876 const char *section,
1877 unsigned section_line,
1878 const char *lvalue,
1879 int ltype,
1880 const char *rvalue,
1881 void *data,
1882 void *userdata) {
1883
1884 Unit *u = data;
1885 Condition *c;
1886 bool trigger, negate;
1887 int b;
1888
1889 assert(filename);
1890 assert(lvalue);
1891 assert(rvalue);
1892 assert(data);
1893
1894 if (isempty(rvalue)) {
1895 /* Empty assignment resets the list */
1896 condition_free_list(u->conditions);
1897 u->conditions = NULL;
1898 return 0;
1899 }
1900
1901 trigger = rvalue[0] == '|';
1902 if (trigger)
1903 rvalue++;
1904
1905 negate = rvalue[0] == '!';
1906 if (negate)
1907 rvalue++;
1908
1909 b = parse_boolean(rvalue);
1910 if (b < 0) {
1911 log_syntax(unit, LOG_ERR, filename, line, -b,
1912 "Failed to parse boolean value in condition, ignoring: %s",
1913 rvalue);
1914 return 0;
1915 }
1916
1917 if (!b)
1918 negate = !negate;
1919
1920 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1921 if (!c)
1922 return log_oom();
1923
1924 LIST_PREPEND(conditions, u->conditions, c);
1925 return 0;
1926 }
1927
1928 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1929 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1930
1931 int config_parse_unit_requires_mounts_for(
1932 const char *unit,
1933 const char *filename,
1934 unsigned line,
1935 const char *section,
1936 unsigned section_line,
1937 const char *lvalue,
1938 int ltype,
1939 const char *rvalue,
1940 void *data,
1941 void *userdata) {
1942
1943 Unit *u = userdata;
1944 char *state;
1945 size_t l;
1946 char *w;
1947
1948 assert(filename);
1949 assert(lvalue);
1950 assert(rvalue);
1951 assert(data);
1952
1953 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1954 int r;
1955 _cleanup_free_ char *n;
1956
1957 n = strndup(w, l);
1958 if (!n)
1959 return log_oom();
1960
1961 if (!utf8_is_valid(n)) {
1962 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1963 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1964 continue;
1965 }
1966
1967 r = unit_require_mounts_for(u, n);
1968 if (r < 0) {
1969 log_syntax(unit, LOG_ERR, filename, line, r,
1970 "Failed to add required mount for, ignoring: %s", rvalue);
1971 continue;
1972 }
1973 }
1974
1975 return 0;
1976 }
1977
1978 int config_parse_documentation(const char *unit,
1979 const char *filename,
1980 unsigned line,
1981 const char *section,
1982 unsigned section_line,
1983 const char *lvalue,
1984 int ltype,
1985 const char *rvalue,
1986 void *data,
1987 void *userdata) {
1988
1989 Unit *u = userdata;
1990 int r;
1991 char **a, **b;
1992
1993 assert(filename);
1994 assert(lvalue);
1995 assert(rvalue);
1996 assert(u);
1997
1998 if (isempty(rvalue)) {
1999 /* Empty assignment resets the list */
2000 strv_free(u->documentation);
2001 u->documentation = NULL;
2002 return 0;
2003 }
2004
2005 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2006 rvalue, data, userdata);
2007 if (r < 0)
2008 return r;
2009
2010 for (a = b = u->documentation; a && *a; a++) {
2011
2012 if (is_valid_documentation_url(*a))
2013 *(b++) = *a;
2014 else {
2015 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2016 "Invalid URL, ignoring: %s", *a);
2017 free(*a);
2018 }
2019 }
2020 if (b)
2021 *b = NULL;
2022
2023 return r;
2024 }
2025
2026 #ifdef HAVE_SECCOMP
2027 int config_parse_syscall_filter(
2028 const char *unit,
2029 const char *filename,
2030 unsigned line,
2031 const char *section,
2032 unsigned section_line,
2033 const char *lvalue,
2034 int ltype,
2035 const char *rvalue,
2036 void *data,
2037 void *userdata) {
2038
2039 static const char default_syscalls[] =
2040 "execve\0"
2041 "exit\0"
2042 "exit_group\0"
2043 "rt_sigreturn\0"
2044 "sigreturn\0";
2045
2046 ExecContext *c = data;
2047 Unit *u = userdata;
2048 bool invert = false;
2049 char *w, *state;
2050 size_t l;
2051 int r;
2052
2053 assert(filename);
2054 assert(lvalue);
2055 assert(rvalue);
2056 assert(u);
2057
2058 if (isempty(rvalue)) {
2059 /* Empty assignment resets the list */
2060 set_free(c->syscall_filter);
2061 c->syscall_filter = NULL;
2062 c->syscall_whitelist = false;
2063 return 0;
2064 }
2065
2066 if (rvalue[0] == '~') {
2067 invert = true;
2068 rvalue++;
2069 }
2070
2071 if (!c->syscall_filter) {
2072 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2073 if (!c->syscall_filter)
2074 return log_oom();
2075
2076 if (invert)
2077 /* Allow everything but the ones listed */
2078 c->syscall_whitelist = false;
2079 else {
2080 const char *i;
2081
2082 /* Allow nothing but the ones listed */
2083 c->syscall_whitelist = true;
2084
2085 /* Accept default syscalls if we are on a whitelist */
2086 NULSTR_FOREACH(i, default_syscalls) {
2087 int id;
2088
2089 id = seccomp_syscall_resolve_name(i);
2090 if (id < 0)
2091 continue;
2092
2093 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2094 if (r == -EEXIST)
2095 continue;
2096 if (r < 0)
2097 return log_oom();
2098 }
2099 }
2100 }
2101
2102 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2103 _cleanup_free_ char *t = NULL;
2104 int id;
2105
2106 t = strndup(w, l);
2107 if (!t)
2108 return log_oom();
2109
2110 id = seccomp_syscall_resolve_name(t);
2111 if (id < 0) {
2112 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2113 continue;
2114 }
2115
2116 /* If we previously wanted to forbid a syscall and now
2117 * we want to allow it, then remove it from the list
2118 */
2119 if (!invert == c->syscall_whitelist) {
2120 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2121 if (r == -EEXIST)
2122 continue;
2123 if (r < 0)
2124 return log_oom();
2125 } else
2126 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2127 }
2128
2129 c->no_new_privileges = true;
2130
2131 return 0;
2132 }
2133
2134 int config_parse_syscall_archs(
2135 const char *unit,
2136 const char *filename,
2137 unsigned line,
2138 const char *section,
2139 unsigned section_line,
2140 const char *lvalue,
2141 int ltype,
2142 const char *rvalue,
2143 void *data,
2144 void *userdata) {
2145
2146 Set **archs = data;
2147 char *w, *state;
2148 size_t l;
2149 int r;
2150
2151 if (isempty(rvalue)) {
2152 set_free(*archs);
2153 *archs = NULL;
2154 return 0;
2155 }
2156
2157 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2158 if (r < 0)
2159 return log_oom();
2160
2161 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2162 _cleanup_free_ char *t = NULL;
2163 uint32_t a;
2164
2165 t = strndup(w, l);
2166 if (!t)
2167 return log_oom();
2168
2169 r = seccomp_arch_from_string(t, &a);
2170 if (r < 0) {
2171 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2172 continue;
2173 }
2174
2175 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2176 if (r == -EEXIST)
2177 continue;
2178 if (r < 0)
2179 return log_oom();
2180 }
2181
2182 return 0;
2183 }
2184
2185 int config_parse_syscall_errno(
2186 const char *unit,
2187 const char *filename,
2188 unsigned line,
2189 const char *section,
2190 unsigned section_line,
2191 const char *lvalue,
2192 int ltype,
2193 const char *rvalue,
2194 void *data,
2195 void *userdata) {
2196
2197 ExecContext *c = data;
2198 int e;
2199
2200 assert(filename);
2201 assert(lvalue);
2202 assert(rvalue);
2203
2204 if (isempty(rvalue)) {
2205 /* Empty assignment resets to KILL */
2206 c->syscall_errno = 0;
2207 return 0;
2208 }
2209
2210 e = errno_from_name(rvalue);
2211 if (e < 0) {
2212 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2213 return 0;
2214 }
2215
2216 c->syscall_errno = e;
2217 return 0;
2218 }
2219 #endif
2220
2221 int config_parse_unit_slice(
2222 const char *unit,
2223 const char *filename,
2224 unsigned line,
2225 const char *section,
2226 unsigned section_line,
2227 const char *lvalue,
2228 int ltype,
2229 const char *rvalue,
2230 void *data,
2231 void *userdata) {
2232
2233 _cleanup_free_ char *k = NULL;
2234 Unit *u = userdata, *slice;
2235 int r;
2236
2237 assert(filename);
2238 assert(lvalue);
2239 assert(rvalue);
2240 assert(u);
2241
2242 r = unit_name_printf(u, rvalue, &k);
2243 if (r < 0)
2244 log_syntax(unit, LOG_ERR, filename, line, -r,
2245 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2246 if (!k) {
2247 k = strdup(rvalue);
2248 if (!k)
2249 return log_oom();
2250 }
2251
2252 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2253 if (r < 0) {
2254 log_syntax(unit, LOG_ERR, filename, line, -r,
2255 "Failed to load slice unit %s. Ignoring.", k);
2256 return 0;
2257 }
2258
2259 if (slice->type != UNIT_SLICE) {
2260 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2261 "Slice unit %s is not a slice. Ignoring.", k);
2262 return 0;
2263 }
2264
2265 unit_ref_set(&u->slice, slice);
2266 return 0;
2267 }
2268
2269 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2270
2271 int config_parse_cpu_shares(
2272 const char *unit,
2273 const char *filename,
2274 unsigned line,
2275 const char *section,
2276 unsigned section_line,
2277 const char *lvalue,
2278 int ltype,
2279 const char *rvalue,
2280 void *data,
2281 void *userdata) {
2282
2283 CGroupContext *c = data;
2284 unsigned long lu;
2285 int r;
2286
2287 assert(filename);
2288 assert(lvalue);
2289 assert(rvalue);
2290
2291 if (isempty(rvalue)) {
2292 c->cpu_shares = 1024;
2293 return 0;
2294 }
2295
2296 r = safe_atolu(rvalue, &lu);
2297 if (r < 0 || lu <= 0) {
2298 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2299 "CPU shares '%s' invalid. Ignoring.", rvalue);
2300 return 0;
2301 }
2302
2303 c->cpu_shares = lu;
2304 return 0;
2305 }
2306
2307 int config_parse_memory_limit(
2308 const char *unit,
2309 const char *filename,
2310 unsigned line,
2311 const char *section,
2312 unsigned section_line,
2313 const char *lvalue,
2314 int ltype,
2315 const char *rvalue,
2316 void *data,
2317 void *userdata) {
2318
2319 CGroupContext *c = data;
2320 off_t bytes;
2321 int r;
2322
2323 if (isempty(rvalue)) {
2324 c->memory_limit = (uint64_t) -1;
2325 return 0;
2326 }
2327
2328 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2329
2330 r = parse_bytes(rvalue, &bytes);
2331 if (r < 0) {
2332 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2333 "Memory limit '%s' invalid. Ignoring.", rvalue);
2334 return 0;
2335 }
2336
2337 c->memory_limit = (uint64_t) bytes;
2338 return 0;
2339 }
2340
2341 int config_parse_device_allow(
2342 const char *unit,
2343 const char *filename,
2344 unsigned line,
2345 const char *section,
2346 unsigned section_line,
2347 const char *lvalue,
2348 int ltype,
2349 const char *rvalue,
2350 void *data,
2351 void *userdata) {
2352
2353 _cleanup_free_ char *path = NULL;
2354 CGroupContext *c = data;
2355 CGroupDeviceAllow *a;
2356 const char *m;
2357 size_t n;
2358
2359 if (isempty(rvalue)) {
2360 while (c->device_allow)
2361 cgroup_context_free_device_allow(c, c->device_allow);
2362
2363 return 0;
2364 }
2365
2366 n = strcspn(rvalue, WHITESPACE);
2367 path = strndup(rvalue, n);
2368 if (!path)
2369 return log_oom();
2370
2371 if (!path_startswith(path, "/dev")) {
2372 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2373 "Invalid device node path '%s'. Ignoring.", path);
2374 return 0;
2375 }
2376
2377 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2378 if (isempty(m))
2379 m = "rwm";
2380
2381 if (!in_charset(m, "rwm")) {
2382 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2383 "Invalid device rights '%s'. Ignoring.", m);
2384 return 0;
2385 }
2386
2387 a = new0(CGroupDeviceAllow, 1);
2388 if (!a)
2389 return log_oom();
2390
2391 a->path = path;
2392 path = NULL;
2393 a->r = !!strchr(m, 'r');
2394 a->w = !!strchr(m, 'w');
2395 a->m = !!strchr(m, 'm');
2396
2397 LIST_PREPEND(device_allow, c->device_allow, a);
2398 return 0;
2399 }
2400
2401 int config_parse_blockio_weight(
2402 const char *unit,
2403 const char *filename,
2404 unsigned line,
2405 const char *section,
2406 unsigned section_line,
2407 const char *lvalue,
2408 int ltype,
2409 const char *rvalue,
2410 void *data,
2411 void *userdata) {
2412
2413 CGroupContext *c = data;
2414 unsigned long lu;
2415 int r;
2416
2417 assert(filename);
2418 assert(lvalue);
2419 assert(rvalue);
2420
2421 if (isempty(rvalue)) {
2422 c->blockio_weight = 1000;
2423 return 0;
2424 }
2425
2426 r = safe_atolu(rvalue, &lu);
2427 if (r < 0 || lu < 10 || lu > 1000) {
2428 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2429 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2430 return 0;
2431 }
2432
2433 c->blockio_weight = lu;
2434
2435 return 0;
2436 }
2437
2438 int config_parse_blockio_device_weight(
2439 const char *unit,
2440 const char *filename,
2441 unsigned line,
2442 const char *section,
2443 unsigned section_line,
2444 const char *lvalue,
2445 int ltype,
2446 const char *rvalue,
2447 void *data,
2448 void *userdata) {
2449
2450 _cleanup_free_ char *path = NULL;
2451 CGroupBlockIODeviceWeight *w;
2452 CGroupContext *c = data;
2453 unsigned long lu;
2454 const char *weight;
2455 size_t n;
2456 int r;
2457
2458 assert(filename);
2459 assert(lvalue);
2460 assert(rvalue);
2461
2462 if (isempty(rvalue)) {
2463 while (c->blockio_device_weights)
2464 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2465
2466 return 0;
2467 }
2468
2469 n = strcspn(rvalue, WHITESPACE);
2470 weight = rvalue + n;
2471 if (!*weight) {
2472 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2473 "Expected block device and device weight. Ignoring.");
2474 return 0;
2475 }
2476
2477 path = strndup(rvalue, n);
2478 if (!path)
2479 return log_oom();
2480
2481 if (!path_startswith(path, "/dev")) {
2482 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2483 "Invalid device node path '%s'. Ignoring.", path);
2484 return 0;
2485 }
2486
2487 weight += strspn(weight, WHITESPACE);
2488 r = safe_atolu(weight, &lu);
2489 if (r < 0 || lu < 10 || lu > 1000) {
2490 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2491 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2492 return 0;
2493 }
2494
2495
2496 w = new0(CGroupBlockIODeviceWeight, 1);
2497 if (!w)
2498 return log_oom();
2499
2500 w->path = path;
2501 path = NULL;
2502
2503 w->weight = lu;
2504
2505 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2506 return 0;
2507 }
2508
2509 int config_parse_blockio_bandwidth(
2510 const char *unit,
2511 const char *filename,
2512 unsigned line,
2513 const char *section,
2514 unsigned section_line,
2515 const char *lvalue,
2516 int ltype,
2517 const char *rvalue,
2518 void *data,
2519 void *userdata) {
2520
2521 _cleanup_free_ char *path = NULL;
2522 CGroupBlockIODeviceBandwidth *b;
2523 CGroupContext *c = data;
2524 const char *bandwidth;
2525 off_t bytes;
2526 bool read;
2527 size_t n;
2528 int r;
2529
2530 assert(filename);
2531 assert(lvalue);
2532 assert(rvalue);
2533
2534 read = streq("BlockIOReadBandwidth", lvalue);
2535
2536 if (isempty(rvalue)) {
2537 CGroupBlockIODeviceBandwidth *next;
2538
2539 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2540 if (b->read == read)
2541 cgroup_context_free_blockio_device_bandwidth(c, b);
2542
2543 return 0;
2544 }
2545
2546 n = strcspn(rvalue, WHITESPACE);
2547 bandwidth = rvalue + n;
2548 bandwidth += strspn(bandwidth, WHITESPACE);
2549
2550 if (!*bandwidth) {
2551 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2552 "Expected space separated pair of device node and bandwidth. Ignoring.");
2553 return 0;
2554 }
2555
2556 path = strndup(rvalue, n);
2557 if (!path)
2558 return log_oom();
2559
2560 if (!path_startswith(path, "/dev")) {
2561 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2562 "Invalid device node path '%s'. Ignoring.", path);
2563 return 0;
2564 }
2565
2566 r = parse_bytes(bandwidth, &bytes);
2567 if (r < 0 || bytes <= 0) {
2568 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2569 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2570 return 0;
2571 }
2572
2573 b = new0(CGroupBlockIODeviceBandwidth, 1);
2574 if (!b)
2575 return log_oom();
2576
2577 b->path = path;
2578 path = NULL;
2579 b->bandwidth = (uint64_t) bytes;
2580 b->read = read;
2581
2582 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2583
2584 return 0;
2585 }
2586
2587 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2588
2589 int config_parse_job_mode_isolate(
2590 const char *unit,
2591 const char *filename,
2592 unsigned line,
2593 const char *section,
2594 unsigned section_line,
2595 const char *lvalue,
2596 int ltype,
2597 const char *rvalue,
2598 void *data,
2599 void *userdata) {
2600
2601 JobMode *m = data;
2602 int r;
2603
2604 assert(filename);
2605 assert(lvalue);
2606 assert(rvalue);
2607
2608 r = parse_boolean(rvalue);
2609 if (r < 0) {
2610 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2611 return 0;
2612 }
2613
2614 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2615 return 0;
2616 }
2617
2618 int config_parse_personality(
2619 const char *unit,
2620 const char *filename,
2621 unsigned line,
2622 const char *section,
2623 unsigned section_line,
2624 const char *lvalue,
2625 int ltype,
2626 const char *rvalue,
2627 void *data,
2628 void *userdata) {
2629
2630 unsigned long *personality = data, p;
2631
2632 assert(filename);
2633 assert(lvalue);
2634 assert(rvalue);
2635 assert(personality);
2636
2637 p = personality_from_string(rvalue);
2638 if (p == 0xffffffffUL) {
2639 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2640 "Failed to parse personality, ignoring: %s", rvalue);
2641 return 0;
2642 }
2643
2644 *personality = p;
2645 return 0;
2646 }
2647
2648 #define FOLLOW_MAX 8
2649
2650 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2651 unsigned c = 0;
2652 int fd, r;
2653 FILE *f;
2654 char *id = NULL;
2655
2656 assert(filename);
2657 assert(*filename);
2658 assert(_f);
2659 assert(names);
2660
2661 /* This will update the filename pointer if the loaded file is
2662 * reached by a symlink. The old string will be freed. */
2663
2664 for (;;) {
2665 char *target, *name;
2666
2667 if (c++ >= FOLLOW_MAX)
2668 return -ELOOP;
2669
2670 path_kill_slashes(*filename);
2671
2672 /* Add the file name we are currently looking at to
2673 * the names of this unit, but only if it is a valid
2674 * unit name. */
2675 name = basename(*filename);
2676
2677 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
2678
2679 id = set_get(names, name);
2680 if (!id) {
2681 id = strdup(name);
2682 if (!id)
2683 return -ENOMEM;
2684
2685 r = set_consume(names, id);
2686 if (r < 0)
2687 return r;
2688 }
2689 }
2690
2691 /* Try to open the file name, but don't if its a symlink */
2692 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2693 if (fd >= 0)
2694 break;
2695
2696 if (errno != ELOOP)
2697 return -errno;
2698
2699 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2700 r = readlink_and_make_absolute(*filename, &target);
2701 if (r < 0)
2702 return r;
2703
2704 free(*filename);
2705 *filename = target;
2706 }
2707
2708 f = fdopen(fd, "re");
2709 if (!f) {
2710 r = -errno;
2711 close_nointr_nofail(fd);
2712 return r;
2713 }
2714
2715 *_f = f;
2716 *_final = id;
2717 return 0;
2718 }
2719
2720 static int merge_by_names(Unit **u, Set *names, const char *id) {
2721 char *k;
2722 int r;
2723
2724 assert(u);
2725 assert(*u);
2726 assert(names);
2727
2728 /* Let's try to add in all symlink names we found */
2729 while ((k = set_steal_first(names))) {
2730
2731 /* First try to merge in the other name into our
2732 * unit */
2733 r = unit_merge_by_name(*u, k);
2734 if (r < 0) {
2735 Unit *other;
2736
2737 /* Hmm, we couldn't merge the other unit into
2738 * ours? Then let's try it the other way
2739 * round */
2740
2741 other = manager_get_unit((*u)->manager, k);
2742 free(k);
2743
2744 if (other) {
2745 r = unit_merge(other, *u);
2746 if (r >= 0) {
2747 *u = other;
2748 return merge_by_names(u, names, NULL);
2749 }
2750 }
2751
2752 return r;
2753 }
2754
2755 if (id == k)
2756 unit_choose_id(*u, id);
2757
2758 free(k);
2759 }
2760
2761 return 0;
2762 }
2763
2764 static int load_from_path(Unit *u, const char *path) {
2765 int r;
2766 _cleanup_set_free_free_ Set *symlink_names = NULL;
2767 _cleanup_fclose_ FILE *f = NULL;
2768 _cleanup_free_ char *filename = NULL;
2769 char *id = NULL;
2770 Unit *merged;
2771 struct stat st;
2772
2773 assert(u);
2774 assert(path);
2775
2776 symlink_names = set_new(string_hash_func, string_compare_func);
2777 if (!symlink_names)
2778 return -ENOMEM;
2779
2780 if (path_is_absolute(path)) {
2781
2782 filename = strdup(path);
2783 if (!filename)
2784 return -ENOMEM;
2785
2786 r = open_follow(&filename, &f, symlink_names, &id);
2787 if (r < 0) {
2788 free(filename);
2789 filename = NULL;
2790
2791 if (r != -ENOENT)
2792 return r;
2793 }
2794
2795 } else {
2796 char **p;
2797
2798 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2799
2800 /* Instead of opening the path right away, we manually
2801 * follow all symlinks and add their name to our unit
2802 * name set while doing so */
2803 filename = path_make_absolute(path, *p);
2804 if (!filename)
2805 return -ENOMEM;
2806
2807 if (u->manager->unit_path_cache &&
2808 !set_get(u->manager->unit_path_cache, filename))
2809 r = -ENOENT;
2810 else
2811 r = open_follow(&filename, &f, symlink_names, &id);
2812
2813 if (r < 0) {
2814 free(filename);
2815 filename = NULL;
2816
2817 if (r != -ENOENT)
2818 return r;
2819
2820 /* Empty the symlink names for the next run */
2821 set_clear_free(symlink_names);
2822 continue;
2823 }
2824
2825 break;
2826 }
2827 }
2828
2829 if (!filename)
2830 /* Hmm, no suitable file found? */
2831 return 0;
2832
2833 merged = u;
2834 r = merge_by_names(&merged, symlink_names, id);
2835 if (r < 0)
2836 return r;
2837
2838 if (merged != u) {
2839 u->load_state = UNIT_MERGED;
2840 return 0;
2841 }
2842
2843 if (fstat(fileno(f), &st) < 0)
2844 return -errno;
2845
2846 if (null_or_empty(&st))
2847 u->load_state = UNIT_MASKED;
2848 else {
2849 u->load_state = UNIT_LOADED;
2850
2851 /* Now, parse the file contents */
2852 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2853 config_item_perf_lookup,
2854 (void*) load_fragment_gperf_lookup, false, true, u);
2855 if (r < 0)
2856 return r;
2857 }
2858
2859 free(u->fragment_path);
2860 u->fragment_path = filename;
2861 filename = NULL;
2862
2863 u->fragment_mtime = timespec_load(&st.st_mtim);
2864
2865 if (u->source_path) {
2866 if (stat(u->source_path, &st) >= 0)
2867 u->source_mtime = timespec_load(&st.st_mtim);
2868 else
2869 u->source_mtime = 0;
2870 }
2871
2872 return 0;
2873 }
2874
2875 int unit_load_fragment(Unit *u) {
2876 int r;
2877 Iterator i;
2878 const char *t;
2879
2880 assert(u);
2881 assert(u->load_state == UNIT_STUB);
2882 assert(u->id);
2883
2884 /* First, try to find the unit under its id. We always look
2885 * for unit files in the default directories, to make it easy
2886 * to override things by placing things in /etc/systemd/system */
2887 r = load_from_path(u, u->id);
2888 if (r < 0)
2889 return r;
2890
2891 /* Try to find an alias we can load this with */
2892 if (u->load_state == UNIT_STUB)
2893 SET_FOREACH(t, u->names, i) {
2894
2895 if (t == u->id)
2896 continue;
2897
2898 r = load_from_path(u, t);
2899 if (r < 0)
2900 return r;
2901
2902 if (u->load_state != UNIT_STUB)
2903 break;
2904 }
2905
2906 /* And now, try looking for it under the suggested (originally linked) path */
2907 if (u->load_state == UNIT_STUB && u->fragment_path) {
2908
2909 r = load_from_path(u, u->fragment_path);
2910 if (r < 0)
2911 return r;
2912
2913 if (u->load_state == UNIT_STUB) {
2914 /* Hmm, this didn't work? Then let's get rid
2915 * of the fragment path stored for us, so that
2916 * we don't point to an invalid location. */
2917 free(u->fragment_path);
2918 u->fragment_path = NULL;
2919 }
2920 }
2921
2922 /* Look for a template */
2923 if (u->load_state == UNIT_STUB && u->instance) {
2924 _cleanup_free_ char *k;
2925
2926 k = unit_name_template(u->id);
2927 if (!k)
2928 return -ENOMEM;
2929
2930 r = load_from_path(u, k);
2931 if (r < 0)
2932 return r;
2933
2934 if (u->load_state == UNIT_STUB)
2935 SET_FOREACH(t, u->names, i) {
2936 _cleanup_free_ char *z = NULL;
2937
2938 if (t == u->id)
2939 continue;
2940
2941 z = unit_name_template(t);
2942 if (!z)
2943 return -ENOMEM;
2944
2945 r = load_from_path(u, z);
2946 if (r < 0)
2947 return r;
2948
2949 if (u->load_state != UNIT_STUB)
2950 break;
2951 }
2952 }
2953
2954 return 0;
2955 }
2956
2957 void unit_dump_config_items(FILE *f) {
2958 static const struct {
2959 const ConfigParserCallback callback;
2960 const char *rvalue;
2961 } table[] = {
2962 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
2963 { config_parse_warn_compat, "NOTSUPPORTED" },
2964 #endif
2965 { config_parse_int, "INTEGER" },
2966 { config_parse_unsigned, "UNSIGNED" },
2967 { config_parse_bytes_size, "SIZE" },
2968 { config_parse_bool, "BOOLEAN" },
2969 { config_parse_string, "STRING" },
2970 { config_parse_path, "PATH" },
2971 { config_parse_unit_path_printf, "PATH" },
2972 { config_parse_strv, "STRING [...]" },
2973 { config_parse_exec_nice, "NICE" },
2974 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2975 { config_parse_exec_io_class, "IOCLASS" },
2976 { config_parse_exec_io_priority, "IOPRIORITY" },
2977 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2978 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2979 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2980 { config_parse_mode, "MODE" },
2981 { config_parse_unit_env_file, "FILE" },
2982 { config_parse_output, "OUTPUT" },
2983 { config_parse_input, "INPUT" },
2984 { config_parse_facility, "FACILITY" },
2985 { config_parse_level, "LEVEL" },
2986 { config_parse_exec_capabilities, "CAPABILITIES" },
2987 { config_parse_exec_secure_bits, "SECUREBITS" },
2988 { config_parse_bounding_set, "BOUNDINGSET" },
2989 { config_parse_limit, "LIMIT" },
2990 { config_parse_unit_deps, "UNIT [...]" },
2991 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2992 { config_parse_service_type, "SERVICETYPE" },
2993 { config_parse_service_restart, "SERVICERESTART" },
2994 #ifdef HAVE_SYSV_COMPAT
2995 { config_parse_sysv_priority, "SYSVPRIORITY" },
2996 #endif
2997 { config_parse_kill_mode, "KILLMODE" },
2998 { config_parse_kill_signal, "SIGNAL" },
2999 { config_parse_socket_listen, "SOCKET [...]" },
3000 { config_parse_socket_bind, "SOCKETBIND" },
3001 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3002 { config_parse_sec, "SECONDS" },
3003 { config_parse_nsec, "NANOSECONDS" },
3004 { config_parse_path_strv, "PATH [...]" },
3005 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3006 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3007 { config_parse_unit_string_printf, "STRING" },
3008 { config_parse_trigger_unit, "UNIT" },
3009 { config_parse_timer, "TIMER" },
3010 { config_parse_path_spec, "PATH" },
3011 { config_parse_notify_access, "ACCESS" },
3012 { config_parse_ip_tos, "TOS" },
3013 { config_parse_unit_condition_path, "CONDITION" },
3014 { config_parse_unit_condition_string, "CONDITION" },
3015 { config_parse_unit_condition_null, "CONDITION" },
3016 { config_parse_unit_slice, "SLICE" },
3017 { config_parse_documentation, "URL" },
3018 { config_parse_service_timeout, "SECONDS" },
3019 { config_parse_start_limit_action, "ACTION" },
3020 { config_parse_set_status, "STATUS" },
3021 { config_parse_service_sockets, "SOCKETS" },
3022 { config_parse_environ, "ENVIRON" },
3023 #ifdef HAVE_SECCOMP
3024 { config_parse_syscall_filter, "SYSCALLS" },
3025 { config_parse_syscall_archs, "ARCHS" },
3026 { config_parse_syscall_errno, "ERRNO" },
3027 #endif
3028 { config_parse_cpu_shares, "SHARES" },
3029 { config_parse_memory_limit, "LIMIT" },
3030 { config_parse_device_allow, "DEVICE" },
3031 { config_parse_device_policy, "POLICY" },
3032 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3033 { config_parse_blockio_weight, "WEIGHT" },
3034 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3035 { config_parse_long, "LONG" },
3036 { config_parse_socket_service, "SERVICE" },
3037 #ifdef HAVE_SELINUX
3038 { config_parse_exec_selinux_context, "LABEL" },
3039 #endif
3040 { config_parse_job_mode, "MODE" },
3041 { config_parse_job_mode_isolate, "BOOLEAN" },
3042 };
3043
3044 const char *prev = NULL;
3045 const char *i;
3046
3047 assert(f);
3048
3049 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3050 const char *rvalue = "OTHER", *lvalue;
3051 unsigned j;
3052 size_t prefix_len;
3053 const char *dot;
3054 const ConfigPerfItem *p;
3055
3056 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3057
3058 dot = strchr(i, '.');
3059 lvalue = dot ? dot + 1 : i;
3060 prefix_len = dot-i;
3061
3062 if (dot)
3063 if (!prev || !strneq(prev, i, prefix_len+1)) {
3064 if (prev)
3065 fputc('\n', f);
3066
3067 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3068 }
3069
3070 for (j = 0; j < ELEMENTSOF(table); j++)
3071 if (p->parse == table[j].callback) {
3072 rvalue = table[j].rvalue;
3073 break;
3074 }
3075
3076 fprintf(f, "%s=%s\n", lvalue, rvalue);
3077 prev = i;
3078 }
3079 }