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