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