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