]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
Merge pull request #1653 from keszybz/lz4-compress-time
[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 _cleanup_free_ char *p = NULL;
1479 Socket *s = data;
1480 Unit *x;
1481 int r;
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_fdname(
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 _cleanup_free_ char *p = NULL;
1523 Socket *s = data;
1524 int r;
1525
1526 assert(filename);
1527 assert(lvalue);
1528 assert(rvalue);
1529 assert(data);
1530
1531 if (isempty(rvalue)) {
1532 s->fdname = mfree(s->fdname);
1533 return 0;
1534 }
1535
1536 r = unit_name_printf(UNIT(s), rvalue, &p);
1537 if (r < 0) {
1538 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1539 return 0;
1540 }
1541
1542 if (!fdname_is_valid(p)) {
1543 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
1544 return 0;
1545 }
1546
1547 free(s->fdname);
1548 s->fdname = p;
1549 p = NULL;
1550
1551 return 0;
1552 }
1553
1554 int config_parse_service_sockets(
1555 const char *unit,
1556 const char *filename,
1557 unsigned line,
1558 const char *section,
1559 unsigned section_line,
1560 const char *lvalue,
1561 int ltype,
1562 const char *rvalue,
1563 void *data,
1564 void *userdata) {
1565
1566 Service *s = data;
1567 const char *word, *state;
1568 size_t l;
1569 int r;
1570
1571 assert(filename);
1572 assert(lvalue);
1573 assert(rvalue);
1574 assert(data);
1575
1576 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1577 _cleanup_free_ char *t = NULL, *k = NULL;
1578
1579 t = strndup(word, l);
1580 if (!t)
1581 return log_oom();
1582
1583 r = unit_name_printf(UNIT(s), t, &k);
1584 if (r < 0) {
1585 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1586 continue;
1587 }
1588
1589 if (!endswith(k, ".socket")) {
1590 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
1591 continue;
1592 }
1593
1594 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1595 if (r < 0)
1596 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1597
1598 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1599 if (r < 0)
1600 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1601 }
1602 if (!isempty(state))
1603 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
1604
1605 return 0;
1606 }
1607
1608 int config_parse_bus_name(
1609 const char *unit,
1610 const char *filename,
1611 unsigned line,
1612 const char *section,
1613 unsigned section_line,
1614 const char *lvalue,
1615 int ltype,
1616 const char *rvalue,
1617 void *data,
1618 void *userdata) {
1619
1620 _cleanup_free_ char *k = NULL;
1621 Unit *u = userdata;
1622 int r;
1623
1624 assert(filename);
1625 assert(lvalue);
1626 assert(rvalue);
1627 assert(u);
1628
1629 r = unit_full_printf(u, rvalue, &k);
1630 if (r < 0) {
1631 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1632 return 0;
1633 }
1634
1635 if (!service_name_is_valid(k)) {
1636 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
1637 return 0;
1638 }
1639
1640 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1641 }
1642
1643 int config_parse_service_timeout(const char *unit,
1644 const char *filename,
1645 unsigned line,
1646 const char *section,
1647 unsigned section_line,
1648 const char *lvalue,
1649 int ltype,
1650 const char *rvalue,
1651 void *data,
1652 void *userdata) {
1653
1654 Service *s = userdata;
1655 int r;
1656
1657 assert(filename);
1658 assert(lvalue);
1659 assert(rvalue);
1660 assert(s);
1661
1662 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1663 rvalue, data, userdata);
1664 if (r < 0)
1665 return r;
1666
1667 if (streq(lvalue, "TimeoutSec")) {
1668 s->start_timeout_defined = true;
1669 s->timeout_stop_usec = s->timeout_start_usec;
1670 } else if (streq(lvalue, "TimeoutStartSec"))
1671 s->start_timeout_defined = true;
1672
1673 return 0;
1674 }
1675
1676 int config_parse_busname_service(
1677 const char *unit,
1678 const char *filename,
1679 unsigned line,
1680 const char *section,
1681 unsigned section_line,
1682 const char *lvalue,
1683 int ltype,
1684 const char *rvalue,
1685 void *data,
1686 void *userdata) {
1687
1688 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1689 BusName *n = data;
1690 int r;
1691 Unit *x;
1692 _cleanup_free_ char *p = NULL;
1693
1694 assert(filename);
1695 assert(lvalue);
1696 assert(rvalue);
1697 assert(data);
1698
1699 r = unit_name_printf(UNIT(n), rvalue, &p);
1700 if (r < 0) {
1701 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1702 return 0;
1703 }
1704
1705 if (!endswith(p, ".service")) {
1706 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
1707 return 0;
1708 }
1709
1710 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1711 if (r < 0) {
1712 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1713 return 0;
1714 }
1715
1716 unit_ref_set(&n->service, x);
1717
1718 return 0;
1719 }
1720
1721 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1722
1723 int config_parse_bus_policy(
1724 const char *unit,
1725 const char *filename,
1726 unsigned line,
1727 const char *section,
1728 unsigned section_line,
1729 const char *lvalue,
1730 int ltype,
1731 const char *rvalue,
1732 void *data,
1733 void *userdata) {
1734
1735 _cleanup_free_ BusNamePolicy *p = NULL;
1736 _cleanup_free_ char *id_str = NULL;
1737 BusName *busname = data;
1738 char *access_str;
1739
1740 assert(filename);
1741 assert(lvalue);
1742 assert(rvalue);
1743 assert(data);
1744
1745 p = new0(BusNamePolicy, 1);
1746 if (!p)
1747 return log_oom();
1748
1749 if (streq(lvalue, "AllowUser"))
1750 p->type = BUSNAME_POLICY_TYPE_USER;
1751 else if (streq(lvalue, "AllowGroup"))
1752 p->type = BUSNAME_POLICY_TYPE_GROUP;
1753 else
1754 assert_not_reached("Unknown lvalue");
1755
1756 id_str = strdup(rvalue);
1757 if (!id_str)
1758 return log_oom();
1759
1760 access_str = strpbrk(id_str, WHITESPACE);
1761 if (!access_str) {
1762 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
1763 return 0;
1764 }
1765
1766 *access_str = '\0';
1767 access_str++;
1768 access_str += strspn(access_str, WHITESPACE);
1769
1770 p->access = bus_policy_access_from_string(access_str);
1771 if (p->access < 0) {
1772 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
1773 return 0;
1774 }
1775
1776 p->name = id_str;
1777 id_str = NULL;
1778
1779 LIST_PREPEND(policy, busname->policy, p);
1780 p = NULL;
1781
1782 return 0;
1783 }
1784
1785 int config_parse_bus_endpoint_policy(
1786 const char *unit,
1787 const char *filename,
1788 unsigned line,
1789 const char *section,
1790 unsigned section_line,
1791 const char *lvalue,
1792 int ltype,
1793 const char *rvalue,
1794 void *data,
1795 void *userdata) {
1796
1797 _cleanup_free_ char *name = NULL;
1798 BusPolicyAccess access;
1799 ExecContext *c = data;
1800 char *access_str;
1801 int r;
1802
1803 assert(filename);
1804 assert(lvalue);
1805 assert(rvalue);
1806 assert(data);
1807
1808 name = strdup(rvalue);
1809 if (!name)
1810 return log_oom();
1811
1812 access_str = strpbrk(name, WHITESPACE);
1813 if (!access_str) {
1814 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue);
1815 return 0;
1816 }
1817
1818 *access_str = '\0';
1819 access_str++;
1820 access_str += strspn(access_str, WHITESPACE);
1821
1822 access = bus_policy_access_from_string(access_str);
1823 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1824 access >= _BUS_POLICY_ACCESS_MAX) {
1825 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str);
1826 return 0;
1827 }
1828
1829 if (!c->bus_endpoint) {
1830 r = bus_endpoint_new(&c->bus_endpoint);
1831 if (r < 0)
1832 return log_error_errno(r, "Failed to create bus endpoint object: %m");
1833 }
1834
1835 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1836 }
1837
1838 int config_parse_working_directory(
1839 const char *unit,
1840 const char *filename,
1841 unsigned line,
1842 const char *section,
1843 unsigned section_line,
1844 const char *lvalue,
1845 int ltype,
1846 const char *rvalue,
1847 void *data,
1848 void *userdata) {
1849
1850 ExecContext *c = data;
1851 Unit *u = userdata;
1852 bool missing_ok;
1853 int r;
1854
1855 assert(filename);
1856 assert(lvalue);
1857 assert(rvalue);
1858 assert(c);
1859 assert(u);
1860
1861 if (rvalue[0] == '-') {
1862 missing_ok = true;
1863 rvalue++;
1864 } else
1865 missing_ok = false;
1866
1867 if (streq(rvalue, "~")) {
1868 c->working_directory_home = true;
1869 c->working_directory = mfree(c->working_directory);
1870 } else {
1871 _cleanup_free_ char *k = NULL;
1872
1873 r = unit_full_printf(u, rvalue, &k);
1874 if (r < 0) {
1875 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
1876 return 0;
1877 }
1878
1879 path_kill_slashes(k);
1880
1881 if (!utf8_is_valid(k)) {
1882 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
1883 return 0;
1884 }
1885
1886 if (!path_is_absolute(k)) {
1887 log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
1888 return 0;
1889 }
1890
1891 free(c->working_directory);
1892 c->working_directory = k;
1893 k = NULL;
1894
1895 c->working_directory_home = false;
1896 }
1897
1898 c->working_directory_missing_ok = missing_ok;
1899 return 0;
1900 }
1901
1902 int config_parse_unit_env_file(const char *unit,
1903 const char *filename,
1904 unsigned line,
1905 const char *section,
1906 unsigned section_line,
1907 const char *lvalue,
1908 int ltype,
1909 const char *rvalue,
1910 void *data,
1911 void *userdata) {
1912
1913 char ***env = data;
1914 Unit *u = userdata;
1915 _cleanup_free_ char *n = NULL;
1916 int r;
1917
1918 assert(filename);
1919 assert(lvalue);
1920 assert(rvalue);
1921 assert(data);
1922
1923 if (isempty(rvalue)) {
1924 /* Empty assignment frees the list */
1925 *env = strv_free(*env);
1926 return 0;
1927 }
1928
1929 r = unit_full_printf(u, rvalue, &n);
1930 if (r < 0) {
1931 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1932 return 0;
1933 }
1934
1935 if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
1936 log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
1937 return 0;
1938 }
1939
1940 r = strv_extend(env, n);
1941 if (r < 0)
1942 return log_oom();
1943
1944 return 0;
1945 }
1946
1947 int config_parse_environ(const char *unit,
1948 const char *filename,
1949 unsigned line,
1950 const char *section,
1951 unsigned section_line,
1952 const char *lvalue,
1953 int ltype,
1954 const char *rvalue,
1955 void *data,
1956 void *userdata) {
1957
1958 Unit *u = userdata;
1959 char*** env = data;
1960 const char *word, *state;
1961 size_t l;
1962 _cleanup_free_ char *k = NULL;
1963 int r;
1964
1965 assert(filename);
1966 assert(lvalue);
1967 assert(rvalue);
1968 assert(data);
1969
1970 if (isempty(rvalue)) {
1971 /* Empty assignment resets the list */
1972 *env = strv_free(*env);
1973 return 0;
1974 }
1975
1976 if (u) {
1977 r = unit_full_printf(u, rvalue, &k);
1978 if (r < 0) {
1979 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1980 return 0;
1981 }
1982 }
1983
1984 if (!k) {
1985 k = strdup(rvalue);
1986 if (!k)
1987 return log_oom();
1988 }
1989
1990 FOREACH_WORD_QUOTED(word, l, k, state) {
1991 _cleanup_free_ char *n = NULL;
1992 char **x;
1993
1994 r = cunescape_length(word, l, 0, &n);
1995 if (r < 0) {
1996 log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
1997 continue;
1998 }
1999
2000 if (!env_assignment_is_valid(n)) {
2001 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue);
2002 continue;
2003 }
2004
2005 x = strv_env_set(*env, n);
2006 if (!x)
2007 return log_oom();
2008
2009 strv_free(*env);
2010 *env = x;
2011 }
2012 if (!isempty(state))
2013 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
2014
2015 return 0;
2016 }
2017
2018 int config_parse_ip_tos(const char *unit,
2019 const char *filename,
2020 unsigned line,
2021 const char *section,
2022 unsigned section_line,
2023 const char *lvalue,
2024 int ltype,
2025 const char *rvalue,
2026 void *data,
2027 void *userdata) {
2028
2029 int *ip_tos = data, x;
2030
2031 assert(filename);
2032 assert(lvalue);
2033 assert(rvalue);
2034 assert(data);
2035
2036 x = ip_tos_from_string(rvalue);
2037 if (x < 0) {
2038 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
2039 return 0;
2040 }
2041
2042 *ip_tos = x;
2043 return 0;
2044 }
2045
2046 int config_parse_unit_condition_path(
2047 const char *unit,
2048 const char *filename,
2049 unsigned line,
2050 const char *section,
2051 unsigned section_line,
2052 const char *lvalue,
2053 int ltype,
2054 const char *rvalue,
2055 void *data,
2056 void *userdata) {
2057
2058 _cleanup_free_ char *p = NULL;
2059 Condition **list = data, *c;
2060 ConditionType t = ltype;
2061 bool trigger, negate;
2062 Unit *u = userdata;
2063 int r;
2064
2065 assert(filename);
2066 assert(lvalue);
2067 assert(rvalue);
2068 assert(data);
2069
2070 if (isempty(rvalue)) {
2071 /* Empty assignment resets the list */
2072 *list = condition_free_list(*list);
2073 return 0;
2074 }
2075
2076 trigger = rvalue[0] == '|';
2077 if (trigger)
2078 rvalue++;
2079
2080 negate = rvalue[0] == '!';
2081 if (negate)
2082 rvalue++;
2083
2084 r = unit_full_printf(u, rvalue, &p);
2085 if (r < 0) {
2086 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2087 return 0;
2088 }
2089
2090 if (!path_is_absolute(p)) {
2091 log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
2092 return 0;
2093 }
2094
2095 c = condition_new(t, p, trigger, negate);
2096 if (!c)
2097 return log_oom();
2098
2099 LIST_PREPEND(conditions, *list, c);
2100 return 0;
2101 }
2102
2103 int config_parse_unit_condition_string(
2104 const char *unit,
2105 const char *filename,
2106 unsigned line,
2107 const char *section,
2108 unsigned section_line,
2109 const char *lvalue,
2110 int ltype,
2111 const char *rvalue,
2112 void *data,
2113 void *userdata) {
2114
2115 _cleanup_free_ char *s = NULL;
2116 Condition **list = data, *c;
2117 ConditionType t = ltype;
2118 bool trigger, negate;
2119 Unit *u = userdata;
2120 int r;
2121
2122 assert(filename);
2123 assert(lvalue);
2124 assert(rvalue);
2125 assert(data);
2126
2127 if (isempty(rvalue)) {
2128 /* Empty assignment resets the list */
2129 *list = condition_free_list(*list);
2130 return 0;
2131 }
2132
2133 trigger = rvalue[0] == '|';
2134 if (trigger)
2135 rvalue++;
2136
2137 negate = rvalue[0] == '!';
2138 if (negate)
2139 rvalue++;
2140
2141 r = unit_full_printf(u, rvalue, &s);
2142 if (r < 0) {
2143 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2144 return 0;
2145 }
2146
2147 c = condition_new(t, s, trigger, negate);
2148 if (!c)
2149 return log_oom();
2150
2151 LIST_PREPEND(conditions, *list, c);
2152 return 0;
2153 }
2154
2155 int config_parse_unit_condition_null(
2156 const char *unit,
2157 const char *filename,
2158 unsigned line,
2159 const char *section,
2160 unsigned section_line,
2161 const char *lvalue,
2162 int ltype,
2163 const char *rvalue,
2164 void *data,
2165 void *userdata) {
2166
2167 Condition **list = data, *c;
2168 bool trigger, negate;
2169 int b;
2170
2171 assert(filename);
2172 assert(lvalue);
2173 assert(rvalue);
2174 assert(data);
2175
2176 if (isempty(rvalue)) {
2177 /* Empty assignment resets the list */
2178 *list = condition_free_list(*list);
2179 return 0;
2180 }
2181
2182 trigger = rvalue[0] == '|';
2183 if (trigger)
2184 rvalue++;
2185
2186 negate = rvalue[0] == '!';
2187 if (negate)
2188 rvalue++;
2189
2190 b = parse_boolean(rvalue);
2191 if (b < 0) {
2192 log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2193 return 0;
2194 }
2195
2196 if (!b)
2197 negate = !negate;
2198
2199 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2200 if (!c)
2201 return log_oom();
2202
2203 LIST_PREPEND(conditions, *list, c);
2204 return 0;
2205 }
2206
2207 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2208 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2209
2210 int config_parse_unit_requires_mounts_for(
2211 const char *unit,
2212 const char *filename,
2213 unsigned line,
2214 const char *section,
2215 unsigned section_line,
2216 const char *lvalue,
2217 int ltype,
2218 const char *rvalue,
2219 void *data,
2220 void *userdata) {
2221
2222 Unit *u = userdata;
2223 const char *word, *state;
2224 size_t l;
2225
2226 assert(filename);
2227 assert(lvalue);
2228 assert(rvalue);
2229 assert(data);
2230
2231 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2232 int r;
2233 _cleanup_free_ char *n;
2234
2235 n = strndup(word, l);
2236 if (!n)
2237 return log_oom();
2238
2239 if (!utf8_is_valid(n)) {
2240 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
2241 continue;
2242 }
2243
2244 r = unit_require_mounts_for(u, n);
2245 if (r < 0) {
2246 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue);
2247 continue;
2248 }
2249 }
2250 if (!isempty(state))
2251 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
2252
2253 return 0;
2254 }
2255
2256 int config_parse_documentation(const char *unit,
2257 const char *filename,
2258 unsigned line,
2259 const char *section,
2260 unsigned section_line,
2261 const char *lvalue,
2262 int ltype,
2263 const char *rvalue,
2264 void *data,
2265 void *userdata) {
2266
2267 Unit *u = userdata;
2268 int r;
2269 char **a, **b;
2270
2271 assert(filename);
2272 assert(lvalue);
2273 assert(rvalue);
2274 assert(u);
2275
2276 if (isempty(rvalue)) {
2277 /* Empty assignment resets the list */
2278 u->documentation = strv_free(u->documentation);
2279 return 0;
2280 }
2281
2282 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2283 rvalue, data, userdata);
2284 if (r < 0)
2285 return r;
2286
2287 for (a = b = u->documentation; a && *a; a++) {
2288
2289 if (documentation_url_is_valid(*a))
2290 *(b++) = *a;
2291 else {
2292 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
2293 free(*a);
2294 }
2295 }
2296 if (b)
2297 *b = NULL;
2298
2299 return r;
2300 }
2301
2302 #ifdef HAVE_SECCOMP
2303 int config_parse_syscall_filter(
2304 const char *unit,
2305 const char *filename,
2306 unsigned line,
2307 const char *section,
2308 unsigned section_line,
2309 const char *lvalue,
2310 int ltype,
2311 const char *rvalue,
2312 void *data,
2313 void *userdata) {
2314
2315 static const char default_syscalls[] =
2316 "execve\0"
2317 "exit\0"
2318 "exit_group\0"
2319 "rt_sigreturn\0"
2320 "sigreturn\0";
2321
2322 ExecContext *c = data;
2323 Unit *u = userdata;
2324 bool invert = false;
2325 const char *word, *state;
2326 size_t l;
2327 int r;
2328
2329 assert(filename);
2330 assert(lvalue);
2331 assert(rvalue);
2332 assert(u);
2333
2334 if (isempty(rvalue)) {
2335 /* Empty assignment resets the list */
2336 c->syscall_filter = set_free(c->syscall_filter);
2337 c->syscall_whitelist = false;
2338 return 0;
2339 }
2340
2341 if (rvalue[0] == '~') {
2342 invert = true;
2343 rvalue++;
2344 }
2345
2346 if (!c->syscall_filter) {
2347 c->syscall_filter = set_new(NULL);
2348 if (!c->syscall_filter)
2349 return log_oom();
2350
2351 if (invert)
2352 /* Allow everything but the ones listed */
2353 c->syscall_whitelist = false;
2354 else {
2355 const char *i;
2356
2357 /* Allow nothing but the ones listed */
2358 c->syscall_whitelist = true;
2359
2360 /* Accept default syscalls if we are on a whitelist */
2361 NULSTR_FOREACH(i, default_syscalls) {
2362 int id;
2363
2364 id = seccomp_syscall_resolve_name(i);
2365 if (id < 0)
2366 continue;
2367
2368 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2369 if (r == 0)
2370 continue;
2371 if (r < 0)
2372 return log_oom();
2373 }
2374 }
2375 }
2376
2377 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2378 _cleanup_free_ char *t = NULL;
2379 int id;
2380
2381 t = strndup(word, l);
2382 if (!t)
2383 return log_oom();
2384
2385 id = seccomp_syscall_resolve_name(t);
2386 if (id < 0) {
2387 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
2388 continue;
2389 }
2390
2391 /* If we previously wanted to forbid a syscall and now
2392 * we want to allow it, then remove it from the list
2393 */
2394 if (!invert == c->syscall_whitelist) {
2395 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2396 if (r == 0)
2397 continue;
2398 if (r < 0)
2399 return log_oom();
2400 } else
2401 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2402 }
2403 if (!isempty(state))
2404 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
2405
2406 /* Turn on NNP, but only if it wasn't configured explicitly
2407 * before, and only if we are in user mode. */
2408 if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
2409 c->no_new_privileges = true;
2410
2411 return 0;
2412 }
2413
2414 int config_parse_syscall_archs(
2415 const char *unit,
2416 const char *filename,
2417 unsigned line,
2418 const char *section,
2419 unsigned section_line,
2420 const char *lvalue,
2421 int ltype,
2422 const char *rvalue,
2423 void *data,
2424 void *userdata) {
2425
2426 Set **archs = data;
2427 const char *word, *state;
2428 size_t l;
2429 int r;
2430
2431 if (isempty(rvalue)) {
2432 *archs = set_free(*archs);
2433 return 0;
2434 }
2435
2436 r = set_ensure_allocated(archs, NULL);
2437 if (r < 0)
2438 return log_oom();
2439
2440 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2441 _cleanup_free_ char *t = NULL;
2442 uint32_t a;
2443
2444 t = strndup(word, l);
2445 if (!t)
2446 return log_oom();
2447
2448 r = seccomp_arch_from_string(t, &a);
2449 if (r < 0) {
2450 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
2451 continue;
2452 }
2453
2454 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2455 if (r == 0)
2456 continue;
2457 if (r < 0)
2458 return log_oom();
2459 }
2460 if (!isempty(state))
2461 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
2462
2463 return 0;
2464 }
2465
2466 int config_parse_syscall_errno(
2467 const char *unit,
2468 const char *filename,
2469 unsigned line,
2470 const char *section,
2471 unsigned section_line,
2472 const char *lvalue,
2473 int ltype,
2474 const char *rvalue,
2475 void *data,
2476 void *userdata) {
2477
2478 ExecContext *c = data;
2479 int e;
2480
2481 assert(filename);
2482 assert(lvalue);
2483 assert(rvalue);
2484
2485 if (isempty(rvalue)) {
2486 /* Empty assignment resets to KILL */
2487 c->syscall_errno = 0;
2488 return 0;
2489 }
2490
2491 e = errno_from_name(rvalue);
2492 if (e < 0) {
2493 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
2494 return 0;
2495 }
2496
2497 c->syscall_errno = e;
2498 return 0;
2499 }
2500
2501 int config_parse_address_families(
2502 const char *unit,
2503 const char *filename,
2504 unsigned line,
2505 const char *section,
2506 unsigned section_line,
2507 const char *lvalue,
2508 int ltype,
2509 const char *rvalue,
2510 void *data,
2511 void *userdata) {
2512
2513 ExecContext *c = data;
2514 bool invert = false;
2515 const char *word, *state;
2516 size_t l;
2517 int r;
2518
2519 assert(filename);
2520 assert(lvalue);
2521 assert(rvalue);
2522
2523 if (isempty(rvalue)) {
2524 /* Empty assignment resets the list */
2525 c->address_families = set_free(c->address_families);
2526 c->address_families_whitelist = false;
2527 return 0;
2528 }
2529
2530 if (rvalue[0] == '~') {
2531 invert = true;
2532 rvalue++;
2533 }
2534
2535 if (!c->address_families) {
2536 c->address_families = set_new(NULL);
2537 if (!c->address_families)
2538 return log_oom();
2539
2540 c->address_families_whitelist = !invert;
2541 }
2542
2543 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2544 _cleanup_free_ char *t = NULL;
2545 int af;
2546
2547 t = strndup(word, l);
2548 if (!t)
2549 return log_oom();
2550
2551 af = af_from_name(t);
2552 if (af <= 0) {
2553 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t);
2554 continue;
2555 }
2556
2557 /* If we previously wanted to forbid an address family and now
2558 * we want to allow it, then remove it from the list
2559 */
2560 if (!invert == c->address_families_whitelist) {
2561 r = set_put(c->address_families, INT_TO_PTR(af));
2562 if (r == 0)
2563 continue;
2564 if (r < 0)
2565 return log_oom();
2566 } else
2567 set_remove(c->address_families, INT_TO_PTR(af));
2568 }
2569 if (!isempty(state))
2570 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
2571
2572 return 0;
2573 }
2574 #endif
2575
2576 int config_parse_unit_slice(
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 _cleanup_free_ char *k = NULL;
2589 Unit *u = userdata, *slice = NULL;
2590 int r;
2591
2592 assert(filename);
2593 assert(lvalue);
2594 assert(rvalue);
2595 assert(u);
2596
2597 r = unit_name_printf(u, rvalue, &k);
2598 if (r < 0) {
2599 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2600 return 0;
2601 }
2602
2603 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2604 if (r < 0) {
2605 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
2606 return 0;
2607 }
2608
2609 r = unit_set_slice(u, slice);
2610 if (r < 0) {
2611 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
2612 return 0;
2613 }
2614
2615 return 0;
2616 }
2617
2618 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2619
2620 int config_parse_cpu_shares(
2621 const char *unit,
2622 const char *filename,
2623 unsigned line,
2624 const char *section,
2625 unsigned section_line,
2626 const char *lvalue,
2627 int ltype,
2628 const char *rvalue,
2629 void *data,
2630 void *userdata) {
2631
2632 uint64_t *shares = data;
2633 int r;
2634
2635 assert(filename);
2636 assert(lvalue);
2637 assert(rvalue);
2638
2639 r = cg_cpu_shares_parse(rvalue, shares);
2640 if (r < 0) {
2641 log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
2642 return 0;
2643 }
2644
2645 return 0;
2646 }
2647
2648 int config_parse_cpu_quota(
2649 const char *unit,
2650 const char *filename,
2651 unsigned line,
2652 const char *section,
2653 unsigned section_line,
2654 const char *lvalue,
2655 int ltype,
2656 const char *rvalue,
2657 void *data,
2658 void *userdata) {
2659
2660 CGroupContext *c = data;
2661 double percent;
2662
2663 assert(filename);
2664 assert(lvalue);
2665 assert(rvalue);
2666
2667 if (isempty(rvalue)) {
2668 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2669 return 0;
2670 }
2671
2672 if (!endswith(rvalue, "%")) {
2673 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2674 return 0;
2675 }
2676
2677 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2678 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue);
2679 return 0;
2680 }
2681
2682 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2683
2684 return 0;
2685 }
2686
2687 int config_parse_memory_limit(
2688 const char *unit,
2689 const char *filename,
2690 unsigned line,
2691 const char *section,
2692 unsigned section_line,
2693 const char *lvalue,
2694 int ltype,
2695 const char *rvalue,
2696 void *data,
2697 void *userdata) {
2698
2699 CGroupContext *c = data;
2700 uint64_t bytes;
2701 int r;
2702
2703 if (isempty(rvalue) || streq(rvalue, "infinity")) {
2704 c->memory_limit = (uint64_t) -1;
2705 return 0;
2706 }
2707
2708 r = parse_size(rvalue, 1024, &bytes);
2709 if (r < 0 || bytes < 1) {
2710 log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
2711 return 0;
2712 }
2713
2714 c->memory_limit = bytes;
2715 return 0;
2716 }
2717
2718 int config_parse_tasks_max(
2719 const char *unit,
2720 const char *filename,
2721 unsigned line,
2722 const char *section,
2723 unsigned section_line,
2724 const char *lvalue,
2725 int ltype,
2726 const char *rvalue,
2727 void *data,
2728 void *userdata) {
2729
2730 CGroupContext *c = data;
2731 uint64_t u;
2732 int r;
2733
2734 if (isempty(rvalue) || streq(rvalue, "infinity")) {
2735 c->tasks_max = (uint64_t) -1;
2736 return 0;
2737 }
2738
2739 r = safe_atou64(rvalue, &u);
2740 if (r < 0 || u < 1) {
2741 log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
2742 return 0;
2743 }
2744
2745 c->tasks_max = u;
2746 return 0;
2747 }
2748
2749 int config_parse_device_allow(
2750 const char *unit,
2751 const char *filename,
2752 unsigned line,
2753 const char *section,
2754 unsigned section_line,
2755 const char *lvalue,
2756 int ltype,
2757 const char *rvalue,
2758 void *data,
2759 void *userdata) {
2760
2761 _cleanup_free_ char *path = NULL;
2762 CGroupContext *c = data;
2763 CGroupDeviceAllow *a;
2764 const char *m;
2765 size_t n;
2766
2767 if (isempty(rvalue)) {
2768 while (c->device_allow)
2769 cgroup_context_free_device_allow(c, c->device_allow);
2770
2771 return 0;
2772 }
2773
2774 n = strcspn(rvalue, WHITESPACE);
2775 path = strndup(rvalue, n);
2776 if (!path)
2777 return log_oom();
2778
2779 if (!startswith(path, "/dev/") &&
2780 !startswith(path, "block-") &&
2781 !startswith(path, "char-")) {
2782 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
2783 return 0;
2784 }
2785
2786 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2787 if (isempty(m))
2788 m = "rwm";
2789
2790 if (!in_charset(m, "rwm")) {
2791 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
2792 return 0;
2793 }
2794
2795 a = new0(CGroupDeviceAllow, 1);
2796 if (!a)
2797 return log_oom();
2798
2799 a->path = path;
2800 path = NULL;
2801 a->r = !!strchr(m, 'r');
2802 a->w = !!strchr(m, 'w');
2803 a->m = !!strchr(m, 'm');
2804
2805 LIST_PREPEND(device_allow, c->device_allow, a);
2806 return 0;
2807 }
2808
2809 int config_parse_blockio_weight(
2810 const char *unit,
2811 const char *filename,
2812 unsigned line,
2813 const char *section,
2814 unsigned section_line,
2815 const char *lvalue,
2816 int ltype,
2817 const char *rvalue,
2818 void *data,
2819 void *userdata) {
2820
2821 uint64_t *weight = data;
2822 int r;
2823
2824 assert(filename);
2825 assert(lvalue);
2826 assert(rvalue);
2827
2828 r = cg_blkio_weight_parse(rvalue, weight);
2829 if (r < 0) {
2830 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2831 return 0;
2832 }
2833
2834 return 0;
2835 }
2836
2837 int config_parse_blockio_device_weight(
2838 const char *unit,
2839 const char *filename,
2840 unsigned line,
2841 const char *section,
2842 unsigned section_line,
2843 const char *lvalue,
2844 int ltype,
2845 const char *rvalue,
2846 void *data,
2847 void *userdata) {
2848
2849 _cleanup_free_ char *path = NULL;
2850 CGroupBlockIODeviceWeight *w;
2851 CGroupContext *c = data;
2852 const char *weight;
2853 uint64_t u;
2854 size_t n;
2855 int r;
2856
2857 assert(filename);
2858 assert(lvalue);
2859 assert(rvalue);
2860
2861 if (isempty(rvalue)) {
2862 while (c->blockio_device_weights)
2863 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2864
2865 return 0;
2866 }
2867
2868 n = strcspn(rvalue, WHITESPACE);
2869 weight = rvalue + n;
2870 weight += strspn(weight, WHITESPACE);
2871
2872 if (isempty(weight)) {
2873 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
2874 return 0;
2875 }
2876
2877 path = strndup(rvalue, n);
2878 if (!path)
2879 return log_oom();
2880
2881 if (!path_startswith(path, "/dev")) {
2882 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
2883 return 0;
2884 }
2885
2886 r = cg_blkio_weight_parse(weight, &u);
2887 if (r < 0) {
2888 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
2889 return 0;
2890 }
2891
2892 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
2893
2894 w = new0(CGroupBlockIODeviceWeight, 1);
2895 if (!w)
2896 return log_oom();
2897
2898 w->path = path;
2899 path = NULL;
2900
2901 w->weight = u;
2902
2903 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2904 return 0;
2905 }
2906
2907 int config_parse_blockio_bandwidth(
2908 const char *unit,
2909 const char *filename,
2910 unsigned line,
2911 const char *section,
2912 unsigned section_line,
2913 const char *lvalue,
2914 int ltype,
2915 const char *rvalue,
2916 void *data,
2917 void *userdata) {
2918
2919 _cleanup_free_ char *path = NULL;
2920 CGroupBlockIODeviceBandwidth *b;
2921 CGroupContext *c = data;
2922 const char *bandwidth;
2923 uint64_t bytes;
2924 bool read;
2925 size_t n;
2926 int r;
2927
2928 assert(filename);
2929 assert(lvalue);
2930 assert(rvalue);
2931
2932 read = streq("BlockIOReadBandwidth", lvalue);
2933
2934 if (isempty(rvalue)) {
2935 CGroupBlockIODeviceBandwidth *next;
2936
2937 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2938 if (b->read == read)
2939 cgroup_context_free_blockio_device_bandwidth(c, b);
2940
2941 return 0;
2942 }
2943
2944 n = strcspn(rvalue, WHITESPACE);
2945 bandwidth = rvalue + n;
2946 bandwidth += strspn(bandwidth, WHITESPACE);
2947
2948 if (!*bandwidth) {
2949 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
2950 return 0;
2951 }
2952
2953 path = strndup(rvalue, n);
2954 if (!path)
2955 return log_oom();
2956
2957 if (!path_startswith(path, "/dev")) {
2958 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
2959 return 0;
2960 }
2961
2962 r = parse_size(bandwidth, 1000, &bytes);
2963 if (r < 0 || bytes <= 0) {
2964 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2965 return 0;
2966 }
2967
2968 b = new0(CGroupBlockIODeviceBandwidth, 1);
2969 if (!b)
2970 return log_oom();
2971
2972 b->path = path;
2973 path = NULL;
2974 b->bandwidth = bytes;
2975 b->read = read;
2976
2977 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2978
2979 return 0;
2980 }
2981
2982 int config_parse_netclass(
2983 const char *unit,
2984 const char *filename,
2985 unsigned line,
2986 const char *section,
2987 unsigned section_line,
2988 const char *lvalue,
2989 int ltype,
2990 const char *rvalue,
2991 void *data,
2992 void *userdata) {
2993
2994 CGroupContext *c = data;
2995 unsigned v;
2996 int r;
2997
2998 assert(filename);
2999 assert(lvalue);
3000 assert(rvalue);
3001
3002 if (streq(rvalue, "auto")) {
3003 c->netclass_type = CGROUP_NETCLASS_TYPE_AUTO;
3004 return 0;
3005 }
3006
3007 r = safe_atou32(rvalue, &v);
3008 if (r < 0) {
3009 log_syntax(unit, LOG_ERR, filename, line, r, "Netclass '%s' invalid. Ignoring.", rvalue);
3010 return 0;
3011 }
3012
3013 if (v > CGROUP_NETCLASS_FIXED_MAX)
3014 log_syntax(unit, LOG_ERR, filename, line, 0,
3015 "Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX);
3016
3017 c->netclass_id = v;
3018 c->netclass_type = CGROUP_NETCLASS_TYPE_FIXED;
3019
3020 return 0;
3021 }
3022
3023 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3024
3025 int config_parse_job_mode_isolate(
3026 const char *unit,
3027 const char *filename,
3028 unsigned line,
3029 const char *section,
3030 unsigned section_line,
3031 const char *lvalue,
3032 int ltype,
3033 const char *rvalue,
3034 void *data,
3035 void *userdata) {
3036
3037 JobMode *m = data;
3038 int r;
3039
3040 assert(filename);
3041 assert(lvalue);
3042 assert(rvalue);
3043
3044 r = parse_boolean(rvalue);
3045 if (r < 0) {
3046 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
3047 return 0;
3048 }
3049
3050 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3051 return 0;
3052 }
3053
3054 int config_parse_runtime_directory(
3055 const char *unit,
3056 const char *filename,
3057 unsigned line,
3058 const char *section,
3059 unsigned section_line,
3060 const char *lvalue,
3061 int ltype,
3062 const char *rvalue,
3063 void *data,
3064 void *userdata) {
3065
3066 char***rt = data;
3067 Unit *u = userdata;
3068 const char *word, *state;
3069 size_t l;
3070 int r;
3071
3072 assert(filename);
3073 assert(lvalue);
3074 assert(rvalue);
3075 assert(data);
3076
3077 if (isempty(rvalue)) {
3078 /* Empty assignment resets the list */
3079 *rt = strv_free(*rt);
3080 return 0;
3081 }
3082
3083 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3084 _cleanup_free_ char *t = NULL, *n = NULL;
3085
3086 t = strndup(word, l);
3087 if (!t)
3088 return log_oom();
3089
3090 r = unit_name_printf(u, t, &n);
3091 if (r < 0) {
3092 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
3093 continue;
3094 }
3095
3096 if (!filename_is_valid(n)) {
3097 log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3098 continue;
3099 }
3100
3101 r = strv_push(rt, n);
3102 if (r < 0)
3103 return log_oom();
3104
3105 n = NULL;
3106 }
3107 if (!isempty(state))
3108 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3109
3110 return 0;
3111 }
3112
3113 int config_parse_set_status(
3114 const char *unit,
3115 const char *filename,
3116 unsigned line,
3117 const char *section,
3118 unsigned section_line,
3119 const char *lvalue,
3120 int ltype,
3121 const char *rvalue,
3122 void *data,
3123 void *userdata) {
3124
3125 size_t l;
3126 const char *word, *state;
3127 int r;
3128 ExitStatusSet *status_set = data;
3129
3130 assert(filename);
3131 assert(lvalue);
3132 assert(rvalue);
3133 assert(data);
3134
3135 /* Empty assignment resets the list */
3136 if (isempty(rvalue)) {
3137 exit_status_set_free(status_set);
3138 return 0;
3139 }
3140
3141 FOREACH_WORD(word, l, rvalue, state) {
3142 _cleanup_free_ char *temp;
3143 int val;
3144 Set **set;
3145
3146 temp = strndup(word, l);
3147 if (!temp)
3148 return log_oom();
3149
3150 r = safe_atoi(temp, &val);
3151 if (r < 0) {
3152 val = signal_from_string_try_harder(temp);
3153
3154 if (val <= 0) {
3155 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
3156 continue;
3157 }
3158 set = &status_set->signal;
3159 } else {
3160 if (val < 0 || val > 255) {
3161 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
3162 continue;
3163 }
3164 set = &status_set->status;
3165 }
3166
3167 r = set_ensure_allocated(set, NULL);
3168 if (r < 0)
3169 return log_oom();
3170
3171 r = set_put(*set, INT_TO_PTR(val));
3172 if (r < 0) {
3173 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
3174 return r;
3175 }
3176 }
3177 if (!isempty(state))
3178 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3179
3180 return 0;
3181 }
3182
3183 int config_parse_namespace_path_strv(
3184 const char *unit,
3185 const char *filename,
3186 unsigned line,
3187 const char *section,
3188 unsigned section_line,
3189 const char *lvalue,
3190 int ltype,
3191 const char *rvalue,
3192 void *data,
3193 void *userdata) {
3194
3195 char*** sv = data;
3196 const char *prev;
3197 const char *cur;
3198 int r;
3199
3200 assert(filename);
3201 assert(lvalue);
3202 assert(rvalue);
3203 assert(data);
3204
3205 if (isempty(rvalue)) {
3206 /* Empty assignment resets the list */
3207 *sv = strv_free(*sv);
3208 return 0;
3209 }
3210
3211 prev = cur = rvalue;
3212 for (;;) {
3213 _cleanup_free_ char *word = NULL;
3214 int offset;
3215
3216 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
3217 if (r < 0) {
3218 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring: %s", prev);
3219 return 0;
3220 }
3221 if (r == 0)
3222 break;
3223
3224 if (!utf8_is_valid(word)) {
3225 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3226 prev = cur;
3227 continue;
3228 }
3229
3230 offset = word[0] == '-';
3231 if (!path_is_absolute(word + offset)) {
3232 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
3233 prev = cur;
3234 continue;
3235 }
3236
3237 path_kill_slashes(word + offset);
3238
3239 r = strv_push(sv, word);
3240 if (r < 0)
3241 return log_oom();
3242
3243 prev = cur;
3244 word = NULL;
3245 }
3246
3247 return 0;
3248 }
3249
3250 int config_parse_no_new_privileges(
3251 const char* unit,
3252 const char *filename,
3253 unsigned line,
3254 const char *section,
3255 unsigned section_line,
3256 const char *lvalue,
3257 int ltype,
3258 const char *rvalue,
3259 void *data,
3260 void *userdata) {
3261
3262 ExecContext *c = data;
3263 int k;
3264
3265 assert(filename);
3266 assert(lvalue);
3267 assert(rvalue);
3268 assert(data);
3269
3270 k = parse_boolean(rvalue);
3271 if (k < 0) {
3272 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
3273 return 0;
3274 }
3275
3276 c->no_new_privileges = !!k;
3277 c->no_new_privileges_set = true;
3278
3279 return 0;
3280 }
3281
3282 int config_parse_protect_home(
3283 const char* unit,
3284 const char *filename,
3285 unsigned line,
3286 const char *section,
3287 unsigned section_line,
3288 const char *lvalue,
3289 int ltype,
3290 const char *rvalue,
3291 void *data,
3292 void *userdata) {
3293
3294 ExecContext *c = data;
3295 int k;
3296
3297 assert(filename);
3298 assert(lvalue);
3299 assert(rvalue);
3300 assert(data);
3301
3302 /* Our enum shall be a superset of booleans, hence first try
3303 * to parse as as boolean, and then as enum */
3304
3305 k = parse_boolean(rvalue);
3306 if (k > 0)
3307 c->protect_home = PROTECT_HOME_YES;
3308 else if (k == 0)
3309 c->protect_home = PROTECT_HOME_NO;
3310 else {
3311 ProtectHome h;
3312
3313 h = protect_home_from_string(rvalue);
3314 if (h < 0){
3315 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
3316 return 0;
3317 }
3318
3319 c->protect_home = h;
3320 }
3321
3322 return 0;
3323 }
3324
3325 int config_parse_protect_system(
3326 const char* unit,
3327 const char *filename,
3328 unsigned line,
3329 const char *section,
3330 unsigned section_line,
3331 const char *lvalue,
3332 int ltype,
3333 const char *rvalue,
3334 void *data,
3335 void *userdata) {
3336
3337 ExecContext *c = data;
3338 int k;
3339
3340 assert(filename);
3341 assert(lvalue);
3342 assert(rvalue);
3343 assert(data);
3344
3345 /* Our enum shall be a superset of booleans, hence first try
3346 * to parse as as boolean, and then as enum */
3347
3348 k = parse_boolean(rvalue);
3349 if (k > 0)
3350 c->protect_system = PROTECT_SYSTEM_YES;
3351 else if (k == 0)
3352 c->protect_system = PROTECT_SYSTEM_NO;
3353 else {
3354 ProtectSystem s;
3355
3356 s = protect_system_from_string(rvalue);
3357 if (s < 0){
3358 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
3359 return 0;
3360 }
3361
3362 c->protect_system = s;
3363 }
3364
3365 return 0;
3366 }
3367
3368 #define FOLLOW_MAX 8
3369
3370 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3371 unsigned c = 0;
3372 int fd, r;
3373 FILE *f;
3374 char *id = NULL;
3375
3376 assert(filename);
3377 assert(*filename);
3378 assert(_f);
3379 assert(names);
3380
3381 /* This will update the filename pointer if the loaded file is
3382 * reached by a symlink. The old string will be freed. */
3383
3384 for (;;) {
3385 char *target, *name;
3386
3387 if (c++ >= FOLLOW_MAX)
3388 return -ELOOP;
3389
3390 path_kill_slashes(*filename);
3391
3392 /* Add the file name we are currently looking at to
3393 * the names of this unit, but only if it is a valid
3394 * unit name. */
3395 name = basename(*filename);
3396
3397 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
3398
3399 id = set_get(names, name);
3400 if (!id) {
3401 id = strdup(name);
3402 if (!id)
3403 return -ENOMEM;
3404
3405 r = set_consume(names, id);
3406 if (r < 0)
3407 return r;
3408 }
3409 }
3410
3411 /* Try to open the file name, but don't if its a symlink */
3412 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3413 if (fd >= 0)
3414 break;
3415
3416 if (errno != ELOOP)
3417 return -errno;
3418
3419 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3420 r = readlink_and_make_absolute(*filename, &target);
3421 if (r < 0)
3422 return r;
3423
3424 free(*filename);
3425 *filename = target;
3426 }
3427
3428 f = fdopen(fd, "re");
3429 if (!f) {
3430 safe_close(fd);
3431 return -errno;
3432 }
3433
3434 *_f = f;
3435 *_final = id;
3436 return 0;
3437 }
3438
3439 static int merge_by_names(Unit **u, Set *names, const char *id) {
3440 char *k;
3441 int r;
3442
3443 assert(u);
3444 assert(*u);
3445 assert(names);
3446
3447 /* Let's try to add in all symlink names we found */
3448 while ((k = set_steal_first(names))) {
3449
3450 /* First try to merge in the other name into our
3451 * unit */
3452 r = unit_merge_by_name(*u, k);
3453 if (r < 0) {
3454 Unit *other;
3455
3456 /* Hmm, we couldn't merge the other unit into
3457 * ours? Then let's try it the other way
3458 * round */
3459
3460 other = manager_get_unit((*u)->manager, k);
3461 free(k);
3462
3463 if (other) {
3464 r = unit_merge(other, *u);
3465 if (r >= 0) {
3466 *u = other;
3467 return merge_by_names(u, names, NULL);
3468 }
3469 }
3470
3471 return r;
3472 }
3473
3474 if (id == k)
3475 unit_choose_id(*u, id);
3476
3477 free(k);
3478 }
3479
3480 return 0;
3481 }
3482
3483 static int load_from_path(Unit *u, const char *path) {
3484 int r;
3485 _cleanup_set_free_free_ Set *symlink_names = NULL;
3486 _cleanup_fclose_ FILE *f = NULL;
3487 _cleanup_free_ char *filename = NULL;
3488 char *id = NULL;
3489 Unit *merged;
3490 struct stat st;
3491
3492 assert(u);
3493 assert(path);
3494
3495 symlink_names = set_new(&string_hash_ops);
3496 if (!symlink_names)
3497 return -ENOMEM;
3498
3499 if (path_is_absolute(path)) {
3500
3501 filename = strdup(path);
3502 if (!filename)
3503 return -ENOMEM;
3504
3505 r = open_follow(&filename, &f, symlink_names, &id);
3506 if (r < 0) {
3507 filename = mfree(filename);
3508 if (r != -ENOENT)
3509 return r;
3510 }
3511
3512 } else {
3513 char **p;
3514
3515 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3516
3517 /* Instead of opening the path right away, we manually
3518 * follow all symlinks and add their name to our unit
3519 * name set while doing so */
3520 filename = path_make_absolute(path, *p);
3521 if (!filename)
3522 return -ENOMEM;
3523
3524 if (u->manager->unit_path_cache &&
3525 !set_get(u->manager->unit_path_cache, filename))
3526 r = -ENOENT;
3527 else
3528 r = open_follow(&filename, &f, symlink_names, &id);
3529
3530 if (r < 0) {
3531 filename = mfree(filename);
3532 if (r != -ENOENT)
3533 return r;
3534
3535 /* Empty the symlink names for the next run */
3536 set_clear_free(symlink_names);
3537 continue;
3538 }
3539
3540 break;
3541 }
3542 }
3543
3544 if (!filename)
3545 /* Hmm, no suitable file found? */
3546 return 0;
3547
3548 merged = u;
3549 r = merge_by_names(&merged, symlink_names, id);
3550 if (r < 0)
3551 return r;
3552
3553 if (merged != u) {
3554 u->load_state = UNIT_MERGED;
3555 return 0;
3556 }
3557
3558 if (fstat(fileno(f), &st) < 0)
3559 return -errno;
3560
3561 if (null_or_empty(&st))
3562 u->load_state = UNIT_MASKED;
3563 else {
3564 u->load_state = UNIT_LOADED;
3565
3566 /* Now, parse the file contents */
3567 r = config_parse(u->id, filename, f,
3568 UNIT_VTABLE(u)->sections,
3569 config_item_perf_lookup, load_fragment_gperf_lookup,
3570 false, true, false, u);
3571 if (r < 0)
3572 return r;
3573 }
3574
3575 free(u->fragment_path);
3576 u->fragment_path = filename;
3577 filename = NULL;
3578
3579 u->fragment_mtime = timespec_load(&st.st_mtim);
3580
3581 if (u->source_path) {
3582 if (stat(u->source_path, &st) >= 0)
3583 u->source_mtime = timespec_load(&st.st_mtim);
3584 else
3585 u->source_mtime = 0;
3586 }
3587
3588 return 0;
3589 }
3590
3591 int unit_load_fragment(Unit *u) {
3592 int r;
3593 Iterator i;
3594 const char *t;
3595
3596 assert(u);
3597 assert(u->load_state == UNIT_STUB);
3598 assert(u->id);
3599
3600 if (u->transient) {
3601 u->load_state = UNIT_LOADED;
3602 return 0;
3603 }
3604
3605 /* First, try to find the unit under its id. We always look
3606 * for unit files in the default directories, to make it easy
3607 * to override things by placing things in /etc/systemd/system */
3608 r = load_from_path(u, u->id);
3609 if (r < 0)
3610 return r;
3611
3612 /* Try to find an alias we can load this with */
3613 if (u->load_state == UNIT_STUB) {
3614 SET_FOREACH(t, u->names, i) {
3615
3616 if (t == u->id)
3617 continue;
3618
3619 r = load_from_path(u, t);
3620 if (r < 0)
3621 return r;
3622
3623 if (u->load_state != UNIT_STUB)
3624 break;
3625 }
3626 }
3627
3628 /* And now, try looking for it under the suggested (originally linked) path */
3629 if (u->load_state == UNIT_STUB && u->fragment_path) {
3630
3631 r = load_from_path(u, u->fragment_path);
3632 if (r < 0)
3633 return r;
3634
3635 if (u->load_state == UNIT_STUB)
3636 /* Hmm, this didn't work? Then let's get rid
3637 * of the fragment path stored for us, so that
3638 * we don't point to an invalid location. */
3639 u->fragment_path = mfree(u->fragment_path);
3640 }
3641
3642 /* Look for a template */
3643 if (u->load_state == UNIT_STUB && u->instance) {
3644 _cleanup_free_ char *k = NULL;
3645
3646 r = unit_name_template(u->id, &k);
3647 if (r < 0)
3648 return r;
3649
3650 r = load_from_path(u, k);
3651 if (r < 0)
3652 return r;
3653
3654 if (u->load_state == UNIT_STUB) {
3655 SET_FOREACH(t, u->names, i) {
3656 _cleanup_free_ char *z = NULL;
3657
3658 if (t == u->id)
3659 continue;
3660
3661 r = unit_name_template(t, &z);
3662 if (r < 0)
3663 return r;
3664
3665 r = load_from_path(u, z);
3666 if (r < 0)
3667 return r;
3668
3669 if (u->load_state != UNIT_STUB)
3670 break;
3671 }
3672 }
3673 }
3674
3675 return 0;
3676 }
3677
3678 void unit_dump_config_items(FILE *f) {
3679 static const struct {
3680 const ConfigParserCallback callback;
3681 const char *rvalue;
3682 } table[] = {
3683 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3684 { config_parse_warn_compat, "NOTSUPPORTED" },
3685 #endif
3686 { config_parse_int, "INTEGER" },
3687 { config_parse_unsigned, "UNSIGNED" },
3688 { config_parse_iec_size, "SIZE" },
3689 { config_parse_iec_uint64, "SIZE" },
3690 { config_parse_si_size, "SIZE" },
3691 { config_parse_bool, "BOOLEAN" },
3692 { config_parse_string, "STRING" },
3693 { config_parse_path, "PATH" },
3694 { config_parse_unit_path_printf, "PATH" },
3695 { config_parse_strv, "STRING [...]" },
3696 { config_parse_exec_nice, "NICE" },
3697 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3698 { config_parse_exec_io_class, "IOCLASS" },
3699 { config_parse_exec_io_priority, "IOPRIORITY" },
3700 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3701 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3702 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3703 { config_parse_mode, "MODE" },
3704 { config_parse_unit_env_file, "FILE" },
3705 { config_parse_output, "OUTPUT" },
3706 { config_parse_input, "INPUT" },
3707 { config_parse_log_facility, "FACILITY" },
3708 { config_parse_log_level, "LEVEL" },
3709 { config_parse_exec_capabilities, "CAPABILITIES" },
3710 { config_parse_exec_secure_bits, "SECUREBITS" },
3711 { config_parse_bounding_set, "BOUNDINGSET" },
3712 { config_parse_limit, "LIMIT" },
3713 { config_parse_unit_deps, "UNIT [...]" },
3714 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3715 { config_parse_service_type, "SERVICETYPE" },
3716 { config_parse_service_restart, "SERVICERESTART" },
3717 #ifdef HAVE_SYSV_COMPAT
3718 { config_parse_sysv_priority, "SYSVPRIORITY" },
3719 #endif
3720 { config_parse_kill_mode, "KILLMODE" },
3721 { config_parse_signal, "SIGNAL" },
3722 { config_parse_socket_listen, "SOCKET [...]" },
3723 { config_parse_socket_bind, "SOCKETBIND" },
3724 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3725 { config_parse_sec, "SECONDS" },
3726 { config_parse_nsec, "NANOSECONDS" },
3727 { config_parse_namespace_path_strv, "PATH [...]" },
3728 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3729 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3730 { config_parse_unit_string_printf, "STRING" },
3731 { config_parse_trigger_unit, "UNIT" },
3732 { config_parse_timer, "TIMER" },
3733 { config_parse_path_spec, "PATH" },
3734 { config_parse_notify_access, "ACCESS" },
3735 { config_parse_ip_tos, "TOS" },
3736 { config_parse_unit_condition_path, "CONDITION" },
3737 { config_parse_unit_condition_string, "CONDITION" },
3738 { config_parse_unit_condition_null, "CONDITION" },
3739 { config_parse_unit_slice, "SLICE" },
3740 { config_parse_documentation, "URL" },
3741 { config_parse_service_timeout, "SECONDS" },
3742 { config_parse_failure_action, "ACTION" },
3743 { config_parse_set_status, "STATUS" },
3744 { config_parse_service_sockets, "SOCKETS" },
3745 { config_parse_environ, "ENVIRON" },
3746 #ifdef HAVE_SECCOMP
3747 { config_parse_syscall_filter, "SYSCALLS" },
3748 { config_parse_syscall_archs, "ARCHS" },
3749 { config_parse_syscall_errno, "ERRNO" },
3750 { config_parse_address_families, "FAMILIES" },
3751 #endif
3752 { config_parse_cpu_shares, "SHARES" },
3753 { config_parse_memory_limit, "LIMIT" },
3754 { config_parse_device_allow, "DEVICE" },
3755 { config_parse_device_policy, "POLICY" },
3756 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3757 { config_parse_blockio_weight, "WEIGHT" },
3758 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3759 { config_parse_long, "LONG" },
3760 { config_parse_socket_service, "SERVICE" },
3761 #ifdef HAVE_SELINUX
3762 { config_parse_exec_selinux_context, "LABEL" },
3763 #endif
3764 { config_parse_job_mode, "MODE" },
3765 { config_parse_job_mode_isolate, "BOOLEAN" },
3766 { config_parse_personality, "PERSONALITY" },
3767 };
3768
3769 const char *prev = NULL;
3770 const char *i;
3771
3772 assert(f);
3773
3774 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3775 const char *rvalue = "OTHER", *lvalue;
3776 unsigned j;
3777 size_t prefix_len;
3778 const char *dot;
3779 const ConfigPerfItem *p;
3780
3781 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3782
3783 dot = strchr(i, '.');
3784 lvalue = dot ? dot + 1 : i;
3785 prefix_len = dot-i;
3786
3787 if (dot)
3788 if (!prev || !strneq(prev, i, prefix_len+1)) {
3789 if (prev)
3790 fputc('\n', f);
3791
3792 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3793 }
3794
3795 for (j = 0; j < ELEMENTSOF(table); j++)
3796 if (p->parse == table[j].callback) {
3797 rvalue = table[j].rvalue;
3798 break;
3799 }
3800
3801 fprintf(f, "%s=%s\n", lvalue, rvalue);
3802 prev = i;
3803 }
3804 }