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