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