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