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