]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
Merge pull request #1024 from poettering/sd-bus-explicit
[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;
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,
2616 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2617 if (!k) {
2618 k = strdup(rvalue);
2619 if (!k)
2620 return log_oom();
2621 }
2622
2623 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2624 if (r < 0) {
2625 log_syntax(unit, LOG_ERR, filename, line, -r,
2626 "Failed to load slice unit %s. Ignoring.", k);
2627 return 0;
2628 }
2629
2630 if (slice->type != UNIT_SLICE) {
2631 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2632 "Slice unit %s is not a slice. Ignoring.", k);
2633 return 0;
2634 }
2635
2636 unit_ref_set(&u->slice, slice);
2637 return 0;
2638 }
2639
2640 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2641
2642 int config_parse_cpu_shares(
2643 const char *unit,
2644 const char *filename,
2645 unsigned line,
2646 const char *section,
2647 unsigned section_line,
2648 const char *lvalue,
2649 int ltype,
2650 const char *rvalue,
2651 void *data,
2652 void *userdata) {
2653
2654 unsigned long *shares = data, lu;
2655 int r;
2656
2657 assert(filename);
2658 assert(lvalue);
2659 assert(rvalue);
2660
2661 if (isempty(rvalue)) {
2662 *shares = (unsigned long) -1;
2663 return 0;
2664 }
2665
2666 r = safe_atolu(rvalue, &lu);
2667 if (r < 0 || lu <= 0) {
2668 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2669 "CPU shares '%s' invalid. Ignoring.", rvalue);
2670 return 0;
2671 }
2672
2673 *shares = lu;
2674 return 0;
2675 }
2676
2677 int config_parse_cpu_quota(
2678 const char *unit,
2679 const char *filename,
2680 unsigned line,
2681 const char *section,
2682 unsigned section_line,
2683 const char *lvalue,
2684 int ltype,
2685 const char *rvalue,
2686 void *data,
2687 void *userdata) {
2688
2689 CGroupContext *c = data;
2690 double percent;
2691
2692 assert(filename);
2693 assert(lvalue);
2694 assert(rvalue);
2695
2696 if (isempty(rvalue)) {
2697 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2698 return 0;
2699 }
2700
2701 if (!endswith(rvalue, "%")) {
2702
2703 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2704 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2705 return 0;
2706 }
2707
2708 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2709 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710 "CPU quota '%s' invalid. Ignoring.", rvalue);
2711 return 0;
2712 }
2713
2714 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2715
2716 return 0;
2717 }
2718
2719 int config_parse_memory_limit(
2720 const char *unit,
2721 const char *filename,
2722 unsigned line,
2723 const char *section,
2724 unsigned section_line,
2725 const char *lvalue,
2726 int ltype,
2727 const char *rvalue,
2728 void *data,
2729 void *userdata) {
2730
2731 CGroupContext *c = data;
2732 off_t bytes;
2733 int r;
2734
2735 if (isempty(rvalue)) {
2736 c->memory_limit = (uint64_t) -1;
2737 return 0;
2738 }
2739
2740 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2741
2742 r = parse_size(rvalue, 1024, &bytes);
2743 if (r < 0) {
2744 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2745 "Memory limit '%s' invalid. Ignoring.", rvalue);
2746 return 0;
2747 }
2748
2749 c->memory_limit = (uint64_t) bytes;
2750 return 0;
2751 }
2752
2753 int config_parse_device_allow(
2754 const char *unit,
2755 const char *filename,
2756 unsigned line,
2757 const char *section,
2758 unsigned section_line,
2759 const char *lvalue,
2760 int ltype,
2761 const char *rvalue,
2762 void *data,
2763 void *userdata) {
2764
2765 _cleanup_free_ char *path = NULL;
2766 CGroupContext *c = data;
2767 CGroupDeviceAllow *a;
2768 const char *m;
2769 size_t n;
2770
2771 if (isempty(rvalue)) {
2772 while (c->device_allow)
2773 cgroup_context_free_device_allow(c, c->device_allow);
2774
2775 return 0;
2776 }
2777
2778 n = strcspn(rvalue, WHITESPACE);
2779 path = strndup(rvalue, n);
2780 if (!path)
2781 return log_oom();
2782
2783 if (!startswith(path, "/dev/") &&
2784 !startswith(path, "block-") &&
2785 !startswith(path, "char-")) {
2786 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2787 "Invalid device node path '%s'. Ignoring.", path);
2788 return 0;
2789 }
2790
2791 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2792 if (isempty(m))
2793 m = "rwm";
2794
2795 if (!in_charset(m, "rwm")) {
2796 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2797 "Invalid device rights '%s'. Ignoring.", m);
2798 return 0;
2799 }
2800
2801 a = new0(CGroupDeviceAllow, 1);
2802 if (!a)
2803 return log_oom();
2804
2805 a->path = path;
2806 path = NULL;
2807 a->r = !!strchr(m, 'r');
2808 a->w = !!strchr(m, 'w');
2809 a->m = !!strchr(m, 'm');
2810
2811 LIST_PREPEND(device_allow, c->device_allow, a);
2812 return 0;
2813 }
2814
2815 int config_parse_blockio_weight(
2816 const char *unit,
2817 const char *filename,
2818 unsigned line,
2819 const char *section,
2820 unsigned section_line,
2821 const char *lvalue,
2822 int ltype,
2823 const char *rvalue,
2824 void *data,
2825 void *userdata) {
2826
2827 unsigned long *weight = data, lu;
2828 int r;
2829
2830 assert(filename);
2831 assert(lvalue);
2832 assert(rvalue);
2833
2834 if (isempty(rvalue)) {
2835 *weight = (unsigned long) -1;
2836 return 0;
2837 }
2838
2839 r = safe_atolu(rvalue, &lu);
2840 if (r < 0 || lu < 10 || lu > 1000) {
2841 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2842 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2843 return 0;
2844 }
2845
2846 *weight = lu;
2847 return 0;
2848 }
2849
2850 int config_parse_blockio_device_weight(
2851 const char *unit,
2852 const char *filename,
2853 unsigned line,
2854 const char *section,
2855 unsigned section_line,
2856 const char *lvalue,
2857 int ltype,
2858 const char *rvalue,
2859 void *data,
2860 void *userdata) {
2861
2862 _cleanup_free_ char *path = NULL;
2863 CGroupBlockIODeviceWeight *w;
2864 CGroupContext *c = data;
2865 unsigned long lu;
2866 const char *weight;
2867 size_t n;
2868 int r;
2869
2870 assert(filename);
2871 assert(lvalue);
2872 assert(rvalue);
2873
2874 if (isempty(rvalue)) {
2875 while (c->blockio_device_weights)
2876 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2877
2878 return 0;
2879 }
2880
2881 n = strcspn(rvalue, WHITESPACE);
2882 weight = rvalue + n;
2883 if (!*weight) {
2884 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2885 "Expected block device and device weight. Ignoring.");
2886 return 0;
2887 }
2888
2889 path = strndup(rvalue, n);
2890 if (!path)
2891 return log_oom();
2892
2893 if (!path_startswith(path, "/dev")) {
2894 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2895 "Invalid device node path '%s'. Ignoring.", path);
2896 return 0;
2897 }
2898
2899 weight += strspn(weight, WHITESPACE);
2900 r = safe_atolu(weight, &lu);
2901 if (r < 0 || lu < 10 || lu > 1000) {
2902 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2903 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2904 return 0;
2905 }
2906
2907 w = new0(CGroupBlockIODeviceWeight, 1);
2908 if (!w)
2909 return log_oom();
2910
2911 w->path = path;
2912 path = NULL;
2913
2914 w->weight = lu;
2915
2916 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2917 return 0;
2918 }
2919
2920 int config_parse_blockio_bandwidth(
2921 const char *unit,
2922 const char *filename,
2923 unsigned line,
2924 const char *section,
2925 unsigned section_line,
2926 const char *lvalue,
2927 int ltype,
2928 const char *rvalue,
2929 void *data,
2930 void *userdata) {
2931
2932 _cleanup_free_ char *path = NULL;
2933 CGroupBlockIODeviceBandwidth *b;
2934 CGroupContext *c = data;
2935 const char *bandwidth;
2936 off_t bytes;
2937 bool read;
2938 size_t n;
2939 int r;
2940
2941 assert(filename);
2942 assert(lvalue);
2943 assert(rvalue);
2944
2945 read = streq("BlockIOReadBandwidth", lvalue);
2946
2947 if (isempty(rvalue)) {
2948 CGroupBlockIODeviceBandwidth *next;
2949
2950 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2951 if (b->read == read)
2952 cgroup_context_free_blockio_device_bandwidth(c, b);
2953
2954 return 0;
2955 }
2956
2957 n = strcspn(rvalue, WHITESPACE);
2958 bandwidth = rvalue + n;
2959 bandwidth += strspn(bandwidth, WHITESPACE);
2960
2961 if (!*bandwidth) {
2962 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2963 "Expected space separated pair of device node and bandwidth. Ignoring.");
2964 return 0;
2965 }
2966
2967 path = strndup(rvalue, n);
2968 if (!path)
2969 return log_oom();
2970
2971 if (!path_startswith(path, "/dev")) {
2972 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2973 "Invalid device node path '%s'. Ignoring.", path);
2974 return 0;
2975 }
2976
2977 r = parse_size(bandwidth, 1000, &bytes);
2978 if (r < 0 || bytes <= 0) {
2979 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2980 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2981 return 0;
2982 }
2983
2984 b = new0(CGroupBlockIODeviceBandwidth, 1);
2985 if (!b)
2986 return log_oom();
2987
2988 b->path = path;
2989 path = NULL;
2990 b->bandwidth = (uint64_t) bytes;
2991 b->read = read;
2992
2993 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2994
2995 return 0;
2996 }
2997
2998 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2999
3000 int config_parse_job_mode_isolate(
3001 const char *unit,
3002 const char *filename,
3003 unsigned line,
3004 const char *section,
3005 unsigned section_line,
3006 const char *lvalue,
3007 int ltype,
3008 const char *rvalue,
3009 void *data,
3010 void *userdata) {
3011
3012 JobMode *m = data;
3013 int r;
3014
3015 assert(filename);
3016 assert(lvalue);
3017 assert(rvalue);
3018
3019 r = parse_boolean(rvalue);
3020 if (r < 0) {
3021 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3022 "Failed to parse boolean, ignoring: %s", rvalue);
3023 return 0;
3024 }
3025
3026 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3027 return 0;
3028 }
3029
3030 int config_parse_personality(
3031 const char *unit,
3032 const char *filename,
3033 unsigned line,
3034 const char *section,
3035 unsigned section_line,
3036 const char *lvalue,
3037 int ltype,
3038 const char *rvalue,
3039 void *data,
3040 void *userdata) {
3041
3042 unsigned long *personality = data, p;
3043
3044 assert(filename);
3045 assert(lvalue);
3046 assert(rvalue);
3047 assert(personality);
3048
3049 p = personality_from_string(rvalue);
3050 if (p == PERSONALITY_INVALID) {
3051 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3052 "Failed to parse personality, ignoring: %s", rvalue);
3053 return 0;
3054 }
3055
3056 *personality = p;
3057 return 0;
3058 }
3059
3060 int config_parse_runtime_directory(
3061 const char *unit,
3062 const char *filename,
3063 unsigned line,
3064 const char *section,
3065 unsigned section_line,
3066 const char *lvalue,
3067 int ltype,
3068 const char *rvalue,
3069 void *data,
3070 void *userdata) {
3071
3072 char***rt = data;
3073 const char *word, *state;
3074 size_t l;
3075 int r;
3076
3077 assert(filename);
3078 assert(lvalue);
3079 assert(rvalue);
3080 assert(data);
3081
3082 if (isempty(rvalue)) {
3083 /* Empty assignment resets the list */
3084 strv_free(*rt);
3085 *rt = NULL;
3086 return 0;
3087 }
3088
3089 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3090 _cleanup_free_ char *n;
3091
3092 n = strndup(word, l);
3093 if (!n)
3094 return log_oom();
3095
3096 if (!filename_is_valid(n)) {
3097 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3098 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3099 continue;
3100 }
3101
3102 r = strv_push(rt, n);
3103 if (r < 0)
3104 return log_oom();
3105
3106 n = NULL;
3107 }
3108 if (!isempty(state))
3109 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3110 "Trailing garbage, ignoring.");
3111
3112 return 0;
3113 }
3114
3115 int config_parse_set_status(
3116 const char *unit,
3117 const char *filename,
3118 unsigned line,
3119 const char *section,
3120 unsigned section_line,
3121 const char *lvalue,
3122 int ltype,
3123 const char *rvalue,
3124 void *data,
3125 void *userdata) {
3126
3127 size_t l;
3128 const char *word, *state;
3129 int r;
3130 ExitStatusSet *status_set = data;
3131
3132 assert(filename);
3133 assert(lvalue);
3134 assert(rvalue);
3135 assert(data);
3136
3137 /* Empty assignment resets the list */
3138 if (isempty(rvalue)) {
3139 exit_status_set_free(status_set);
3140 return 0;
3141 }
3142
3143 FOREACH_WORD(word, l, rvalue, state) {
3144 _cleanup_free_ char *temp;
3145 int val;
3146 Set **set;
3147
3148 temp = strndup(word, l);
3149 if (!temp)
3150 return log_oom();
3151
3152 r = safe_atoi(temp, &val);
3153 if (r < 0) {
3154 val = signal_from_string_try_harder(temp);
3155
3156 if (val <= 0) {
3157 log_syntax(unit, LOG_ERR, filename, line, -val,
3158 "Failed to parse value, ignoring: %s", word);
3159 continue;
3160 }
3161 set = &status_set->signal;
3162 } else {
3163 if (val < 0 || val > 255) {
3164 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3165 "Value %d is outside range 0-255, ignoring", val);
3166 continue;
3167 }
3168 set = &status_set->status;
3169 }
3170
3171 r = set_ensure_allocated(set, NULL);
3172 if (r < 0)
3173 return log_oom();
3174
3175 r = set_put(*set, INT_TO_PTR(val));
3176 if (r < 0) {
3177 log_syntax(unit, LOG_ERR, filename, line, -r,
3178 "Unable to store: %s", word);
3179 return r;
3180 }
3181 }
3182 if (!isempty(state))
3183 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3184 "Trailing garbage, ignoring.");
3185
3186 return 0;
3187 }
3188
3189 int config_parse_namespace_path_strv(
3190 const char *unit,
3191 const char *filename,
3192 unsigned line,
3193 const char *section,
3194 unsigned section_line,
3195 const char *lvalue,
3196 int ltype,
3197 const char *rvalue,
3198 void *data,
3199 void *userdata) {
3200
3201 char*** sv = data;
3202 const char *word, *state;
3203 size_t l;
3204 int r;
3205
3206 assert(filename);
3207 assert(lvalue);
3208 assert(rvalue);
3209 assert(data);
3210
3211 if (isempty(rvalue)) {
3212 /* Empty assignment resets the list */
3213 strv_free(*sv);
3214 *sv = NULL;
3215 return 0;
3216 }
3217
3218 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3219 _cleanup_free_ char *n;
3220 int offset;
3221
3222 n = strndup(word, l);
3223 if (!n)
3224 return log_oom();
3225
3226 if (!utf8_is_valid(n)) {
3227 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3228 continue;
3229 }
3230
3231 offset = n[0] == '-';
3232 if (!path_is_absolute(n + offset)) {
3233 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3234 "Not an absolute path, ignoring: %s", rvalue);
3235 continue;
3236 }
3237
3238 path_kill_slashes(n);
3239
3240 r = strv_push(sv, n);
3241 if (r < 0)
3242 return log_oom();
3243
3244 n = NULL;
3245 }
3246 if (!isempty(state))
3247 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3248 "Trailing garbage, ignoring.");
3249
3250 return 0;
3251 }
3252
3253 int config_parse_no_new_privileges(
3254 const char* unit,
3255 const char *filename,
3256 unsigned line,
3257 const char *section,
3258 unsigned section_line,
3259 const char *lvalue,
3260 int ltype,
3261 const char *rvalue,
3262 void *data,
3263 void *userdata) {
3264
3265 ExecContext *c = data;
3266 int k;
3267
3268 assert(filename);
3269 assert(lvalue);
3270 assert(rvalue);
3271 assert(data);
3272
3273 k = parse_boolean(rvalue);
3274 if (k < 0) {
3275 log_syntax(unit, LOG_ERR, filename, line, -k,
3276 "Failed to parse boolean value, ignoring: %s", rvalue);
3277 return 0;
3278 }
3279
3280 c->no_new_privileges = !!k;
3281 c->no_new_privileges_set = true;
3282
3283 return 0;
3284 }
3285
3286 int config_parse_protect_home(
3287 const char* unit,
3288 const char *filename,
3289 unsigned line,
3290 const char *section,
3291 unsigned section_line,
3292 const char *lvalue,
3293 int ltype,
3294 const char *rvalue,
3295 void *data,
3296 void *userdata) {
3297
3298 ExecContext *c = data;
3299 int k;
3300
3301 assert(filename);
3302 assert(lvalue);
3303 assert(rvalue);
3304 assert(data);
3305
3306 /* Our enum shall be a superset of booleans, hence first try
3307 * to parse as as boolean, and then as enum */
3308
3309 k = parse_boolean(rvalue);
3310 if (k > 0)
3311 c->protect_home = PROTECT_HOME_YES;
3312 else if (k == 0)
3313 c->protect_home = PROTECT_HOME_NO;
3314 else {
3315 ProtectHome h;
3316
3317 h = protect_home_from_string(rvalue);
3318 if (h < 0){
3319 log_syntax(unit, LOG_ERR, filename, line, -h,
3320 "Failed to parse protect home value, ignoring: %s", rvalue);
3321 return 0;
3322 }
3323
3324 c->protect_home = h;
3325 }
3326
3327 return 0;
3328 }
3329
3330 int config_parse_protect_system(
3331 const char* unit,
3332 const char *filename,
3333 unsigned line,
3334 const char *section,
3335 unsigned section_line,
3336 const char *lvalue,
3337 int ltype,
3338 const char *rvalue,
3339 void *data,
3340 void *userdata) {
3341
3342 ExecContext *c = data;
3343 int k;
3344
3345 assert(filename);
3346 assert(lvalue);
3347 assert(rvalue);
3348 assert(data);
3349
3350 /* Our enum shall be a superset of booleans, hence first try
3351 * to parse as as boolean, and then as enum */
3352
3353 k = parse_boolean(rvalue);
3354 if (k > 0)
3355 c->protect_system = PROTECT_SYSTEM_YES;
3356 else if (k == 0)
3357 c->protect_system = PROTECT_SYSTEM_NO;
3358 else {
3359 ProtectSystem s;
3360
3361 s = protect_system_from_string(rvalue);
3362 if (s < 0){
3363 log_syntax(unit, LOG_ERR, filename, line, -s,
3364 "Failed to parse protect system value, ignoring: %s", rvalue);
3365 return 0;
3366 }
3367
3368 c->protect_system = s;
3369 }
3370
3371 return 0;
3372 }
3373
3374 #define FOLLOW_MAX 8
3375
3376 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3377 unsigned c = 0;
3378 int fd, r;
3379 FILE *f;
3380 char *id = NULL;
3381
3382 assert(filename);
3383 assert(*filename);
3384 assert(_f);
3385 assert(names);
3386
3387 /* This will update the filename pointer if the loaded file is
3388 * reached by a symlink. The old string will be freed. */
3389
3390 for (;;) {
3391 char *target, *name;
3392
3393 if (c++ >= FOLLOW_MAX)
3394 return -ELOOP;
3395
3396 path_kill_slashes(*filename);
3397
3398 /* Add the file name we are currently looking at to
3399 * the names of this unit, but only if it is a valid
3400 * unit name. */
3401 name = basename(*filename);
3402
3403 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
3404
3405 id = set_get(names, name);
3406 if (!id) {
3407 id = strdup(name);
3408 if (!id)
3409 return -ENOMEM;
3410
3411 r = set_consume(names, id);
3412 if (r < 0)
3413 return r;
3414 }
3415 }
3416
3417 /* Try to open the file name, but don't if its a symlink */
3418 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3419 if (fd >= 0)
3420 break;
3421
3422 if (errno != ELOOP)
3423 return -errno;
3424
3425 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3426 r = readlink_and_make_absolute(*filename, &target);
3427 if (r < 0)
3428 return r;
3429
3430 free(*filename);
3431 *filename = target;
3432 }
3433
3434 f = fdopen(fd, "re");
3435 if (!f) {
3436 safe_close(fd);
3437 return -errno;
3438 }
3439
3440 *_f = f;
3441 *_final = id;
3442 return 0;
3443 }
3444
3445 static int merge_by_names(Unit **u, Set *names, const char *id) {
3446 char *k;
3447 int r;
3448
3449 assert(u);
3450 assert(*u);
3451 assert(names);
3452
3453 /* Let's try to add in all symlink names we found */
3454 while ((k = set_steal_first(names))) {
3455
3456 /* First try to merge in the other name into our
3457 * unit */
3458 r = unit_merge_by_name(*u, k);
3459 if (r < 0) {
3460 Unit *other;
3461
3462 /* Hmm, we couldn't merge the other unit into
3463 * ours? Then let's try it the other way
3464 * round */
3465
3466 other = manager_get_unit((*u)->manager, k);
3467 free(k);
3468
3469 if (other) {
3470 r = unit_merge(other, *u);
3471 if (r >= 0) {
3472 *u = other;
3473 return merge_by_names(u, names, NULL);
3474 }
3475 }
3476
3477 return r;
3478 }
3479
3480 if (id == k)
3481 unit_choose_id(*u, id);
3482
3483 free(k);
3484 }
3485
3486 return 0;
3487 }
3488
3489 static int load_from_path(Unit *u, const char *path) {
3490 int r;
3491 _cleanup_set_free_free_ Set *symlink_names = NULL;
3492 _cleanup_fclose_ FILE *f = NULL;
3493 _cleanup_free_ char *filename = NULL;
3494 char *id = NULL;
3495 Unit *merged;
3496 struct stat st;
3497
3498 assert(u);
3499 assert(path);
3500
3501 symlink_names = set_new(&string_hash_ops);
3502 if (!symlink_names)
3503 return -ENOMEM;
3504
3505 if (path_is_absolute(path)) {
3506
3507 filename = strdup(path);
3508 if (!filename)
3509 return -ENOMEM;
3510
3511 r = open_follow(&filename, &f, symlink_names, &id);
3512 if (r < 0) {
3513 filename = mfree(filename);
3514 if (r != -ENOENT)
3515 return r;
3516 }
3517
3518 } else {
3519 char **p;
3520
3521 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3522
3523 /* Instead of opening the path right away, we manually
3524 * follow all symlinks and add their name to our unit
3525 * name set while doing so */
3526 filename = path_make_absolute(path, *p);
3527 if (!filename)
3528 return -ENOMEM;
3529
3530 if (u->manager->unit_path_cache &&
3531 !set_get(u->manager->unit_path_cache, filename))
3532 r = -ENOENT;
3533 else
3534 r = open_follow(&filename, &f, symlink_names, &id);
3535
3536 if (r < 0) {
3537 filename = mfree(filename);
3538 if (r != -ENOENT)
3539 return r;
3540
3541 /* Empty the symlink names for the next run */
3542 set_clear_free(symlink_names);
3543 continue;
3544 }
3545
3546 break;
3547 }
3548 }
3549
3550 if (!filename)
3551 /* Hmm, no suitable file found? */
3552 return 0;
3553
3554 merged = u;
3555 r = merge_by_names(&merged, symlink_names, id);
3556 if (r < 0)
3557 return r;
3558
3559 if (merged != u) {
3560 u->load_state = UNIT_MERGED;
3561 return 0;
3562 }
3563
3564 if (fstat(fileno(f), &st) < 0)
3565 return -errno;
3566
3567 if (null_or_empty(&st))
3568 u->load_state = UNIT_MASKED;
3569 else {
3570 u->load_state = UNIT_LOADED;
3571
3572 /* Now, parse the file contents */
3573 r = config_parse(u->id, filename, f,
3574 UNIT_VTABLE(u)->sections,
3575 config_item_perf_lookup, load_fragment_gperf_lookup,
3576 false, true, false, u);
3577 if (r < 0)
3578 return r;
3579 }
3580
3581 free(u->fragment_path);
3582 u->fragment_path = filename;
3583 filename = NULL;
3584
3585 u->fragment_mtime = timespec_load(&st.st_mtim);
3586
3587 if (u->source_path) {
3588 if (stat(u->source_path, &st) >= 0)
3589 u->source_mtime = timespec_load(&st.st_mtim);
3590 else
3591 u->source_mtime = 0;
3592 }
3593
3594 return 0;
3595 }
3596
3597 int unit_load_fragment(Unit *u) {
3598 int r;
3599 Iterator i;
3600 const char *t;
3601
3602 assert(u);
3603 assert(u->load_state == UNIT_STUB);
3604 assert(u->id);
3605
3606 /* First, try to find the unit under its id. We always look
3607 * for unit files in the default directories, to make it easy
3608 * to override things by placing things in /etc/systemd/system */
3609 r = load_from_path(u, u->id);
3610 if (r < 0)
3611 return r;
3612
3613 /* Try to find an alias we can load this with */
3614 if (u->load_state == UNIT_STUB) {
3615 SET_FOREACH(t, u->names, i) {
3616
3617 if (t == u->id)
3618 continue;
3619
3620 r = load_from_path(u, t);
3621 if (r < 0)
3622 return r;
3623
3624 if (u->load_state != UNIT_STUB)
3625 break;
3626 }
3627 }
3628
3629 /* And now, try looking for it under the suggested (originally linked) path */
3630 if (u->load_state == UNIT_STUB && u->fragment_path) {
3631
3632 r = load_from_path(u, u->fragment_path);
3633 if (r < 0)
3634 return r;
3635
3636 if (u->load_state == UNIT_STUB) {
3637 /* Hmm, this didn't work? Then let's get rid
3638 * of the fragment path stored for us, so that
3639 * we don't point to an invalid location. */
3640 free(u->fragment_path);
3641 u->fragment_path = NULL;
3642 }
3643 }
3644
3645 /* Look for a template */
3646 if (u->load_state == UNIT_STUB && u->instance) {
3647 _cleanup_free_ char *k = NULL;
3648
3649 r = unit_name_template(u->id, &k);
3650 if (r < 0)
3651 return r;
3652
3653 r = load_from_path(u, k);
3654 if (r < 0)
3655 return r;
3656
3657 if (u->load_state == UNIT_STUB) {
3658 SET_FOREACH(t, u->names, i) {
3659 _cleanup_free_ char *z = NULL;
3660
3661 if (t == u->id)
3662 continue;
3663
3664 r = unit_name_template(t, &z);
3665 if (r < 0)
3666 return r;
3667
3668 r = load_from_path(u, z);
3669 if (r < 0)
3670 return r;
3671
3672 if (u->load_state != UNIT_STUB)
3673 break;
3674 }
3675 }
3676 }
3677
3678 return 0;
3679 }
3680
3681 void unit_dump_config_items(FILE *f) {
3682 static const struct {
3683 const ConfigParserCallback callback;
3684 const char *rvalue;
3685 } table[] = {
3686 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3687 { config_parse_warn_compat, "NOTSUPPORTED" },
3688 #endif
3689 { config_parse_int, "INTEGER" },
3690 { config_parse_unsigned, "UNSIGNED" },
3691 { config_parse_iec_size, "SIZE" },
3692 { config_parse_iec_off, "SIZE" },
3693 { config_parse_si_size, "SIZE" },
3694 { config_parse_bool, "BOOLEAN" },
3695 { config_parse_string, "STRING" },
3696 { config_parse_path, "PATH" },
3697 { config_parse_unit_path_printf, "PATH" },
3698 { config_parse_strv, "STRING [...]" },
3699 { config_parse_exec_nice, "NICE" },
3700 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3701 { config_parse_exec_io_class, "IOCLASS" },
3702 { config_parse_exec_io_priority, "IOPRIORITY" },
3703 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3704 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3705 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3706 { config_parse_mode, "MODE" },
3707 { config_parse_unit_env_file, "FILE" },
3708 { config_parse_output, "OUTPUT" },
3709 { config_parse_input, "INPUT" },
3710 { config_parse_log_facility, "FACILITY" },
3711 { config_parse_log_level, "LEVEL" },
3712 { config_parse_exec_capabilities, "CAPABILITIES" },
3713 { config_parse_exec_secure_bits, "SECUREBITS" },
3714 { config_parse_bounding_set, "BOUNDINGSET" },
3715 { config_parse_limit, "LIMIT" },
3716 { config_parse_unit_deps, "UNIT [...]" },
3717 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3718 { config_parse_service_type, "SERVICETYPE" },
3719 { config_parse_service_restart, "SERVICERESTART" },
3720 #ifdef HAVE_SYSV_COMPAT
3721 { config_parse_sysv_priority, "SYSVPRIORITY" },
3722 #endif
3723 { config_parse_kill_mode, "KILLMODE" },
3724 { config_parse_kill_signal, "SIGNAL" },
3725 { config_parse_socket_listen, "SOCKET [...]" },
3726 { config_parse_socket_bind, "SOCKETBIND" },
3727 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3728 { config_parse_sec, "SECONDS" },
3729 { config_parse_nsec, "NANOSECONDS" },
3730 { config_parse_namespace_path_strv, "PATH [...]" },
3731 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3732 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3733 { config_parse_unit_string_printf, "STRING" },
3734 { config_parse_trigger_unit, "UNIT" },
3735 { config_parse_timer, "TIMER" },
3736 { config_parse_path_spec, "PATH" },
3737 { config_parse_notify_access, "ACCESS" },
3738 { config_parse_ip_tos, "TOS" },
3739 { config_parse_unit_condition_path, "CONDITION" },
3740 { config_parse_unit_condition_string, "CONDITION" },
3741 { config_parse_unit_condition_null, "CONDITION" },
3742 { config_parse_unit_slice, "SLICE" },
3743 { config_parse_documentation, "URL" },
3744 { config_parse_service_timeout, "SECONDS" },
3745 { config_parse_failure_action, "ACTION" },
3746 { config_parse_set_status, "STATUS" },
3747 { config_parse_service_sockets, "SOCKETS" },
3748 { config_parse_environ, "ENVIRON" },
3749 #ifdef HAVE_SECCOMP
3750 { config_parse_syscall_filter, "SYSCALLS" },
3751 { config_parse_syscall_archs, "ARCHS" },
3752 { config_parse_syscall_errno, "ERRNO" },
3753 { config_parse_address_families, "FAMILIES" },
3754 #endif
3755 { config_parse_cpu_shares, "SHARES" },
3756 { config_parse_memory_limit, "LIMIT" },
3757 { config_parse_device_allow, "DEVICE" },
3758 { config_parse_device_policy, "POLICY" },
3759 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3760 { config_parse_blockio_weight, "WEIGHT" },
3761 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3762 { config_parse_long, "LONG" },
3763 { config_parse_socket_service, "SERVICE" },
3764 #ifdef HAVE_SELINUX
3765 { config_parse_exec_selinux_context, "LABEL" },
3766 #endif
3767 { config_parse_job_mode, "MODE" },
3768 { config_parse_job_mode_isolate, "BOOLEAN" },
3769 { config_parse_personality, "PERSONALITY" },
3770 };
3771
3772 const char *prev = NULL;
3773 const char *i;
3774
3775 assert(f);
3776
3777 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3778 const char *rvalue = "OTHER", *lvalue;
3779 unsigned j;
3780 size_t prefix_len;
3781 const char *dot;
3782 const ConfigPerfItem *p;
3783
3784 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3785
3786 dot = strchr(i, '.');
3787 lvalue = dot ? dot + 1 : i;
3788 prefix_len = dot-i;
3789
3790 if (dot)
3791 if (!prev || !strneq(prev, i, prefix_len+1)) {
3792 if (prev)
3793 fputc('\n', f);
3794
3795 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3796 }
3797
3798 for (j = 0; j < ELEMENTSOF(table); j++)
3799 if (p->parse == table[j].callback) {
3800 rvalue = table[j].rvalue;
3801 break;
3802 }
3803
3804 fprintf(f, "%s=%s\n", lvalue, rvalue);
3805 prev = i;
3806 }
3807 }