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