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