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