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