]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
When warning about unsupported options, be more detailed
[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 #include <sys/types.h>
37 #include <grp.h>
38
39 #ifdef HAVE_SECCOMP
40 #include <seccomp.h>
41 #endif
42
43 #include "sd-messages.h"
44 #include "unit.h"
45 #include "strv.h"
46 #include "conf-parser.h"
47 #include "load-fragment.h"
48 #include "log.h"
49 #include "ioprio.h"
50 #include "securebits.h"
51 #include "missing.h"
52 #include "unit-name.h"
53 #include "unit-printf.h"
54 #include "utf8.h"
55 #include "path-util.h"
56 #include "env-util.h"
57 #include "cgroup.h"
58 #include "bus-util.h"
59 #include "bus-error.h"
60 #include "errno-list.h"
61 #include "af-list.h"
62
63 #ifdef HAVE_SECCOMP
64 #include "seccomp-util.h"
65 #endif
66
67 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
68 int config_parse_warn_compat(
69 const char *unit,
70 const char *filename,
71 unsigned line,
72 const char *section,
73 unsigned section_line,
74 const char *lvalue,
75 int ltype,
76 const char *rvalue,
77 void *data,
78 void *userdata) {
79 Disabled reason = ltype;
80
81 switch(reason) {
82 case DISABLED_CONFIGURATION:
83 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
84 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
85 break;
86 case DISABLED_EXPERIMENTAL:
87 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
88 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
89 break;
90 };
91
92 return 0;
93 }
94 #endif
95
96 int config_parse_unit_deps(const char *unit,
97 const char *filename,
98 unsigned line,
99 const char *section,
100 unsigned section_line,
101 const char *lvalue,
102 int ltype,
103 const char *rvalue,
104 void *data,
105 void *userdata) {
106
107 UnitDependency d = ltype;
108 Unit *u = userdata;
109 const char *word, *state;
110 size_t l;
111
112 assert(filename);
113 assert(lvalue);
114 assert(rvalue);
115
116 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
117 _cleanup_free_ char *t = NULL, *k = NULL;
118 int r;
119
120 t = strndup(word, l);
121 if (!t)
122 return log_oom();
123
124 r = unit_name_printf(u, t, &k);
125 if (r < 0) {
126 log_syntax(unit, LOG_ERR, filename, line, -r,
127 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
128 continue;
129 }
130
131 r = unit_add_dependency_by_name(u, d, k, NULL, true);
132 if (r < 0)
133 log_syntax(unit, LOG_ERR, filename, line, -r,
134 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
135 }
136 if (!isempty(state))
137 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
138
139 return 0;
140 }
141
142 int config_parse_unit_string_printf(const char *unit,
143 const char *filename,
144 unsigned line,
145 const char *section,
146 unsigned section_line,
147 const char *lvalue,
148 int ltype,
149 const char *rvalue,
150 void *data,
151 void *userdata) {
152
153 Unit *u = userdata;
154 _cleanup_free_ char *k = NULL;
155 int r;
156
157 assert(filename);
158 assert(lvalue);
159 assert(rvalue);
160 assert(u);
161
162 r = unit_full_printf(u, rvalue, &k);
163 if (r < 0)
164 log_syntax(unit, LOG_ERR, filename, line, -r,
165 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
166
167 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
168 k ? k : rvalue, data, userdata);
169 }
170
171 int config_parse_unit_strv_printf(const char *unit,
172 const char *filename,
173 unsigned line,
174 const char *section,
175 unsigned section_line,
176 const char *lvalue,
177 int ltype,
178 const char *rvalue,
179 void *data,
180 void *userdata) {
181
182 Unit *u = userdata;
183 _cleanup_free_ char *k = NULL;
184 int r;
185
186 assert(filename);
187 assert(lvalue);
188 assert(rvalue);
189 assert(u);
190
191 r = unit_full_printf(u, rvalue, &k);
192 if (r < 0)
193 log_syntax(unit, LOG_ERR, filename, line, -r,
194 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
195
196 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
197 k ? k : rvalue, data, userdata);
198 }
199
200 int config_parse_unit_path_printf(const char *unit,
201 const char *filename,
202 unsigned line,
203 const char *section,
204 unsigned section_line,
205 const char *lvalue,
206 int ltype,
207 const char *rvalue,
208 void *data,
209 void *userdata) {
210
211 _cleanup_free_ char *k = NULL;
212 Unit *u = userdata;
213 int r;
214
215 assert(filename);
216 assert(lvalue);
217 assert(rvalue);
218 assert(u);
219
220 r = unit_full_printf(u, rvalue, &k);
221 if (r < 0) {
222 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
223 return 0;
224 }
225
226 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
227 }
228
229 int config_parse_unit_path_strv_printf(
230 const char *unit,
231 const char *filename,
232 unsigned line,
233 const char *section,
234 unsigned section_line,
235 const char *lvalue,
236 int ltype,
237 const char *rvalue,
238 void *data,
239 void *userdata) {
240
241 char ***x = data;
242 const char *word, *state;
243 Unit *u = userdata;
244 size_t l;
245 int r;
246
247 assert(filename);
248 assert(lvalue);
249 assert(rvalue);
250 assert(u);
251
252 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
253 _cleanup_free_ char *k = NULL;
254 char t[l+1];
255
256 memcpy(t, word, l);
257 t[l] = 0;
258
259 r = unit_full_printf(u, t, &k);
260 if (r < 0) {
261 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
262 return 0;
263 }
264
265 if (!utf8_is_valid(k)) {
266 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
267 return 0;
268 }
269
270 if (!path_is_absolute(k)) {
271 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
272 return 0;
273 }
274
275 path_kill_slashes(k);
276
277 r = strv_push(x, k);
278 if (r < 0)
279 return log_oom();
280
281 k = NULL;
282 }
283 if (!isempty(state))
284 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
285
286 return 0;
287 }
288
289 int config_parse_socket_listen(const char *unit,
290 const char *filename,
291 unsigned line,
292 const char *section,
293 unsigned section_line,
294 const char *lvalue,
295 int ltype,
296 const char *rvalue,
297 void *data,
298 void *userdata) {
299
300 _cleanup_free_ SocketPort *p = NULL;
301 SocketPort *tail;
302 Socket *s;
303 int r;
304
305 assert(filename);
306 assert(lvalue);
307 assert(rvalue);
308 assert(data);
309
310 s = SOCKET(data);
311
312 if (isempty(rvalue)) {
313 /* An empty assignment removes all ports */
314 socket_free_ports(s);
315 return 0;
316 }
317
318 p = new0(SocketPort, 1);
319 if (!p)
320 return log_oom();
321
322 if (ltype != SOCKET_SOCKET) {
323
324 p->type = ltype;
325 r = unit_full_printf(UNIT(s), rvalue, &p->path);
326 if (r < 0) {
327 p->path = strdup(rvalue);
328 if (!p->path)
329 return log_oom();
330 else
331 log_syntax(unit, LOG_ERR, filename, line, -r,
332 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
333 }
334
335 path_kill_slashes(p->path);
336
337 } else if (streq(lvalue, "ListenNetlink")) {
338 _cleanup_free_ char *k = NULL;
339
340 p->type = SOCKET_SOCKET;
341 r = unit_full_printf(UNIT(s), rvalue, &k);
342 if (r < 0)
343 log_syntax(unit, LOG_ERR, filename, line, -r,
344 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
345
346 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
347 if (r < 0) {
348 log_syntax(unit, LOG_ERR, filename, line, -r,
349 "Failed to parse address value, ignoring: %s", rvalue);
350 return 0;
351 }
352
353 } else {
354 _cleanup_free_ char *k = NULL;
355
356 p->type = SOCKET_SOCKET;
357 r = unit_full_printf(UNIT(s), rvalue, &k);
358 if (r < 0)
359 log_syntax(unit, LOG_ERR, filename, line, -r,
360 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
361
362 r = socket_address_parse(&p->address, k ? k : rvalue);
363 if (r < 0) {
364 log_syntax(unit, LOG_ERR, filename, line, -r,
365 "Failed to parse address value, ignoring: %s", rvalue);
366 return 0;
367 }
368
369 if (streq(lvalue, "ListenStream"))
370 p->address.type = SOCK_STREAM;
371 else if (streq(lvalue, "ListenDatagram"))
372 p->address.type = SOCK_DGRAM;
373 else {
374 assert(streq(lvalue, "ListenSequentialPacket"));
375 p->address.type = SOCK_SEQPACKET;
376 }
377
378 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
379 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
380 "Address family not supported, ignoring: %s", rvalue);
381 return 0;
382 }
383 }
384
385 p->fd = -1;
386 p->socket = s;
387
388 if (s->ports) {
389 LIST_FIND_TAIL(port, s->ports, tail);
390 LIST_INSERT_AFTER(port, s->ports, tail, p);
391 } else
392 LIST_PREPEND(port, s->ports, p);
393 p = NULL;
394
395 return 0;
396 }
397
398 int config_parse_socket_bind(const char *unit,
399 const char *filename,
400 unsigned line,
401 const char *section,
402 unsigned section_line,
403 const char *lvalue,
404 int ltype,
405 const char *rvalue,
406 void *data,
407 void *userdata) {
408
409 Socket *s;
410 SocketAddressBindIPv6Only b;
411
412 assert(filename);
413 assert(lvalue);
414 assert(rvalue);
415 assert(data);
416
417 s = SOCKET(data);
418
419 b = socket_address_bind_ipv6_only_from_string(rvalue);
420 if (b < 0) {
421 int r;
422
423 r = parse_boolean(rvalue);
424 if (r < 0) {
425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
426 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
427 return 0;
428 }
429
430 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
431 } else
432 s->bind_ipv6_only = b;
433
434 return 0;
435 }
436
437 int config_parse_exec_nice(const char *unit,
438 const char *filename,
439 unsigned line,
440 const char *section,
441 unsigned section_line,
442 const char *lvalue,
443 int ltype,
444 const char *rvalue,
445 void *data,
446 void *userdata) {
447
448 ExecContext *c = data;
449 int priority, r;
450
451 assert(filename);
452 assert(lvalue);
453 assert(rvalue);
454 assert(data);
455
456 r = safe_atoi(rvalue, &priority);
457 if (r < 0) {
458 log_syntax(unit, LOG_ERR, filename, line, -r,
459 "Failed to parse nice priority, ignoring: %s. ", rvalue);
460 return 0;
461 }
462
463 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
464 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
465 "Nice priority out of range, ignoring: %s", rvalue);
466 return 0;
467 }
468
469 c->nice = priority;
470 c->nice_set = true;
471
472 return 0;
473 }
474
475 int config_parse_exec_oom_score_adjust(const char* unit,
476 const char *filename,
477 unsigned line,
478 const char *section,
479 unsigned section_line,
480 const char *lvalue,
481 int ltype,
482 const char *rvalue,
483 void *data,
484 void *userdata) {
485
486 ExecContext *c = data;
487 int oa, r;
488
489 assert(filename);
490 assert(lvalue);
491 assert(rvalue);
492 assert(data);
493
494 r = safe_atoi(rvalue, &oa);
495 if (r < 0) {
496 log_syntax(unit, LOG_ERR, filename, line, -r,
497 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
498 return 0;
499 }
500
501 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
502 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
503 "OOM score adjust value out of range, ignoring: %s", rvalue);
504 return 0;
505 }
506
507 c->oom_score_adjust = oa;
508 c->oom_score_adjust_set = true;
509
510 return 0;
511 }
512
513 int config_parse_exec(const char *unit,
514 const char *filename,
515 unsigned line,
516 const char *section,
517 unsigned section_line,
518 const char *lvalue,
519 int ltype,
520 const char *rvalue,
521 void *data,
522 void *userdata) {
523
524 ExecCommand **e = data, *nce;
525 char *path, **n;
526 unsigned k;
527 int r;
528
529 assert(filename);
530 assert(lvalue);
531 assert(rvalue);
532 assert(e);
533
534 e += ltype;
535
536 if (isempty(rvalue)) {
537 /* An empty assignment resets the list */
538 exec_command_free_list(*e);
539 *e = NULL;
540 return 0;
541 }
542
543 /* We accept an absolute path as first argument, or
544 * alternatively an absolute prefixed with @ to allow
545 * overriding of argv[0]. */
546 for (;;) {
547 int i;
548 const char *word, *state;
549 size_t l;
550 bool honour_argv0 = false, ignore = false;
551
552 path = NULL;
553 nce = NULL;
554 n = NULL;
555
556 rvalue += strspn(rvalue, WHITESPACE);
557
558 if (rvalue[0] == 0)
559 break;
560
561 for (i = 0; i < 2; i++) {
562 if (rvalue[0] == '-' && !ignore) {
563 ignore = true;
564 rvalue ++;
565 }
566
567 if (rvalue[0] == '@' && !honour_argv0) {
568 honour_argv0 = true;
569 rvalue ++;
570 }
571 }
572
573 if (*rvalue != '/') {
574 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
575 "Executable path is not absolute, ignoring: %s", rvalue);
576 return 0;
577 }
578
579 k = 0;
580 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
581 if (strneq(word, ";", MAX(l, 1U)))
582 goto found;
583
584 k++;
585 }
586 if (!isempty(state)) {
587 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
588 "Trailing garbage, ignoring.");
589 return 0;
590 }
591
592 found:
593 n = new(char*, k + !honour_argv0);
594 if (!n)
595 return log_oom();
596
597 k = 0;
598 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
599 if (strneq(word, ";", MAX(l, 1U)))
600 break;
601 else if (strneq(word, "\\;", MAX(l, 1U)))
602 word ++;
603
604 if (honour_argv0 && word == rvalue) {
605 assert(!path);
606
607 path = strndup(word, l);
608 if (!path) {
609 r = log_oom();
610 goto fail;
611 }
612
613 if (!utf8_is_valid(path)) {
614 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
615 r = 0;
616 goto fail;
617 }
618
619 } else {
620 char *c;
621
622 c = n[k++] = cunescape_length(word, l);
623 if (!c) {
624 r = log_oom();
625 goto fail;
626 }
627
628 if (!utf8_is_valid(c)) {
629 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
630 r = 0;
631 goto fail;
632 }
633 }
634 }
635
636 n[k] = NULL;
637
638 if (!n[0]) {
639 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
640 "Invalid command line, ignoring: %s", rvalue);
641 r = 0;
642 goto fail;
643 }
644
645 if (!path) {
646 path = strdup(n[0]);
647 if (!path) {
648 r = log_oom();
649 goto fail;
650 }
651 }
652
653 assert(path_is_absolute(path));
654
655 nce = new0(ExecCommand, 1);
656 if (!nce) {
657 r = log_oom();
658 goto fail;
659 }
660
661 nce->argv = n;
662 nce->path = path;
663 nce->ignore = ignore;
664
665 path_kill_slashes(nce->path);
666
667 exec_command_append_list(e, nce);
668
669 rvalue = state;
670 }
671
672 return 0;
673
674 fail:
675 n[k] = NULL;
676 strv_free(n);
677 free(path);
678 free(nce);
679
680 return r;
681 }
682
683 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
684 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
685
686 int config_parse_socket_bindtodevice(const char* unit,
687 const char *filename,
688 unsigned line,
689 const char *section,
690 unsigned section_line,
691 const char *lvalue,
692 int ltype,
693 const char *rvalue,
694 void *data,
695 void *userdata) {
696
697 Socket *s = data;
698 char *n;
699
700 assert(filename);
701 assert(lvalue);
702 assert(rvalue);
703 assert(data);
704
705 if (rvalue[0] && !streq(rvalue, "*")) {
706 n = strdup(rvalue);
707 if (!n)
708 return log_oom();
709 } else
710 n = NULL;
711
712 free(s->bind_to_device);
713 s->bind_to_device = n;
714
715 return 0;
716 }
717
718 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
719 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
720
721 int config_parse_exec_io_class(const char *unit,
722 const char *filename,
723 unsigned line,
724 const char *section,
725 unsigned section_line,
726 const char *lvalue,
727 int ltype,
728 const char *rvalue,
729 void *data,
730 void *userdata) {
731
732 ExecContext *c = data;
733 int x;
734
735 assert(filename);
736 assert(lvalue);
737 assert(rvalue);
738 assert(data);
739
740 x = ioprio_class_from_string(rvalue);
741 if (x < 0) {
742 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
743 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
744 return 0;
745 }
746
747 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
748 c->ioprio_set = true;
749
750 return 0;
751 }
752
753 int config_parse_exec_io_priority(const char *unit,
754 const char *filename,
755 unsigned line,
756 const char *section,
757 unsigned section_line,
758 const char *lvalue,
759 int ltype,
760 const char *rvalue,
761 void *data,
762 void *userdata) {
763
764 ExecContext *c = data;
765 int i, r;
766
767 assert(filename);
768 assert(lvalue);
769 assert(rvalue);
770 assert(data);
771
772 r = safe_atoi(rvalue, &i);
773 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
774 log_syntax(unit, LOG_ERR, filename, line, -r,
775 "Failed to parse IO priority, ignoring: %s", rvalue);
776 return 0;
777 }
778
779 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
780 c->ioprio_set = true;
781
782 return 0;
783 }
784
785 int config_parse_exec_cpu_sched_policy(const char *unit,
786 const char *filename,
787 unsigned line,
788 const char *section,
789 unsigned section_line,
790 const char *lvalue,
791 int ltype,
792 const char *rvalue,
793 void *data,
794 void *userdata) {
795
796
797 ExecContext *c = data;
798 int x;
799
800 assert(filename);
801 assert(lvalue);
802 assert(rvalue);
803 assert(data);
804
805 x = sched_policy_from_string(rvalue);
806 if (x < 0) {
807 log_syntax(unit, LOG_ERR, filename, line, -x,
808 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
809 return 0;
810 }
811
812 c->cpu_sched_policy = x;
813 /* Moving to or from real-time policy? We need to adjust the priority */
814 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
815 c->cpu_sched_set = true;
816
817 return 0;
818 }
819
820 int config_parse_exec_cpu_sched_prio(const char *unit,
821 const char *filename,
822 unsigned line,
823 const char *section,
824 unsigned section_line,
825 const char *lvalue,
826 int ltype,
827 const char *rvalue,
828 void *data,
829 void *userdata) {
830
831 ExecContext *c = data;
832 int i, min, max, r;
833
834 assert(filename);
835 assert(lvalue);
836 assert(rvalue);
837 assert(data);
838
839 r = safe_atoi(rvalue, &i);
840 if (r < 0) {
841 log_syntax(unit, LOG_ERR, filename, line, -r,
842 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
843 return 0;
844 }
845
846 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
847 min = sched_get_priority_min(c->cpu_sched_policy);
848 max = sched_get_priority_max(c->cpu_sched_policy);
849
850 if (i < min || i > max) {
851 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
852 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
853 return 0;
854 }
855
856 c->cpu_sched_priority = i;
857 c->cpu_sched_set = true;
858
859 return 0;
860 }
861
862 int config_parse_exec_cpu_affinity(const char *unit,
863 const char *filename,
864 unsigned line,
865 const char *section,
866 unsigned section_line,
867 const char *lvalue,
868 int ltype,
869 const char *rvalue,
870 void *data,
871 void *userdata) {
872
873 ExecContext *c = data;
874 const char *word, *state;
875 size_t l;
876
877 assert(filename);
878 assert(lvalue);
879 assert(rvalue);
880 assert(data);
881
882 if (isempty(rvalue)) {
883 /* An empty assignment resets the CPU list */
884 if (c->cpuset)
885 CPU_FREE(c->cpuset);
886 c->cpuset = NULL;
887 return 0;
888 }
889
890 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
891 _cleanup_free_ char *t = NULL;
892 int r;
893 unsigned cpu;
894
895 t = strndup(word, l);
896 if (!t)
897 return log_oom();
898
899 r = safe_atou(t, &cpu);
900
901 if (!c->cpuset) {
902 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
903 if (!c->cpuset)
904 return log_oom();
905 }
906
907 if (r < 0 || cpu >= c->cpuset_ncpus) {
908 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
909 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
910 return 0;
911 }
912
913 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
914 }
915 if (!isempty(state))
916 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
917 "Trailing garbage, ignoring.");
918
919 return 0;
920 }
921
922 int config_parse_exec_capabilities(const char *unit,
923 const char *filename,
924 unsigned line,
925 const char *section,
926 unsigned section_line,
927 const char *lvalue,
928 int ltype,
929 const char *rvalue,
930 void *data,
931 void *userdata) {
932
933 ExecContext *c = data;
934 cap_t cap;
935
936 assert(filename);
937 assert(lvalue);
938 assert(rvalue);
939 assert(data);
940
941 cap = cap_from_text(rvalue);
942 if (!cap) {
943 log_syntax(unit, LOG_ERR, filename, line, errno,
944 "Failed to parse capabilities, ignoring: %s", rvalue);
945 return 0;
946 }
947
948 if (c->capabilities)
949 cap_free(c->capabilities);
950 c->capabilities = cap;
951
952 return 0;
953 }
954
955 int config_parse_exec_secure_bits(const char *unit,
956 const char *filename,
957 unsigned line,
958 const char *section,
959 unsigned section_line,
960 const char *lvalue,
961 int ltype,
962 const char *rvalue,
963 void *data,
964 void *userdata) {
965
966 ExecContext *c = data;
967 size_t l;
968 const char *word, *state;
969
970 assert(filename);
971 assert(lvalue);
972 assert(rvalue);
973 assert(data);
974
975 if (isempty(rvalue)) {
976 /* An empty assignment resets the field */
977 c->secure_bits = 0;
978 return 0;
979 }
980
981 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
982 if (first_word(word, "keep-caps"))
983 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
984 else if (first_word(word, "keep-caps-locked"))
985 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
986 else if (first_word(word, "no-setuid-fixup"))
987 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
988 else if (first_word(word, "no-setuid-fixup-locked"))
989 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
990 else if (first_word(word, "noroot"))
991 c->secure_bits |= 1<<SECURE_NOROOT;
992 else if (first_word(word, "noroot-locked"))
993 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
994 else {
995 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
996 "Failed to parse secure bits, ignoring: %s", rvalue);
997 return 0;
998 }
999 }
1000 if (!isempty(state))
1001 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1002 "Invalid syntax, garbage at the end, ignoring.");
1003
1004 return 0;
1005 }
1006
1007 int config_parse_bounding_set(const char *unit,
1008 const char *filename,
1009 unsigned line,
1010 const char *section,
1011 unsigned section_line,
1012 const char *lvalue,
1013 int ltype,
1014 const char *rvalue,
1015 void *data,
1016 void *userdata) {
1017
1018 uint64_t *capability_bounding_set_drop = data;
1019 const char *word, *state;
1020 size_t l;
1021 bool invert = false;
1022 uint64_t sum = 0;
1023
1024 assert(filename);
1025 assert(lvalue);
1026 assert(rvalue);
1027 assert(data);
1028
1029 if (rvalue[0] == '~') {
1030 invert = true;
1031 rvalue++;
1032 }
1033
1034 /* Note that we store this inverted internally, since the
1035 * kernel wants it like this. But we actually expose it
1036 * non-inverted everywhere to have a fully normalized
1037 * interface. */
1038
1039 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1040 _cleanup_free_ char *t = NULL;
1041 int r;
1042 cap_value_t cap;
1043
1044 t = strndup(word, l);
1045 if (!t)
1046 return log_oom();
1047
1048 r = cap_from_name(t, &cap);
1049 if (r < 0) {
1050 log_syntax(unit, LOG_ERR, filename, line, errno,
1051 "Failed to parse capability in bounding set, ignoring: %s", t);
1052 continue;
1053 }
1054
1055 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1056 }
1057 if (!isempty(state))
1058 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1059 "Trailing garbage, ignoring.");
1060
1061 if (invert)
1062 *capability_bounding_set_drop |= sum;
1063 else
1064 *capability_bounding_set_drop |= ~sum;
1065
1066 return 0;
1067 }
1068
1069 int config_parse_limit(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 struct rlimit **rl = data;
1081 unsigned long long u;
1082
1083 assert(filename);
1084 assert(lvalue);
1085 assert(rvalue);
1086 assert(data);
1087
1088 rl += ltype;
1089
1090 if (streq(rvalue, "infinity"))
1091 u = (unsigned long long) RLIM_INFINITY;
1092 else {
1093 int r;
1094
1095 r = safe_atollu(rvalue, &u);
1096 if (r < 0) {
1097 log_syntax(unit, LOG_ERR, filename, line, -r,
1098 "Failed to parse resource value, ignoring: %s", rvalue);
1099 return 0;
1100 }
1101 }
1102
1103 if (!*rl) {
1104 *rl = new(struct rlimit, 1);
1105 if (!*rl)
1106 return log_oom();
1107 }
1108
1109 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1110 return 0;
1111 }
1112
1113 #ifdef HAVE_SYSV_COMPAT
1114 int config_parse_sysv_priority(const char *unit,
1115 const char *filename,
1116 unsigned line,
1117 const char *section,
1118 unsigned section_line,
1119 const char *lvalue,
1120 int ltype,
1121 const char *rvalue,
1122 void *data,
1123 void *userdata) {
1124
1125 int *priority = data;
1126 int i, r;
1127
1128 assert(filename);
1129 assert(lvalue);
1130 assert(rvalue);
1131 assert(data);
1132
1133 r = safe_atoi(rvalue, &i);
1134 if (r < 0 || i < 0) {
1135 log_syntax(unit, LOG_ERR, filename, line, -r,
1136 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1137 return 0;
1138 }
1139
1140 *priority = (int) i;
1141 return 0;
1142 }
1143 #endif
1144
1145 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1146
1147 int config_parse_kill_signal(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 int *sig = data;
1159 int r;
1160
1161 assert(filename);
1162 assert(lvalue);
1163 assert(rvalue);
1164 assert(sig);
1165
1166 r = signal_from_string_try_harder(rvalue);
1167 if (r <= 0) {
1168 log_syntax(unit, LOG_ERR, filename, line, -r,
1169 "Failed to parse kill signal, ignoring: %s", rvalue);
1170 return 0;
1171 }
1172
1173 *sig = r;
1174 return 0;
1175 }
1176
1177 int config_parse_exec_mount_flags(const char *unit,
1178 const char *filename,
1179 unsigned line,
1180 const char *section,
1181 unsigned section_line,
1182 const char *lvalue,
1183 int ltype,
1184 const char *rvalue,
1185 void *data,
1186 void *userdata) {
1187
1188 ExecContext *c = data;
1189 const char *word, *state;
1190 size_t l;
1191 unsigned long flags = 0;
1192
1193 assert(filename);
1194 assert(lvalue);
1195 assert(rvalue);
1196 assert(data);
1197
1198 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1199 _cleanup_free_ char *t;
1200
1201 t = strndup(word, l);
1202 if (!t)
1203 return log_oom();
1204
1205 if (streq(t, "shared"))
1206 flags = MS_SHARED;
1207 else if (streq(t, "slave"))
1208 flags = MS_SLAVE;
1209 else if (streq(word, "private"))
1210 flags = MS_PRIVATE;
1211 else {
1212 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1213 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1214 return 0;
1215 }
1216 }
1217 if (!isempty(state))
1218 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1219 "Trailing garbage, ignoring.");
1220
1221 c->mount_flags = flags;
1222 return 0;
1223 }
1224
1225 int config_parse_exec_selinux_context(
1226 const char *unit,
1227 const char *filename,
1228 unsigned line,
1229 const char *section,
1230 unsigned section_line,
1231 const char *lvalue,
1232 int ltype,
1233 const char *rvalue,
1234 void *data,
1235 void *userdata) {
1236
1237 ExecContext *c = data;
1238 Unit *u = userdata;
1239 bool ignore;
1240 char *k;
1241 int r;
1242
1243 assert(filename);
1244 assert(lvalue);
1245 assert(rvalue);
1246 assert(data);
1247
1248 if (isempty(rvalue)) {
1249 free(c->selinux_context);
1250 c->selinux_context = NULL;
1251 c->selinux_context_ignore = false;
1252 return 0;
1253 }
1254
1255 if (rvalue[0] == '-') {
1256 ignore = true;
1257 rvalue++;
1258 } else
1259 ignore = false;
1260
1261 r = unit_name_printf(u, rvalue, &k);
1262 if (r < 0) {
1263 log_syntax(unit, LOG_ERR, filename, line, -r,
1264 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1265 return 0;
1266 }
1267
1268 free(c->selinux_context);
1269 c->selinux_context = k;
1270 c->selinux_context_ignore = ignore;
1271
1272 return 0;
1273 }
1274
1275 int config_parse_exec_apparmor_profile(
1276 const char *unit,
1277 const char *filename,
1278 unsigned line,
1279 const char *section,
1280 unsigned section_line,
1281 const char *lvalue,
1282 int ltype,
1283 const char *rvalue,
1284 void *data,
1285 void *userdata) {
1286
1287 ExecContext *c = data;
1288 Unit *u = userdata;
1289 bool ignore;
1290 char *k;
1291 int r;
1292
1293 assert(filename);
1294 assert(lvalue);
1295 assert(rvalue);
1296 assert(data);
1297
1298 if (isempty(rvalue)) {
1299 free(c->apparmor_profile);
1300 c->apparmor_profile = NULL;
1301 c->apparmor_profile_ignore = false;
1302 return 0;
1303 }
1304
1305 if (rvalue[0] == '-') {
1306 ignore = true;
1307 rvalue++;
1308 } else
1309 ignore = false;
1310
1311 r = unit_name_printf(u, rvalue, &k);
1312 if (r < 0) {
1313 log_syntax(unit, LOG_ERR, filename, line, -r,
1314 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1315 return 0;
1316 }
1317
1318 free(c->apparmor_profile);
1319 c->apparmor_profile = k;
1320 c->apparmor_profile_ignore = ignore;
1321
1322 return 0;
1323 }
1324
1325 int config_parse_exec_smack_process_label(
1326 const char *unit,
1327 const char *filename,
1328 unsigned line,
1329 const char *section,
1330 unsigned section_line,
1331 const char *lvalue,
1332 int ltype,
1333 const char *rvalue,
1334 void *data,
1335 void *userdata) {
1336
1337 ExecContext *c = data;
1338 Unit *u = userdata;
1339 bool ignore;
1340 char *k;
1341 int r;
1342
1343 assert(filename);
1344 assert(lvalue);
1345 assert(rvalue);
1346 assert(data);
1347
1348 if (isempty(rvalue)) {
1349 free(c->smack_process_label);
1350 c->smack_process_label = NULL;
1351 c->smack_process_label_ignore = false;
1352 return 0;
1353 }
1354
1355 if (rvalue[0] == '-') {
1356 ignore = true;
1357 rvalue++;
1358 } else
1359 ignore = false;
1360
1361 r = unit_name_printf(u, rvalue, &k);
1362 if (r < 0) {
1363 log_syntax(unit, LOG_ERR, filename, line, -r,
1364 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1365 return 0;
1366 }
1367
1368 free(c->smack_process_label);
1369 c->smack_process_label = k;
1370 c->smack_process_label_ignore = ignore;
1371
1372 return 0;
1373 }
1374
1375 int config_parse_timer(const char *unit,
1376 const char *filename,
1377 unsigned line,
1378 const char *section,
1379 unsigned section_line,
1380 const char *lvalue,
1381 int ltype,
1382 const char *rvalue,
1383 void *data,
1384 void *userdata) {
1385
1386 Timer *t = data;
1387 usec_t u = 0;
1388 TimerValue *v;
1389 TimerBase b;
1390 CalendarSpec *c = NULL;
1391
1392 assert(filename);
1393 assert(lvalue);
1394 assert(rvalue);
1395 assert(data);
1396
1397 if (isempty(rvalue)) {
1398 /* Empty assignment resets list */
1399 timer_free_values(t);
1400 return 0;
1401 }
1402
1403 b = timer_base_from_string(lvalue);
1404 if (b < 0) {
1405 log_syntax(unit, LOG_ERR, filename, line, -b,
1406 "Failed to parse timer base, ignoring: %s", lvalue);
1407 return 0;
1408 }
1409
1410 if (b == TIMER_CALENDAR) {
1411 if (calendar_spec_from_string(rvalue, &c) < 0) {
1412 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1413 "Failed to parse calendar specification, ignoring: %s",
1414 rvalue);
1415 return 0;
1416 }
1417 } else {
1418 if (parse_sec(rvalue, &u) < 0) {
1419 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1420 "Failed to parse timer value, ignoring: %s",
1421 rvalue);
1422 return 0;
1423 }
1424 }
1425
1426 v = new0(TimerValue, 1);
1427 if (!v) {
1428 calendar_spec_free(c);
1429 return log_oom();
1430 }
1431
1432 v->base = b;
1433 v->value = u;
1434 v->calendar_spec = c;
1435
1436 LIST_PREPEND(value, t->values, v);
1437
1438 return 0;
1439 }
1440
1441 int config_parse_trigger_unit(
1442 const char *unit,
1443 const char *filename,
1444 unsigned line,
1445 const char *section,
1446 unsigned section_line,
1447 const char *lvalue,
1448 int ltype,
1449 const char *rvalue,
1450 void *data,
1451 void *userdata) {
1452
1453 _cleanup_free_ char *p = NULL;
1454 Unit *u = data;
1455 UnitType type;
1456 int r;
1457
1458 assert(filename);
1459 assert(lvalue);
1460 assert(rvalue);
1461 assert(data);
1462
1463 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1464 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1465 "Multiple units to trigger specified, ignoring: %s", rvalue);
1466 return 0;
1467 }
1468
1469 r = unit_name_printf(u, rvalue, &p);
1470 if (r < 0)
1471 log_syntax(unit, LOG_ERR, filename, line, -r,
1472 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1473
1474 type = unit_name_to_type(p ?: rvalue);
1475 if (type < 0) {
1476 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1477 "Unit type not valid, ignoring: %s", rvalue);
1478 return 0;
1479 }
1480
1481 if (type == u->type) {
1482 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1483 "Trigger cannot be of same type, ignoring: %s", rvalue);
1484 return 0;
1485 }
1486
1487 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1488 if (r < 0) {
1489 log_syntax(unit, LOG_ERR, filename, line, -r,
1490 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1491 return 0;
1492 }
1493
1494 return 0;
1495 }
1496
1497 int config_parse_path_spec(const char *unit,
1498 const char *filename,
1499 unsigned line,
1500 const char *section,
1501 unsigned section_line,
1502 const char *lvalue,
1503 int ltype,
1504 const char *rvalue,
1505 void *data,
1506 void *userdata) {
1507
1508 Path *p = data;
1509 PathSpec *s;
1510 PathType b;
1511 _cleanup_free_ char *k = NULL;
1512 int r;
1513
1514 assert(filename);
1515 assert(lvalue);
1516 assert(rvalue);
1517 assert(data);
1518
1519 if (isempty(rvalue)) {
1520 /* Empty assignment clears list */
1521 path_free_specs(p);
1522 return 0;
1523 }
1524
1525 b = path_type_from_string(lvalue);
1526 if (b < 0) {
1527 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1528 "Failed to parse path type, ignoring: %s", lvalue);
1529 return 0;
1530 }
1531
1532 r = unit_full_printf(UNIT(p), rvalue, &k);
1533 if (r < 0) {
1534 k = strdup(rvalue);
1535 if (!k)
1536 return log_oom();
1537 else
1538 log_syntax(unit, LOG_ERR, filename, line, -r,
1539 "Failed to resolve unit specifiers on %s. Ignoring.",
1540 rvalue);
1541 }
1542
1543 if (!path_is_absolute(k)) {
1544 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1545 "Path is not absolute, ignoring: %s", k);
1546 return 0;
1547 }
1548
1549 s = new0(PathSpec, 1);
1550 if (!s)
1551 return log_oom();
1552
1553 s->unit = UNIT(p);
1554 s->path = path_kill_slashes(k);
1555 k = NULL;
1556 s->type = b;
1557 s->inotify_fd = -1;
1558
1559 LIST_PREPEND(spec, p->specs, s);
1560
1561 return 0;
1562 }
1563
1564 int config_parse_socket_service(const char *unit,
1565 const char *filename,
1566 unsigned line,
1567 const char *section,
1568 unsigned section_line,
1569 const char *lvalue,
1570 int ltype,
1571 const char *rvalue,
1572 void *data,
1573 void *userdata) {
1574
1575 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1576 Socket *s = data;
1577 int r;
1578 Unit *x;
1579 _cleanup_free_ char *p = NULL;
1580
1581 assert(filename);
1582 assert(lvalue);
1583 assert(rvalue);
1584 assert(data);
1585
1586 r = unit_name_printf(UNIT(s), rvalue, &p);
1587 if (r < 0) {
1588 log_syntax(unit, LOG_ERR, filename, line, -r,
1589 "Failed to resolve specifiers, ignoring: %s", rvalue);
1590 return 0;
1591 }
1592
1593 if (!endswith(p, ".service")) {
1594 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1595 "Unit must be of type service, ignoring: %s", rvalue);
1596 return 0;
1597 }
1598
1599 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1600 if (r < 0) {
1601 log_syntax(unit, LOG_ERR, filename, line, -r,
1602 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1603 return 0;
1604 }
1605
1606 unit_ref_set(&s->service, x);
1607
1608 return 0;
1609 }
1610
1611 int config_parse_service_sockets(const char *unit,
1612 const char *filename,
1613 unsigned line,
1614 const char *section,
1615 unsigned section_line,
1616 const char *lvalue,
1617 int ltype,
1618 const char *rvalue,
1619 void *data,
1620 void *userdata) {
1621
1622 Service *s = data;
1623 int r;
1624 const char *word, *state;
1625 size_t l;
1626
1627 assert(filename);
1628 assert(lvalue);
1629 assert(rvalue);
1630 assert(data);
1631
1632 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1633 _cleanup_free_ char *t = NULL, *k = NULL;
1634
1635 t = strndup(word, l);
1636 if (!t)
1637 return log_oom();
1638
1639 r = unit_name_printf(UNIT(s), t, &k);
1640 if (r < 0)
1641 log_syntax(unit, LOG_ERR, filename, line, -r,
1642 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1643
1644 if (!endswith(k ?: t, ".socket")) {
1645 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1646 "Unit must be of type socket, ignoring: %s", k ?: t);
1647 continue;
1648 }
1649
1650 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1651 if (r < 0)
1652 log_syntax(unit, LOG_ERR, filename, line, -r,
1653 "Failed to add dependency on %s, ignoring: %s",
1654 k ?: t, strerror(-r));
1655
1656 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1657 if (r < 0)
1658 return r;
1659 }
1660 if (!isempty(state))
1661 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1662 "Trailing garbage, ignoring.");
1663
1664 return 0;
1665 }
1666
1667 int config_parse_service_timeout(const char *unit,
1668 const char *filename,
1669 unsigned line,
1670 const char *section,
1671 unsigned section_line,
1672 const char *lvalue,
1673 int ltype,
1674 const char *rvalue,
1675 void *data,
1676 void *userdata) {
1677
1678 Service *s = userdata;
1679 int r;
1680
1681 assert(filename);
1682 assert(lvalue);
1683 assert(rvalue);
1684 assert(s);
1685
1686 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1687 rvalue, data, userdata);
1688 if (r < 0)
1689 return r;
1690
1691 if (streq(lvalue, "TimeoutSec")) {
1692 s->start_timeout_defined = true;
1693 s->timeout_stop_usec = s->timeout_start_usec;
1694 } else if (streq(lvalue, "TimeoutStartSec"))
1695 s->start_timeout_defined = true;
1696
1697 return 0;
1698 }
1699
1700 int config_parse_busname_service(
1701 const char *unit,
1702 const char *filename,
1703 unsigned line,
1704 const char *section,
1705 unsigned section_line,
1706 const char *lvalue,
1707 int ltype,
1708 const char *rvalue,
1709 void *data,
1710 void *userdata) {
1711
1712 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1713 BusName *n = data;
1714 int r;
1715 Unit *x;
1716 _cleanup_free_ char *p = NULL;
1717
1718 assert(filename);
1719 assert(lvalue);
1720 assert(rvalue);
1721 assert(data);
1722
1723 r = unit_name_printf(UNIT(n), rvalue, &p);
1724 if (r < 0) {
1725 log_syntax(unit, LOG_ERR, filename, line, -r,
1726 "Failed to resolve specifiers, ignoring: %s", rvalue);
1727 return 0;
1728 }
1729
1730 if (!endswith(p, ".service")) {
1731 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1732 "Unit must be of type service, ignoring: %s", rvalue);
1733 return 0;
1734 }
1735
1736 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1737 if (r < 0) {
1738 log_syntax(unit, LOG_ERR, filename, line, -r,
1739 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1740 return 0;
1741 }
1742
1743 unit_ref_set(&n->service, x);
1744
1745 return 0;
1746 }
1747
1748 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1749
1750 int config_parse_bus_policy(
1751 const char *unit,
1752 const char *filename,
1753 unsigned line,
1754 const char *section,
1755 unsigned section_line,
1756 const char *lvalue,
1757 int ltype,
1758 const char *rvalue,
1759 void *data,
1760 void *userdata) {
1761
1762 _cleanup_free_ BusNamePolicy *p = NULL;
1763 _cleanup_free_ char *id_str = NULL;
1764 BusName *busname = data;
1765 char *access_str;
1766
1767 assert(filename);
1768 assert(lvalue);
1769 assert(rvalue);
1770 assert(data);
1771
1772 p = new0(BusNamePolicy, 1);
1773 if (!p)
1774 return log_oom();
1775
1776 if (streq(lvalue, "AllowUser"))
1777 p->type = BUSNAME_POLICY_TYPE_USER;
1778 else if (streq(lvalue, "AllowGroup"))
1779 p->type = BUSNAME_POLICY_TYPE_GROUP;
1780 else
1781 assert_not_reached("Unknown lvalue");
1782
1783 id_str = strdup(rvalue);
1784 if (!id_str)
1785 return log_oom();
1786
1787 access_str = strpbrk(id_str, WHITESPACE);
1788 if (!access_str) {
1789 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1790 "Invalid busname policy value '%s'", rvalue);
1791 return 0;
1792 }
1793
1794 *access_str = '\0';
1795 access_str++;
1796 access_str += strspn(access_str, WHITESPACE);
1797
1798 p->access = bus_policy_access_from_string(access_str);
1799 if (p->access < 0) {
1800 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1801 "Invalid busname policy access type '%s'", access_str);
1802 return 0;
1803 }
1804
1805 p->name = id_str;
1806 id_str = NULL;
1807
1808 LIST_PREPEND(policy, busname->policy, p);
1809 p = NULL;
1810
1811 return 0;
1812 }
1813
1814 int config_parse_bus_endpoint_policy(
1815 const char *unit,
1816 const char *filename,
1817 unsigned line,
1818 const char *section,
1819 unsigned section_line,
1820 const char *lvalue,
1821 int ltype,
1822 const char *rvalue,
1823 void *data,
1824 void *userdata) {
1825
1826 _cleanup_free_ char *name = NULL;
1827 BusPolicyAccess access;
1828 ExecContext *c = data;
1829 char *access_str;
1830 int r;
1831
1832 assert(filename);
1833 assert(lvalue);
1834 assert(rvalue);
1835 assert(data);
1836
1837 name = strdup(rvalue);
1838 if (!name)
1839 return log_oom();
1840
1841 access_str = strpbrk(name, WHITESPACE);
1842 if (!access_str) {
1843 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1844 "Invalid endpoint policy value '%s'", rvalue);
1845 return 0;
1846 }
1847
1848 *access_str = '\0';
1849 access_str++;
1850 access_str += strspn(access_str, WHITESPACE);
1851
1852 access = bus_policy_access_from_string(access_str);
1853 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1854 access >= _BUS_POLICY_ACCESS_MAX) {
1855 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1856 "Invalid endpoint policy access type '%s'", access_str);
1857 return 0;
1858 }
1859
1860 if (!c->bus_endpoint) {
1861 r = bus_endpoint_new(&c->bus_endpoint);
1862
1863 if (r < 0)
1864 return r;
1865 }
1866
1867 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1868 }
1869
1870 int config_parse_unit_env_file(const char *unit,
1871 const char *filename,
1872 unsigned line,
1873 const char *section,
1874 unsigned section_line,
1875 const char *lvalue,
1876 int ltype,
1877 const char *rvalue,
1878 void *data,
1879 void *userdata) {
1880
1881 char ***env = data;
1882 Unit *u = userdata;
1883 _cleanup_free_ char *n = NULL;
1884 const char *s;
1885 int r;
1886
1887 assert(filename);
1888 assert(lvalue);
1889 assert(rvalue);
1890 assert(data);
1891
1892 if (isempty(rvalue)) {
1893 /* Empty assignment frees the list */
1894 strv_free(*env);
1895 *env = NULL;
1896 return 0;
1897 }
1898
1899 r = unit_full_printf(u, rvalue, &n);
1900 if (r < 0)
1901 log_syntax(unit, LOG_ERR, filename, line, -r,
1902 "Failed to resolve specifiers, ignoring: %s", rvalue);
1903
1904 s = n ?: rvalue;
1905 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1906 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1907 "Path '%s' is not absolute, ignoring.", s);
1908 return 0;
1909 }
1910
1911 r = strv_extend(env, s);
1912 if (r < 0)
1913 return log_oom();
1914
1915 return 0;
1916 }
1917
1918 int config_parse_environ(const char *unit,
1919 const char *filename,
1920 unsigned line,
1921 const char *section,
1922 unsigned section_line,
1923 const char *lvalue,
1924 int ltype,
1925 const char *rvalue,
1926 void *data,
1927 void *userdata) {
1928
1929 Unit *u = userdata;
1930 char*** env = data;
1931 const char *word, *state;
1932 size_t l;
1933 _cleanup_free_ char *k = NULL;
1934 int r;
1935
1936 assert(filename);
1937 assert(lvalue);
1938 assert(rvalue);
1939 assert(data);
1940
1941 if (isempty(rvalue)) {
1942 /* Empty assignment resets the list */
1943 strv_free(*env);
1944 *env = NULL;
1945 return 0;
1946 }
1947
1948 if (u) {
1949 r = unit_full_printf(u, rvalue, &k);
1950 if (r < 0)
1951 log_syntax(unit, LOG_ERR, filename, line, -r,
1952 "Failed to resolve specifiers, ignoring: %s", rvalue);
1953 }
1954
1955 if (!k)
1956 k = strdup(rvalue);
1957 if (!k)
1958 return log_oom();
1959
1960 FOREACH_WORD_QUOTED(word, l, k, state) {
1961 _cleanup_free_ char *n;
1962 char **x;
1963
1964 n = cunescape_length(word, l);
1965 if (!n)
1966 return log_oom();
1967
1968 if (!env_assignment_is_valid(n)) {
1969 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1970 "Invalid environment assignment, ignoring: %s", rvalue);
1971 continue;
1972 }
1973
1974 x = strv_env_set(*env, n);
1975 if (!x)
1976 return log_oom();
1977
1978 strv_free(*env);
1979 *env = x;
1980 }
1981 if (!isempty(state))
1982 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1983 "Trailing garbage, ignoring.");
1984
1985 return 0;
1986 }
1987
1988 int config_parse_ip_tos(const char *unit,
1989 const char *filename,
1990 unsigned line,
1991 const char *section,
1992 unsigned section_line,
1993 const char *lvalue,
1994 int ltype,
1995 const char *rvalue,
1996 void *data,
1997 void *userdata) {
1998
1999 int *ip_tos = data, x;
2000
2001 assert(filename);
2002 assert(lvalue);
2003 assert(rvalue);
2004 assert(data);
2005
2006 x = ip_tos_from_string(rvalue);
2007 if (x < 0) {
2008 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2009 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2010 return 0;
2011 }
2012
2013 *ip_tos = x;
2014 return 0;
2015 }
2016
2017 int config_parse_unit_condition_path(
2018 const char *unit,
2019 const char *filename,
2020 unsigned line,
2021 const char *section,
2022 unsigned section_line,
2023 const char *lvalue,
2024 int ltype,
2025 const char *rvalue,
2026 void *data,
2027 void *userdata) {
2028
2029 _cleanup_free_ char *p = NULL;
2030 Condition **list = data, *c;
2031 ConditionType t = ltype;
2032 bool trigger, negate;
2033 Unit *u = userdata;
2034 int r;
2035
2036 assert(filename);
2037 assert(lvalue);
2038 assert(rvalue);
2039 assert(data);
2040
2041 if (isempty(rvalue)) {
2042 /* Empty assignment resets the list */
2043 condition_free_list(*list);
2044 *list = NULL;
2045 return 0;
2046 }
2047
2048 trigger = rvalue[0] == '|';
2049 if (trigger)
2050 rvalue++;
2051
2052 negate = rvalue[0] == '!';
2053 if (negate)
2054 rvalue++;
2055
2056 r = unit_full_printf(u, rvalue, &p);
2057 if (r < 0) {
2058 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2059 return 0;
2060 }
2061
2062 if (!path_is_absolute(p)) {
2063 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2064 return 0;
2065 }
2066
2067 c = condition_new(t, p, trigger, negate);
2068 if (!c)
2069 return log_oom();
2070
2071 LIST_PREPEND(conditions, *list, c);
2072 return 0;
2073 }
2074
2075 int config_parse_unit_condition_string(
2076 const char *unit,
2077 const char *filename,
2078 unsigned line,
2079 const char *section,
2080 unsigned section_line,
2081 const char *lvalue,
2082 int ltype,
2083 const char *rvalue,
2084 void *data,
2085 void *userdata) {
2086
2087 _cleanup_free_ char *s = NULL;
2088 Condition **list = data, *c;
2089 ConditionType t = ltype;
2090 bool trigger, negate;
2091 Unit *u = userdata;
2092 int r;
2093
2094 assert(filename);
2095 assert(lvalue);
2096 assert(rvalue);
2097 assert(data);
2098
2099 if (isempty(rvalue)) {
2100 /* Empty assignment resets the list */
2101 condition_free_list(*list);
2102 *list = NULL;
2103 return 0;
2104 }
2105
2106 trigger = rvalue[0] == '|';
2107 if (trigger)
2108 rvalue++;
2109
2110 negate = rvalue[0] == '!';
2111 if (negate)
2112 rvalue++;
2113
2114 r = unit_full_printf(u, rvalue, &s);
2115 if (r < 0) {
2116 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2117 return 0;
2118 }
2119
2120 c = condition_new(t, s, trigger, negate);
2121 if (!c)
2122 return log_oom();
2123
2124 LIST_PREPEND(conditions, *list, c);
2125 return 0;
2126 }
2127
2128 int config_parse_unit_condition_null(
2129 const char *unit,
2130 const char *filename,
2131 unsigned line,
2132 const char *section,
2133 unsigned section_line,
2134 const char *lvalue,
2135 int ltype,
2136 const char *rvalue,
2137 void *data,
2138 void *userdata) {
2139
2140 Condition **list = data, *c;
2141 bool trigger, negate;
2142 int b;
2143
2144 assert(filename);
2145 assert(lvalue);
2146 assert(rvalue);
2147 assert(data);
2148
2149 if (isempty(rvalue)) {
2150 /* Empty assignment resets the list */
2151 condition_free_list(*list);
2152 *list = NULL;
2153 return 0;
2154 }
2155
2156 trigger = rvalue[0] == '|';
2157 if (trigger)
2158 rvalue++;
2159
2160 negate = rvalue[0] == '!';
2161 if (negate)
2162 rvalue++;
2163
2164 b = parse_boolean(rvalue);
2165 if (b < 0) {
2166 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2167 return 0;
2168 }
2169
2170 if (!b)
2171 negate = !negate;
2172
2173 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2174 if (!c)
2175 return log_oom();
2176
2177 LIST_PREPEND(conditions, *list, c);
2178 return 0;
2179 }
2180
2181 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2182 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2183
2184 int config_parse_unit_requires_mounts_for(
2185 const char *unit,
2186 const char *filename,
2187 unsigned line,
2188 const char *section,
2189 unsigned section_line,
2190 const char *lvalue,
2191 int ltype,
2192 const char *rvalue,
2193 void *data,
2194 void *userdata) {
2195
2196 Unit *u = userdata;
2197 const char *word, *state;
2198 size_t l;
2199
2200 assert(filename);
2201 assert(lvalue);
2202 assert(rvalue);
2203 assert(data);
2204
2205 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2206 int r;
2207 _cleanup_free_ char *n;
2208
2209 n = strndup(word, l);
2210 if (!n)
2211 return log_oom();
2212
2213 if (!utf8_is_valid(n)) {
2214 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2215 continue;
2216 }
2217
2218 r = unit_require_mounts_for(u, n);
2219 if (r < 0) {
2220 log_syntax(unit, LOG_ERR, filename, line, -r,
2221 "Failed to add required mount for, ignoring: %s", rvalue);
2222 continue;
2223 }
2224 }
2225 if (!isempty(state))
2226 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2227 "Trailing garbage, ignoring.");
2228
2229 return 0;
2230 }
2231
2232 int config_parse_documentation(const char *unit,
2233 const char *filename,
2234 unsigned line,
2235 const char *section,
2236 unsigned section_line,
2237 const char *lvalue,
2238 int ltype,
2239 const char *rvalue,
2240 void *data,
2241 void *userdata) {
2242
2243 Unit *u = userdata;
2244 int r;
2245 char **a, **b;
2246
2247 assert(filename);
2248 assert(lvalue);
2249 assert(rvalue);
2250 assert(u);
2251
2252 if (isempty(rvalue)) {
2253 /* Empty assignment resets the list */
2254 strv_free(u->documentation);
2255 u->documentation = NULL;
2256 return 0;
2257 }
2258
2259 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2260 rvalue, data, userdata);
2261 if (r < 0)
2262 return r;
2263
2264 for (a = b = u->documentation; a && *a; a++) {
2265
2266 if (is_valid_documentation_url(*a))
2267 *(b++) = *a;
2268 else {
2269 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2270 "Invalid URL, ignoring: %s", *a);
2271 free(*a);
2272 }
2273 }
2274 if (b)
2275 *b = NULL;
2276
2277 return r;
2278 }
2279
2280 #ifdef HAVE_SECCOMP
2281 int config_parse_syscall_filter(
2282 const char *unit,
2283 const char *filename,
2284 unsigned line,
2285 const char *section,
2286 unsigned section_line,
2287 const char *lvalue,
2288 int ltype,
2289 const char *rvalue,
2290 void *data,
2291 void *userdata) {
2292
2293 static const char default_syscalls[] =
2294 "execve\0"
2295 "exit\0"
2296 "exit_group\0"
2297 "rt_sigreturn\0"
2298 "sigreturn\0";
2299
2300 ExecContext *c = data;
2301 Unit *u = userdata;
2302 bool invert = false;
2303 const char *word, *state;
2304 size_t l;
2305 int r;
2306
2307 assert(filename);
2308 assert(lvalue);
2309 assert(rvalue);
2310 assert(u);
2311
2312 if (isempty(rvalue)) {
2313 /* Empty assignment resets the list */
2314 set_free(c->syscall_filter);
2315 c->syscall_filter = NULL;
2316 c->syscall_whitelist = false;
2317 return 0;
2318 }
2319
2320 if (rvalue[0] == '~') {
2321 invert = true;
2322 rvalue++;
2323 }
2324
2325 if (!c->syscall_filter) {
2326 c->syscall_filter = set_new(NULL);
2327 if (!c->syscall_filter)
2328 return log_oom();
2329
2330 if (invert)
2331 /* Allow everything but the ones listed */
2332 c->syscall_whitelist = false;
2333 else {
2334 const char *i;
2335
2336 /* Allow nothing but the ones listed */
2337 c->syscall_whitelist = true;
2338
2339 /* Accept default syscalls if we are on a whitelist */
2340 NULSTR_FOREACH(i, default_syscalls) {
2341 int id;
2342
2343 id = seccomp_syscall_resolve_name(i);
2344 if (id < 0)
2345 continue;
2346
2347 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2348 if (r == -EEXIST)
2349 continue;
2350 if (r < 0)
2351 return log_oom();
2352 }
2353 }
2354 }
2355
2356 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2357 _cleanup_free_ char *t = NULL;
2358 int id;
2359
2360 t = strndup(word, l);
2361 if (!t)
2362 return log_oom();
2363
2364 id = seccomp_syscall_resolve_name(t);
2365 if (id < 0) {
2366 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2367 "Failed to parse system call, ignoring: %s", t);
2368 continue;
2369 }
2370
2371 /* If we previously wanted to forbid a syscall and now
2372 * we want to allow it, then remove it from the list
2373 */
2374 if (!invert == c->syscall_whitelist) {
2375 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2376 if (r == -EEXIST)
2377 continue;
2378 if (r < 0)
2379 return log_oom();
2380 } else
2381 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2382 }
2383 if (!isempty(state))
2384 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2385 "Trailing garbage, ignoring.");
2386
2387 /* Turn on NNP, but only if it wasn't configured explicitly
2388 * before, and only if we are in user mode. */
2389 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2390 c->no_new_privileges = true;
2391
2392 return 0;
2393 }
2394
2395 int config_parse_syscall_archs(
2396 const char *unit,
2397 const char *filename,
2398 unsigned line,
2399 const char *section,
2400 unsigned section_line,
2401 const char *lvalue,
2402 int ltype,
2403 const char *rvalue,
2404 void *data,
2405 void *userdata) {
2406
2407 Set **archs = data;
2408 const char *word, *state;
2409 size_t l;
2410 int r;
2411
2412 if (isempty(rvalue)) {
2413 set_free(*archs);
2414 *archs = NULL;
2415 return 0;
2416 }
2417
2418 r = set_ensure_allocated(archs, NULL);
2419 if (r < 0)
2420 return log_oom();
2421
2422 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2423 _cleanup_free_ char *t = NULL;
2424 uint32_t a;
2425
2426 t = strndup(word, l);
2427 if (!t)
2428 return log_oom();
2429
2430 r = seccomp_arch_from_string(t, &a);
2431 if (r < 0) {
2432 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2433 "Failed to parse system call architecture, ignoring: %s", t);
2434 continue;
2435 }
2436
2437 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2438 if (r == -EEXIST)
2439 continue;
2440 if (r < 0)
2441 return log_oom();
2442 }
2443 if (!isempty(state))
2444 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2445 "Trailing garbage, ignoring.");
2446
2447 return 0;
2448 }
2449
2450 int config_parse_syscall_errno(
2451 const char *unit,
2452 const char *filename,
2453 unsigned line,
2454 const char *section,
2455 unsigned section_line,
2456 const char *lvalue,
2457 int ltype,
2458 const char *rvalue,
2459 void *data,
2460 void *userdata) {
2461
2462 ExecContext *c = data;
2463 int e;
2464
2465 assert(filename);
2466 assert(lvalue);
2467 assert(rvalue);
2468
2469 if (isempty(rvalue)) {
2470 /* Empty assignment resets to KILL */
2471 c->syscall_errno = 0;
2472 return 0;
2473 }
2474
2475 e = errno_from_name(rvalue);
2476 if (e < 0) {
2477 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2478 "Failed to parse error number, ignoring: %s", rvalue);
2479 return 0;
2480 }
2481
2482 c->syscall_errno = e;
2483 return 0;
2484 }
2485
2486 int config_parse_address_families(
2487 const char *unit,
2488 const char *filename,
2489 unsigned line,
2490 const char *section,
2491 unsigned section_line,
2492 const char *lvalue,
2493 int ltype,
2494 const char *rvalue,
2495 void *data,
2496 void *userdata) {
2497
2498 ExecContext *c = data;
2499 bool invert = false;
2500 const char *word, *state;
2501 size_t l;
2502 int r;
2503
2504 assert(filename);
2505 assert(lvalue);
2506 assert(rvalue);
2507
2508 if (isempty(rvalue)) {
2509 /* Empty assignment resets the list */
2510 set_free(c->address_families);
2511 c->address_families = NULL;
2512 c->address_families_whitelist = false;
2513 return 0;
2514 }
2515
2516 if (rvalue[0] == '~') {
2517 invert = true;
2518 rvalue++;
2519 }
2520
2521 if (!c->address_families) {
2522 c->address_families = set_new(NULL);
2523 if (!c->address_families)
2524 return log_oom();
2525
2526 c->address_families_whitelist = !invert;
2527 }
2528
2529 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2530 _cleanup_free_ char *t = NULL;
2531 int af;
2532
2533 t = strndup(word, l);
2534 if (!t)
2535 return log_oom();
2536
2537 af = af_from_name(t);
2538 if (af <= 0) {
2539 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2540 "Failed to parse address family, ignoring: %s", t);
2541 continue;
2542 }
2543
2544 /* If we previously wanted to forbid an address family and now
2545 * we want to allow it, then remove it from the list
2546 */
2547 if (!invert == c->address_families_whitelist) {
2548 r = set_put(c->address_families, INT_TO_PTR(af));
2549 if (r == -EEXIST)
2550 continue;
2551 if (r < 0)
2552 return log_oom();
2553 } else
2554 set_remove(c->address_families, INT_TO_PTR(af));
2555 }
2556 if (!isempty(state))
2557 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2558 "Trailing garbage, ignoring.");
2559
2560 return 0;
2561 }
2562 #endif
2563
2564 int config_parse_unit_slice(
2565 const char *unit,
2566 const char *filename,
2567 unsigned line,
2568 const char *section,
2569 unsigned section_line,
2570 const char *lvalue,
2571 int ltype,
2572 const char *rvalue,
2573 void *data,
2574 void *userdata) {
2575
2576 _cleanup_free_ char *k = NULL;
2577 Unit *u = userdata, *slice;
2578 int r;
2579
2580 assert(filename);
2581 assert(lvalue);
2582 assert(rvalue);
2583 assert(u);
2584
2585 r = unit_name_printf(u, rvalue, &k);
2586 if (r < 0)
2587 log_syntax(unit, LOG_ERR, filename, line, -r,
2588 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2589 if (!k) {
2590 k = strdup(rvalue);
2591 if (!k)
2592 return log_oom();
2593 }
2594
2595 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2596 if (r < 0) {
2597 log_syntax(unit, LOG_ERR, filename, line, -r,
2598 "Failed to load slice unit %s. Ignoring.", k);
2599 return 0;
2600 }
2601
2602 if (slice->type != UNIT_SLICE) {
2603 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2604 "Slice unit %s is not a slice. Ignoring.", k);
2605 return 0;
2606 }
2607
2608 unit_ref_set(&u->slice, slice);
2609 return 0;
2610 }
2611
2612 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2613
2614 int config_parse_cpu_shares(
2615 const char *unit,
2616 const char *filename,
2617 unsigned line,
2618 const char *section,
2619 unsigned section_line,
2620 const char *lvalue,
2621 int ltype,
2622 const char *rvalue,
2623 void *data,
2624 void *userdata) {
2625
2626 unsigned long *shares = data, lu;
2627 int r;
2628
2629 assert(filename);
2630 assert(lvalue);
2631 assert(rvalue);
2632
2633 if (isempty(rvalue)) {
2634 *shares = (unsigned long) -1;
2635 return 0;
2636 }
2637
2638 r = safe_atolu(rvalue, &lu);
2639 if (r < 0 || lu <= 0) {
2640 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2641 "CPU shares '%s' invalid. Ignoring.", rvalue);
2642 return 0;
2643 }
2644
2645 *shares = lu;
2646 return 0;
2647 }
2648
2649 int config_parse_cpu_quota(
2650 const char *unit,
2651 const char *filename,
2652 unsigned line,
2653 const char *section,
2654 unsigned section_line,
2655 const char *lvalue,
2656 int ltype,
2657 const char *rvalue,
2658 void *data,
2659 void *userdata) {
2660
2661 CGroupContext *c = data;
2662 double percent;
2663
2664 assert(filename);
2665 assert(lvalue);
2666 assert(rvalue);
2667
2668 if (isempty(rvalue)) {
2669 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2670 return 0;
2671 }
2672
2673 if (!endswith(rvalue, "%")) {
2674
2675 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2676 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2677 return 0;
2678 }
2679
2680 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2681 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2682 "CPU quota '%s' invalid. Ignoring.", rvalue);
2683 return 0;
2684 }
2685
2686 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2687
2688 return 0;
2689 }
2690
2691 int config_parse_memory_limit(
2692 const char *unit,
2693 const char *filename,
2694 unsigned line,
2695 const char *section,
2696 unsigned section_line,
2697 const char *lvalue,
2698 int ltype,
2699 const char *rvalue,
2700 void *data,
2701 void *userdata) {
2702
2703 CGroupContext *c = data;
2704 off_t bytes;
2705 int r;
2706
2707 if (isempty(rvalue)) {
2708 c->memory_limit = (uint64_t) -1;
2709 return 0;
2710 }
2711
2712 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2713
2714 r = parse_size(rvalue, 1024, &bytes);
2715 if (r < 0) {
2716 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2717 "Memory limit '%s' invalid. Ignoring.", rvalue);
2718 return 0;
2719 }
2720
2721 c->memory_limit = (uint64_t) bytes;
2722 return 0;
2723 }
2724
2725 int config_parse_device_allow(
2726 const char *unit,
2727 const char *filename,
2728 unsigned line,
2729 const char *section,
2730 unsigned section_line,
2731 const char *lvalue,
2732 int ltype,
2733 const char *rvalue,
2734 void *data,
2735 void *userdata) {
2736
2737 _cleanup_free_ char *path = NULL;
2738 CGroupContext *c = data;
2739 CGroupDeviceAllow *a;
2740 const char *m;
2741 size_t n;
2742
2743 if (isempty(rvalue)) {
2744 while (c->device_allow)
2745 cgroup_context_free_device_allow(c, c->device_allow);
2746
2747 return 0;
2748 }
2749
2750 n = strcspn(rvalue, WHITESPACE);
2751 path = strndup(rvalue, n);
2752 if (!path)
2753 return log_oom();
2754
2755 if (!startswith(path, "/dev/") &&
2756 !startswith(path, "block-") &&
2757 !startswith(path, "char-")) {
2758 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2759 "Invalid device node path '%s'. Ignoring.", path);
2760 return 0;
2761 }
2762
2763 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2764 if (isempty(m))
2765 m = "rwm";
2766
2767 if (!in_charset(m, "rwm")) {
2768 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2769 "Invalid device rights '%s'. Ignoring.", m);
2770 return 0;
2771 }
2772
2773 a = new0(CGroupDeviceAllow, 1);
2774 if (!a)
2775 return log_oom();
2776
2777 a->path = path;
2778 path = NULL;
2779 a->r = !!strchr(m, 'r');
2780 a->w = !!strchr(m, 'w');
2781 a->m = !!strchr(m, 'm');
2782
2783 LIST_PREPEND(device_allow, c->device_allow, a);
2784 return 0;
2785 }
2786
2787 int config_parse_blockio_weight(
2788 const char *unit,
2789 const char *filename,
2790 unsigned line,
2791 const char *section,
2792 unsigned section_line,
2793 const char *lvalue,
2794 int ltype,
2795 const char *rvalue,
2796 void *data,
2797 void *userdata) {
2798
2799 unsigned long *weight = data, lu;
2800 int r;
2801
2802 assert(filename);
2803 assert(lvalue);
2804 assert(rvalue);
2805
2806 if (isempty(rvalue)) {
2807 *weight = (unsigned long) -1;
2808 return 0;
2809 }
2810
2811 r = safe_atolu(rvalue, &lu);
2812 if (r < 0 || lu < 10 || lu > 1000) {
2813 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2814 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2815 return 0;
2816 }
2817
2818 *weight = lu;
2819 return 0;
2820 }
2821
2822 int config_parse_blockio_device_weight(
2823 const char *unit,
2824 const char *filename,
2825 unsigned line,
2826 const char *section,
2827 unsigned section_line,
2828 const char *lvalue,
2829 int ltype,
2830 const char *rvalue,
2831 void *data,
2832 void *userdata) {
2833
2834 _cleanup_free_ char *path = NULL;
2835 CGroupBlockIODeviceWeight *w;
2836 CGroupContext *c = data;
2837 unsigned long lu;
2838 const char *weight;
2839 size_t n;
2840 int r;
2841
2842 assert(filename);
2843 assert(lvalue);
2844 assert(rvalue);
2845
2846 if (isempty(rvalue)) {
2847 while (c->blockio_device_weights)
2848 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2849
2850 return 0;
2851 }
2852
2853 n = strcspn(rvalue, WHITESPACE);
2854 weight = rvalue + n;
2855 if (!*weight) {
2856 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2857 "Expected block device and device weight. Ignoring.");
2858 return 0;
2859 }
2860
2861 path = strndup(rvalue, n);
2862 if (!path)
2863 return log_oom();
2864
2865 if (!path_startswith(path, "/dev")) {
2866 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2867 "Invalid device node path '%s'. Ignoring.", path);
2868 return 0;
2869 }
2870
2871 weight += strspn(weight, WHITESPACE);
2872 r = safe_atolu(weight, &lu);
2873 if (r < 0 || lu < 10 || lu > 1000) {
2874 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2875 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2876 return 0;
2877 }
2878
2879 w = new0(CGroupBlockIODeviceWeight, 1);
2880 if (!w)
2881 return log_oom();
2882
2883 w->path = path;
2884 path = NULL;
2885
2886 w->weight = lu;
2887
2888 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2889 return 0;
2890 }
2891
2892 int config_parse_blockio_bandwidth(
2893 const char *unit,
2894 const char *filename,
2895 unsigned line,
2896 const char *section,
2897 unsigned section_line,
2898 const char *lvalue,
2899 int ltype,
2900 const char *rvalue,
2901 void *data,
2902 void *userdata) {
2903
2904 _cleanup_free_ char *path = NULL;
2905 CGroupBlockIODeviceBandwidth *b;
2906 CGroupContext *c = data;
2907 const char *bandwidth;
2908 off_t bytes;
2909 bool read;
2910 size_t n;
2911 int r;
2912
2913 assert(filename);
2914 assert(lvalue);
2915 assert(rvalue);
2916
2917 read = streq("BlockIOReadBandwidth", lvalue);
2918
2919 if (isempty(rvalue)) {
2920 CGroupBlockIODeviceBandwidth *next;
2921
2922 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2923 if (b->read == read)
2924 cgroup_context_free_blockio_device_bandwidth(c, b);
2925
2926 return 0;
2927 }
2928
2929 n = strcspn(rvalue, WHITESPACE);
2930 bandwidth = rvalue + n;
2931 bandwidth += strspn(bandwidth, WHITESPACE);
2932
2933 if (!*bandwidth) {
2934 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2935 "Expected space separated pair of device node and bandwidth. Ignoring.");
2936 return 0;
2937 }
2938
2939 path = strndup(rvalue, n);
2940 if (!path)
2941 return log_oom();
2942
2943 if (!path_startswith(path, "/dev")) {
2944 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2945 "Invalid device node path '%s'. Ignoring.", path);
2946 return 0;
2947 }
2948
2949 r = parse_size(bandwidth, 1000, &bytes);
2950 if (r < 0 || bytes <= 0) {
2951 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2952 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2953 return 0;
2954 }
2955
2956 b = new0(CGroupBlockIODeviceBandwidth, 1);
2957 if (!b)
2958 return log_oom();
2959
2960 b->path = path;
2961 path = NULL;
2962 b->bandwidth = (uint64_t) bytes;
2963 b->read = read;
2964
2965 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2966
2967 return 0;
2968 }
2969
2970 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2971
2972 int config_parse_job_mode_isolate(
2973 const char *unit,
2974 const char *filename,
2975 unsigned line,
2976 const char *section,
2977 unsigned section_line,
2978 const char *lvalue,
2979 int ltype,
2980 const char *rvalue,
2981 void *data,
2982 void *userdata) {
2983
2984 JobMode *m = data;
2985 int r;
2986
2987 assert(filename);
2988 assert(lvalue);
2989 assert(rvalue);
2990
2991 r = parse_boolean(rvalue);
2992 if (r < 0) {
2993 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2994 "Failed to parse boolean, ignoring: %s", rvalue);
2995 return 0;
2996 }
2997
2998 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2999 return 0;
3000 }
3001
3002 int config_parse_personality(
3003 const char *unit,
3004 const char *filename,
3005 unsigned line,
3006 const char *section,
3007 unsigned section_line,
3008 const char *lvalue,
3009 int ltype,
3010 const char *rvalue,
3011 void *data,
3012 void *userdata) {
3013
3014 unsigned long *personality = data, p;
3015
3016 assert(filename);
3017 assert(lvalue);
3018 assert(rvalue);
3019 assert(personality);
3020
3021 p = personality_from_string(rvalue);
3022 if (p == 0xffffffffUL) {
3023 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3024 "Failed to parse personality, ignoring: %s", rvalue);
3025 return 0;
3026 }
3027
3028 *personality = p;
3029 return 0;
3030 }
3031
3032 int config_parse_runtime_directory(
3033 const char *unit,
3034 const char *filename,
3035 unsigned line,
3036 const char *section,
3037 unsigned section_line,
3038 const char *lvalue,
3039 int ltype,
3040 const char *rvalue,
3041 void *data,
3042 void *userdata) {
3043
3044 char***rt = data;
3045 const char *word, *state;
3046 size_t l;
3047 int r;
3048
3049 assert(filename);
3050 assert(lvalue);
3051 assert(rvalue);
3052 assert(data);
3053
3054 if (isempty(rvalue)) {
3055 /* Empty assignment resets the list */
3056 strv_free(*rt);
3057 *rt = NULL;
3058 return 0;
3059 }
3060
3061 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3062 _cleanup_free_ char *n;
3063
3064 n = strndup(word, l);
3065 if (!n)
3066 return log_oom();
3067
3068 if (!filename_is_safe(n)) {
3069 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3070 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3071 continue;
3072 }
3073
3074 r = strv_push(rt, n);
3075 if (r < 0)
3076 return log_oom();
3077
3078 n = NULL;
3079 }
3080 if (!isempty(state))
3081 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3082 "Trailing garbage, ignoring.");
3083
3084 return 0;
3085 }
3086
3087 int config_parse_set_status(
3088 const char *unit,
3089 const char *filename,
3090 unsigned line,
3091 const char *section,
3092 unsigned section_line,
3093 const char *lvalue,
3094 int ltype,
3095 const char *rvalue,
3096 void *data,
3097 void *userdata) {
3098
3099 size_t l;
3100 const char *word, *state;
3101 int r;
3102 ExitStatusSet *status_set = data;
3103
3104 assert(filename);
3105 assert(lvalue);
3106 assert(rvalue);
3107 assert(data);
3108
3109 /* Empty assignment resets the list */
3110 if (isempty(rvalue)) {
3111 exit_status_set_free(status_set);
3112 return 0;
3113 }
3114
3115 FOREACH_WORD(word, l, rvalue, state) {
3116 _cleanup_free_ char *temp;
3117 int val;
3118
3119 temp = strndup(word, l);
3120 if (!temp)
3121 return log_oom();
3122
3123 r = safe_atoi(temp, &val);
3124 if (r < 0) {
3125 val = signal_from_string_try_harder(temp);
3126
3127 if (val <= 0) {
3128 log_syntax(unit, LOG_ERR, filename, line, -val,
3129 "Failed to parse value, ignoring: %s", word);
3130 return 0;
3131 }
3132 } else {
3133 if (val < 0 || val > 255) {
3134 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3135 "Value %d is outside range 0-255, ignoring", val);
3136 continue;
3137 }
3138 }
3139
3140 r = set_ensure_allocated(&status_set->status, NULL);
3141 if (r < 0)
3142 return log_oom();
3143
3144 r = set_put(status_set->status, INT_TO_PTR(val));
3145 if (r < 0) {
3146 log_syntax(unit, LOG_ERR, filename, line, -r,
3147 "Unable to store: %s", word);
3148 return r;
3149 }
3150 }
3151 if (!isempty(state))
3152 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3153 "Trailing garbage, ignoring.");
3154
3155 return 0;
3156 }
3157
3158 int config_parse_namespace_path_strv(
3159 const char *unit,
3160 const char *filename,
3161 unsigned line,
3162 const char *section,
3163 unsigned section_line,
3164 const char *lvalue,
3165 int ltype,
3166 const char *rvalue,
3167 void *data,
3168 void *userdata) {
3169
3170 char*** sv = data;
3171 const char *word, *state;
3172 size_t l;
3173 int r;
3174
3175 assert(filename);
3176 assert(lvalue);
3177 assert(rvalue);
3178 assert(data);
3179
3180 if (isempty(rvalue)) {
3181 /* Empty assignment resets the list */
3182 strv_free(*sv);
3183 *sv = NULL;
3184 return 0;
3185 }
3186
3187 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3188 _cleanup_free_ char *n;
3189 int offset;
3190
3191 n = strndup(word, l);
3192 if (!n)
3193 return log_oom();
3194
3195 if (!utf8_is_valid(n)) {
3196 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3197 continue;
3198 }
3199
3200 offset = n[0] == '-';
3201 if (!path_is_absolute(n + offset)) {
3202 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3203 "Not an absolute path, ignoring: %s", rvalue);
3204 continue;
3205 }
3206
3207 path_kill_slashes(n);
3208
3209 r = strv_push(sv, n);
3210 if (r < 0)
3211 return log_oom();
3212
3213 n = NULL;
3214 }
3215 if (!isempty(state))
3216 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3217 "Trailing garbage, ignoring.");
3218
3219 return 0;
3220 }
3221
3222 int config_parse_no_new_privileges(
3223 const char* unit,
3224 const char *filename,
3225 unsigned line,
3226 const char *section,
3227 unsigned section_line,
3228 const char *lvalue,
3229 int ltype,
3230 const char *rvalue,
3231 void *data,
3232 void *userdata) {
3233
3234 ExecContext *c = data;
3235 int k;
3236
3237 assert(filename);
3238 assert(lvalue);
3239 assert(rvalue);
3240 assert(data);
3241
3242 k = parse_boolean(rvalue);
3243 if (k < 0) {
3244 log_syntax(unit, LOG_ERR, filename, line, -k,
3245 "Failed to parse boolean value, ignoring: %s", rvalue);
3246 return 0;
3247 }
3248
3249 c->no_new_privileges = !!k;
3250 c->no_new_privileges_set = true;
3251
3252 return 0;
3253 }
3254
3255 int config_parse_protect_home(
3256 const char* unit,
3257 const char *filename,
3258 unsigned line,
3259 const char *section,
3260 unsigned section_line,
3261 const char *lvalue,
3262 int ltype,
3263 const char *rvalue,
3264 void *data,
3265 void *userdata) {
3266
3267 ExecContext *c = data;
3268 int k;
3269
3270 assert(filename);
3271 assert(lvalue);
3272 assert(rvalue);
3273 assert(data);
3274
3275 /* Our enum shall be a superset of booleans, hence first try
3276 * to parse as as boolean, and then as enum */
3277
3278 k = parse_boolean(rvalue);
3279 if (k > 0)
3280 c->protect_home = PROTECT_HOME_YES;
3281 else if (k == 0)
3282 c->protect_home = PROTECT_HOME_NO;
3283 else {
3284 ProtectHome h;
3285
3286 h = protect_home_from_string(rvalue);
3287 if (h < 0){
3288 log_syntax(unit, LOG_ERR, filename, line, -h,
3289 "Failed to parse protect home value, ignoring: %s", rvalue);
3290 return 0;
3291 }
3292
3293 c->protect_home = h;
3294 }
3295
3296 return 0;
3297 }
3298
3299 int config_parse_protect_system(
3300 const char* unit,
3301 const char *filename,
3302 unsigned line,
3303 const char *section,
3304 unsigned section_line,
3305 const char *lvalue,
3306 int ltype,
3307 const char *rvalue,
3308 void *data,
3309 void *userdata) {
3310
3311 ExecContext *c = data;
3312 int k;
3313
3314 assert(filename);
3315 assert(lvalue);
3316 assert(rvalue);
3317 assert(data);
3318
3319 /* Our enum shall be a superset of booleans, hence first try
3320 * to parse as as boolean, and then as enum */
3321
3322 k = parse_boolean(rvalue);
3323 if (k > 0)
3324 c->protect_system = PROTECT_SYSTEM_YES;
3325 else if (k == 0)
3326 c->protect_system = PROTECT_SYSTEM_NO;
3327 else {
3328 ProtectSystem s;
3329
3330 s = protect_system_from_string(rvalue);
3331 if (s < 0){
3332 log_syntax(unit, LOG_ERR, filename, line, -s,
3333 "Failed to parse protect system value, ignoring: %s", rvalue);
3334 return 0;
3335 }
3336
3337 c->protect_system = s;
3338 }
3339
3340 return 0;
3341 }
3342
3343 #define FOLLOW_MAX 8
3344
3345 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3346 unsigned c = 0;
3347 int fd, r;
3348 FILE *f;
3349 char *id = NULL;
3350
3351 assert(filename);
3352 assert(*filename);
3353 assert(_f);
3354 assert(names);
3355
3356 /* This will update the filename pointer if the loaded file is
3357 * reached by a symlink. The old string will be freed. */
3358
3359 for (;;) {
3360 char *target, *name;
3361
3362 if (c++ >= FOLLOW_MAX)
3363 return -ELOOP;
3364
3365 path_kill_slashes(*filename);
3366
3367 /* Add the file name we are currently looking at to
3368 * the names of this unit, but only if it is a valid
3369 * unit name. */
3370 name = basename(*filename);
3371
3372 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3373
3374 id = set_get(names, name);
3375 if (!id) {
3376 id = strdup(name);
3377 if (!id)
3378 return -ENOMEM;
3379
3380 r = set_consume(names, id);
3381 if (r < 0)
3382 return r;
3383 }
3384 }
3385
3386 /* Try to open the file name, but don't if its a symlink */
3387 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3388 if (fd >= 0)
3389 break;
3390
3391 if (errno != ELOOP)
3392 return -errno;
3393
3394 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3395 r = readlink_and_make_absolute(*filename, &target);
3396 if (r < 0)
3397 return r;
3398
3399 free(*filename);
3400 *filename = target;
3401 }
3402
3403 f = fdopen(fd, "re");
3404 if (!f) {
3405 r = -errno;
3406 safe_close(fd);
3407 return r;
3408 }
3409
3410 *_f = f;
3411 *_final = id;
3412 return 0;
3413 }
3414
3415 static int merge_by_names(Unit **u, Set *names, const char *id) {
3416 char *k;
3417 int r;
3418
3419 assert(u);
3420 assert(*u);
3421 assert(names);
3422
3423 /* Let's try to add in all symlink names we found */
3424 while ((k = set_steal_first(names))) {
3425
3426 /* First try to merge in the other name into our
3427 * unit */
3428 r = unit_merge_by_name(*u, k);
3429 if (r < 0) {
3430 Unit *other;
3431
3432 /* Hmm, we couldn't merge the other unit into
3433 * ours? Then let's try it the other way
3434 * round */
3435
3436 other = manager_get_unit((*u)->manager, k);
3437 free(k);
3438
3439 if (other) {
3440 r = unit_merge(other, *u);
3441 if (r >= 0) {
3442 *u = other;
3443 return merge_by_names(u, names, NULL);
3444 }
3445 }
3446
3447 return r;
3448 }
3449
3450 if (id == k)
3451 unit_choose_id(*u, id);
3452
3453 free(k);
3454 }
3455
3456 return 0;
3457 }
3458
3459 static int load_from_path(Unit *u, const char *path) {
3460 int r;
3461 _cleanup_set_free_free_ Set *symlink_names = NULL;
3462 _cleanup_fclose_ FILE *f = NULL;
3463 _cleanup_free_ char *filename = NULL;
3464 char *id = NULL;
3465 Unit *merged;
3466 struct stat st;
3467
3468 assert(u);
3469 assert(path);
3470
3471 symlink_names = set_new(&string_hash_ops);
3472 if (!symlink_names)
3473 return -ENOMEM;
3474
3475 if (path_is_absolute(path)) {
3476
3477 filename = strdup(path);
3478 if (!filename)
3479 return -ENOMEM;
3480
3481 r = open_follow(&filename, &f, symlink_names, &id);
3482 if (r < 0) {
3483 free(filename);
3484 filename = NULL;
3485
3486 if (r != -ENOENT)
3487 return r;
3488 }
3489
3490 } else {
3491 char **p;
3492
3493 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3494
3495 /* Instead of opening the path right away, we manually
3496 * follow all symlinks and add their name to our unit
3497 * name set while doing so */
3498 filename = path_make_absolute(path, *p);
3499 if (!filename)
3500 return -ENOMEM;
3501
3502 if (u->manager->unit_path_cache &&
3503 !set_get(u->manager->unit_path_cache, filename))
3504 r = -ENOENT;
3505 else
3506 r = open_follow(&filename, &f, symlink_names, &id);
3507
3508 if (r < 0) {
3509 free(filename);
3510 filename = NULL;
3511
3512 if (r != -ENOENT)
3513 return r;
3514
3515 /* Empty the symlink names for the next run */
3516 set_clear_free(symlink_names);
3517 continue;
3518 }
3519
3520 break;
3521 }
3522 }
3523
3524 if (!filename)
3525 /* Hmm, no suitable file found? */
3526 return 0;
3527
3528 merged = u;
3529 r = merge_by_names(&merged, symlink_names, id);
3530 if (r < 0)
3531 return r;
3532
3533 if (merged != u) {
3534 u->load_state = UNIT_MERGED;
3535 return 0;
3536 }
3537
3538 if (fstat(fileno(f), &st) < 0)
3539 return -errno;
3540
3541 if (null_or_empty(&st))
3542 u->load_state = UNIT_MASKED;
3543 else {
3544 u->load_state = UNIT_LOADED;
3545
3546 /* Now, parse the file contents */
3547 r = config_parse(u->id, filename, f,
3548 UNIT_VTABLE(u)->sections,
3549 config_item_perf_lookup, load_fragment_gperf_lookup,
3550 false, true, false, u);
3551 if (r < 0)
3552 return r;
3553 }
3554
3555 free(u->fragment_path);
3556 u->fragment_path = filename;
3557 filename = NULL;
3558
3559 u->fragment_mtime = timespec_load(&st.st_mtim);
3560
3561 if (u->source_path) {
3562 if (stat(u->source_path, &st) >= 0)
3563 u->source_mtime = timespec_load(&st.st_mtim);
3564 else
3565 u->source_mtime = 0;
3566 }
3567
3568 return 0;
3569 }
3570
3571 int unit_load_fragment(Unit *u) {
3572 int r;
3573 Iterator i;
3574 const char *t;
3575
3576 assert(u);
3577 assert(u->load_state == UNIT_STUB);
3578 assert(u->id);
3579
3580 /* First, try to find the unit under its id. We always look
3581 * for unit files in the default directories, to make it easy
3582 * to override things by placing things in /etc/systemd/system */
3583 r = load_from_path(u, u->id);
3584 if (r < 0)
3585 return r;
3586
3587 /* Try to find an alias we can load this with */
3588 if (u->load_state == UNIT_STUB)
3589 SET_FOREACH(t, u->names, i) {
3590
3591 if (t == u->id)
3592 continue;
3593
3594 r = load_from_path(u, t);
3595 if (r < 0)
3596 return r;
3597
3598 if (u->load_state != UNIT_STUB)
3599 break;
3600 }
3601
3602 /* And now, try looking for it under the suggested (originally linked) path */
3603 if (u->load_state == UNIT_STUB && u->fragment_path) {
3604
3605 r = load_from_path(u, u->fragment_path);
3606 if (r < 0)
3607 return r;
3608
3609 if (u->load_state == UNIT_STUB) {
3610 /* Hmm, this didn't work? Then let's get rid
3611 * of the fragment path stored for us, so that
3612 * we don't point to an invalid location. */
3613 free(u->fragment_path);
3614 u->fragment_path = NULL;
3615 }
3616 }
3617
3618 /* Look for a template */
3619 if (u->load_state == UNIT_STUB && u->instance) {
3620 _cleanup_free_ char *k;
3621
3622 k = unit_name_template(u->id);
3623 if (!k)
3624 return -ENOMEM;
3625
3626 r = load_from_path(u, k);
3627 if (r < 0)
3628 return r;
3629
3630 if (u->load_state == UNIT_STUB)
3631 SET_FOREACH(t, u->names, i) {
3632 _cleanup_free_ char *z = NULL;
3633
3634 if (t == u->id)
3635 continue;
3636
3637 z = unit_name_template(t);
3638 if (!z)
3639 return -ENOMEM;
3640
3641 r = load_from_path(u, z);
3642 if (r < 0)
3643 return r;
3644
3645 if (u->load_state != UNIT_STUB)
3646 break;
3647 }
3648 }
3649
3650 return 0;
3651 }
3652
3653 void unit_dump_config_items(FILE *f) {
3654 static const struct {
3655 const ConfigParserCallback callback;
3656 const char *rvalue;
3657 } table[] = {
3658 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3659 { config_parse_warn_compat, "NOTSUPPORTED" },
3660 #endif
3661 { config_parse_int, "INTEGER" },
3662 { config_parse_unsigned, "UNSIGNED" },
3663 { config_parse_iec_size, "SIZE" },
3664 { config_parse_iec_off, "SIZE" },
3665 { config_parse_si_size, "SIZE" },
3666 { config_parse_bool, "BOOLEAN" },
3667 { config_parse_string, "STRING" },
3668 { config_parse_path, "PATH" },
3669 { config_parse_unit_path_printf, "PATH" },
3670 { config_parse_strv, "STRING [...]" },
3671 { config_parse_exec_nice, "NICE" },
3672 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3673 { config_parse_exec_io_class, "IOCLASS" },
3674 { config_parse_exec_io_priority, "IOPRIORITY" },
3675 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3676 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3677 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3678 { config_parse_mode, "MODE" },
3679 { config_parse_unit_env_file, "FILE" },
3680 { config_parse_output, "OUTPUT" },
3681 { config_parse_input, "INPUT" },
3682 { config_parse_log_facility, "FACILITY" },
3683 { config_parse_log_level, "LEVEL" },
3684 { config_parse_exec_capabilities, "CAPABILITIES" },
3685 { config_parse_exec_secure_bits, "SECUREBITS" },
3686 { config_parse_bounding_set, "BOUNDINGSET" },
3687 { config_parse_limit, "LIMIT" },
3688 { config_parse_unit_deps, "UNIT [...]" },
3689 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3690 { config_parse_service_type, "SERVICETYPE" },
3691 { config_parse_service_restart, "SERVICERESTART" },
3692 #ifdef HAVE_SYSV_COMPAT
3693 { config_parse_sysv_priority, "SYSVPRIORITY" },
3694 #endif
3695 { config_parse_kill_mode, "KILLMODE" },
3696 { config_parse_kill_signal, "SIGNAL" },
3697 { config_parse_socket_listen, "SOCKET [...]" },
3698 { config_parse_socket_bind, "SOCKETBIND" },
3699 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3700 { config_parse_sec, "SECONDS" },
3701 { config_parse_nsec, "NANOSECONDS" },
3702 { config_parse_namespace_path_strv, "PATH [...]" },
3703 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3704 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3705 { config_parse_unit_string_printf, "STRING" },
3706 { config_parse_trigger_unit, "UNIT" },
3707 { config_parse_timer, "TIMER" },
3708 { config_parse_path_spec, "PATH" },
3709 { config_parse_notify_access, "ACCESS" },
3710 { config_parse_ip_tos, "TOS" },
3711 { config_parse_unit_condition_path, "CONDITION" },
3712 { config_parse_unit_condition_string, "CONDITION" },
3713 { config_parse_unit_condition_null, "CONDITION" },
3714 { config_parse_unit_slice, "SLICE" },
3715 { config_parse_documentation, "URL" },
3716 { config_parse_service_timeout, "SECONDS" },
3717 { config_parse_failure_action, "ACTION" },
3718 { config_parse_set_status, "STATUS" },
3719 { config_parse_service_sockets, "SOCKETS" },
3720 { config_parse_environ, "ENVIRON" },
3721 #ifdef HAVE_SECCOMP
3722 { config_parse_syscall_filter, "SYSCALLS" },
3723 { config_parse_syscall_archs, "ARCHS" },
3724 { config_parse_syscall_errno, "ERRNO" },
3725 { config_parse_address_families, "FAMILIES" },
3726 #endif
3727 { config_parse_cpu_shares, "SHARES" },
3728 { config_parse_memory_limit, "LIMIT" },
3729 { config_parse_device_allow, "DEVICE" },
3730 { config_parse_device_policy, "POLICY" },
3731 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3732 { config_parse_blockio_weight, "WEIGHT" },
3733 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3734 { config_parse_long, "LONG" },
3735 { config_parse_socket_service, "SERVICE" },
3736 #ifdef HAVE_SELINUX
3737 { config_parse_exec_selinux_context, "LABEL" },
3738 #endif
3739 { config_parse_job_mode, "MODE" },
3740 { config_parse_job_mode_isolate, "BOOLEAN" },
3741 { config_parse_personality, "PERSONALITY" },
3742 };
3743
3744 const char *prev = NULL;
3745 const char *i;
3746
3747 assert(f);
3748
3749 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3750 const char *rvalue = "OTHER", *lvalue;
3751 unsigned j;
3752 size_t prefix_len;
3753 const char *dot;
3754 const ConfigPerfItem *p;
3755
3756 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3757
3758 dot = strchr(i, '.');
3759 lvalue = dot ? dot + 1 : i;
3760 prefix_len = dot-i;
3761
3762 if (dot)
3763 if (!prev || !strneq(prev, i, prefix_len+1)) {
3764 if (prev)
3765 fputc('\n', f);
3766
3767 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3768 }
3769
3770 for (j = 0; j < ELEMENTSOF(table); j++)
3771 if (p->parse == table[j].callback) {
3772 rvalue = table[j].rvalue;
3773 break;
3774 }
3775
3776 fprintf(f, "%s=%s\n", lvalue, rvalue);
3777 prev = i;
3778 }
3779 }