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