]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
conf-parser: turn three bool function params into a flags fields
[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 #if 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 "mount-util.h"
53 #include "parse-util.h"
54 #include "path-util.h"
55 #include "process-util.h"
56 #include "rlimit-util.h"
57 #if HAVE_SECCOMP
58 #include "seccomp-util.h"
59 #endif
60 #include "securebits.h"
61 #include "securebits-util.h"
62 #include "signal-util.h"
63 #include "stat-util.h"
64 #include "string-util.h"
65 #include "strv.h"
66 #include "unit-name.h"
67 #include "unit-printf.h"
68 #include "unit.h"
69 #include "user-util.h"
70 #include "utf8.h"
71 #include "web-util.h"
72
73 int config_parse_warn_compat(
74 const char *unit,
75 const char *filename,
76 unsigned line,
77 const char *section,
78 unsigned section_line,
79 const char *lvalue,
80 int ltype,
81 const char *rvalue,
82 void *data,
83 void *userdata) {
84 Disabled reason = ltype;
85
86 switch(reason) {
87 case DISABLED_CONFIGURATION:
88 log_syntax(unit, LOG_DEBUG, filename, line, 0,
89 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
90 break;
91 case DISABLED_LEGACY:
92 log_syntax(unit, LOG_INFO, filename, line, 0,
93 "Support for option %s= has been removed and it is ignored", lvalue);
94 break;
95 case DISABLED_EXPERIMENTAL:
96 log_syntax(unit, LOG_INFO, filename, line, 0,
97 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
98 break;
99 };
100
101 return 0;
102 }
103
104 int config_parse_unit_deps(
105 const char *unit,
106 const char *filename,
107 unsigned line,
108 const char *section,
109 unsigned section_line,
110 const char *lvalue,
111 int ltype,
112 const char *rvalue,
113 void *data,
114 void *userdata) {
115
116 UnitDependency d = ltype;
117 Unit *u = userdata;
118 const char *p;
119
120 assert(filename);
121 assert(lvalue);
122 assert(rvalue);
123
124 p = rvalue;
125 for (;;) {
126 _cleanup_free_ char *word = NULL, *k = NULL;
127 int r;
128
129 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
130 if (r == 0)
131 break;
132 if (r == -ENOMEM)
133 return log_oom();
134 if (r < 0) {
135 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
136 break;
137 }
138
139 r = unit_name_printf(u, word, &k);
140 if (r < 0) {
141 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
142 continue;
143 }
144
145 r = unit_add_dependency_by_name(u, d, k, NULL, true, UNIT_DEPENDENCY_FILE);
146 if (r < 0)
147 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
148 }
149
150 return 0;
151 }
152
153 int config_parse_obsolete_unit_deps(
154 const char *unit,
155 const char *filename,
156 unsigned line,
157 const char *section,
158 unsigned section_line,
159 const char *lvalue,
160 int ltype,
161 const char *rvalue,
162 void *data,
163 void *userdata) {
164
165 log_syntax(unit, LOG_WARNING, filename, line, 0,
166 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
167
168 return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
169 }
170
171 int config_parse_unit_string_printf(
172 const char *unit,
173 const char *filename,
174 unsigned line,
175 const char *section,
176 unsigned section_line,
177 const char *lvalue,
178 int ltype,
179 const char *rvalue,
180 void *data,
181 void *userdata) {
182
183 _cleanup_free_ char *k = NULL;
184 Unit *u = userdata;
185 int r;
186
187 assert(filename);
188 assert(lvalue);
189 assert(rvalue);
190 assert(u);
191
192 r = unit_full_printf(u, rvalue, &k);
193 if (r < 0) {
194 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
195 return 0;
196 }
197
198 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
199 }
200
201 int config_parse_unit_strv_printf(
202 const char *unit,
203 const char *filename,
204 unsigned line,
205 const char *section,
206 unsigned section_line,
207 const char *lvalue,
208 int ltype,
209 const char *rvalue,
210 void *data,
211 void *userdata) {
212
213 Unit *u = userdata;
214 _cleanup_free_ char *k = NULL;
215 int r;
216
217 assert(filename);
218 assert(lvalue);
219 assert(rvalue);
220 assert(u);
221
222 r = unit_full_printf(u, rvalue, &k);
223 if (r < 0) {
224 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
225 return 0;
226 }
227
228 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
229 }
230
231 int config_parse_unit_path_printf(
232 const char *unit,
233 const char *filename,
234 unsigned line,
235 const char *section,
236 unsigned section_line,
237 const char *lvalue,
238 int ltype,
239 const char *rvalue,
240 void *data,
241 void *userdata) {
242
243 _cleanup_free_ char *k = NULL;
244 Unit *u = userdata;
245 int r;
246 bool fatal = ltype;
247
248 assert(filename);
249 assert(lvalue);
250 assert(rvalue);
251 assert(u);
252
253 r = unit_full_printf(u, rvalue, &k);
254 if (r < 0) {
255 log_syntax(unit, LOG_ERR, filename, line, r,
256 "Failed to resolve unit specifiers on %s%s: %m",
257 fatal ? "" : ", ignoring", rvalue);
258 return fatal ? -ENOEXEC : 0;
259 }
260
261 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
262 }
263
264 int config_parse_unit_path_strv_printf(
265 const char *unit,
266 const char *filename,
267 unsigned line,
268 const char *section,
269 unsigned section_line,
270 const char *lvalue,
271 int ltype,
272 const char *rvalue,
273 void *data,
274 void *userdata) {
275
276 char ***x = data;
277 Unit *u = userdata;
278 int r;
279 const char *p;
280
281 assert(filename);
282 assert(lvalue);
283 assert(rvalue);
284 assert(u);
285
286 if (isempty(rvalue)) {
287 *x = strv_free(*x);
288 return 0;
289 }
290
291 for (p = rvalue;;) {
292 _cleanup_free_ char *word = NULL, *k = NULL;
293
294 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
295 if (r == 0)
296 return 0;
297 if (r == -ENOMEM)
298 return log_oom();
299 if (r < 0) {
300 log_syntax(unit, LOG_WARNING, filename, line, r,
301 "Invalid syntax, ignoring: %s", rvalue);
302 return 0;
303 }
304
305 r = unit_full_printf(u, word, &k);
306 if (r < 0) {
307 log_syntax(unit, LOG_ERR, filename, line, r,
308 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word);
309 return 0;
310 }
311
312 if (!utf8_is_valid(k)) {
313 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
314 return 0;
315 }
316
317 if (!path_is_absolute(k)) {
318 log_syntax(unit, LOG_ERR, filename, line, 0,
319 "Symlink path is not absolute: %s", k);
320 return 0;
321 }
322
323 path_kill_slashes(k);
324
325 r = strv_push(x, k);
326 if (r < 0)
327 return log_oom();
328 k = NULL;
329 }
330 }
331
332 int config_parse_socket_listen(const char *unit,
333 const char *filename,
334 unsigned line,
335 const char *section,
336 unsigned section_line,
337 const char *lvalue,
338 int ltype,
339 const char *rvalue,
340 void *data,
341 void *userdata) {
342
343 _cleanup_free_ SocketPort *p = NULL;
344 SocketPort *tail;
345 Socket *s;
346 int r;
347
348 assert(filename);
349 assert(lvalue);
350 assert(rvalue);
351 assert(data);
352
353 s = SOCKET(data);
354
355 if (isempty(rvalue)) {
356 /* An empty assignment removes all ports */
357 socket_free_ports(s);
358 return 0;
359 }
360
361 p = new0(SocketPort, 1);
362 if (!p)
363 return log_oom();
364
365 if (ltype != SOCKET_SOCKET) {
366
367 p->type = ltype;
368 r = unit_full_printf(UNIT(s), rvalue, &p->path);
369 if (r < 0) {
370 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
371 return 0;
372 }
373
374 path_kill_slashes(p->path);
375
376 } else if (streq(lvalue, "ListenNetlink")) {
377 _cleanup_free_ char *k = NULL;
378
379 p->type = SOCKET_SOCKET;
380 r = unit_full_printf(UNIT(s), rvalue, &k);
381 if (r < 0) {
382 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
383 return 0;
384 }
385
386 r = socket_address_parse_netlink(&p->address, k);
387 if (r < 0) {
388 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
389 return 0;
390 }
391
392 } else {
393 _cleanup_free_ char *k = NULL;
394
395 p->type = SOCKET_SOCKET;
396 r = unit_full_printf(UNIT(s), rvalue, &k);
397 if (r < 0) {
398 log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
399 return 0;
400 }
401
402 r = socket_address_parse_and_warn(&p->address, k);
403 if (r < 0) {
404 if (r != -EAFNOSUPPORT)
405 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
406
407 return 0;
408 }
409
410 if (streq(lvalue, "ListenStream"))
411 p->address.type = SOCK_STREAM;
412 else if (streq(lvalue, "ListenDatagram"))
413 p->address.type = SOCK_DGRAM;
414 else {
415 assert(streq(lvalue, "ListenSequentialPacket"));
416 p->address.type = SOCK_SEQPACKET;
417 }
418
419 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
420 log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
421 return 0;
422 }
423 }
424
425 p->fd = -1;
426 p->auxiliary_fds = NULL;
427 p->n_auxiliary_fds = 0;
428 p->socket = s;
429
430 if (s->ports) {
431 LIST_FIND_TAIL(port, s->ports, tail);
432 LIST_INSERT_AFTER(port, s->ports, tail, p);
433 } else
434 LIST_PREPEND(port, s->ports, p);
435 p = NULL;
436
437 return 0;
438 }
439
440 int config_parse_socket_protocol(const char *unit,
441 const char *filename,
442 unsigned line,
443 const char *section,
444 unsigned section_line,
445 const char *lvalue,
446 int ltype,
447 const char *rvalue,
448 void *data,
449 void *userdata) {
450 Socket *s;
451
452 assert(filename);
453 assert(lvalue);
454 assert(rvalue);
455 assert(data);
456
457 s = SOCKET(data);
458
459 if (streq(rvalue, "udplite"))
460 s->socket_protocol = IPPROTO_UDPLITE;
461 else if (streq(rvalue, "sctp"))
462 s->socket_protocol = IPPROTO_SCTP;
463 else {
464 log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
465 return 0;
466 }
467
468 return 0;
469 }
470
471 int config_parse_socket_bind(const char *unit,
472 const char *filename,
473 unsigned line,
474 const char *section,
475 unsigned section_line,
476 const char *lvalue,
477 int ltype,
478 const char *rvalue,
479 void *data,
480 void *userdata) {
481
482 Socket *s;
483 SocketAddressBindIPv6Only b;
484
485 assert(filename);
486 assert(lvalue);
487 assert(rvalue);
488 assert(data);
489
490 s = SOCKET(data);
491
492 b = socket_address_bind_ipv6_only_from_string(rvalue);
493 if (b < 0) {
494 int r;
495
496 r = parse_boolean(rvalue);
497 if (r < 0) {
498 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
499 return 0;
500 }
501
502 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
503 } else
504 s->bind_ipv6_only = b;
505
506 return 0;
507 }
508
509 int config_parse_exec_nice(
510 const char *unit,
511 const char *filename,
512 unsigned line,
513 const char *section,
514 unsigned section_line,
515 const char *lvalue,
516 int ltype,
517 const char *rvalue,
518 void *data,
519 void *userdata) {
520
521 ExecContext *c = data;
522 int priority, r;
523
524 assert(filename);
525 assert(lvalue);
526 assert(rvalue);
527 assert(data);
528
529 r = parse_nice(rvalue, &priority);
530 if (r < 0) {
531 if (r == -ERANGE)
532 log_syntax(unit, LOG_ERR, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
533 else
534 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
535
536 return 0;
537 }
538
539 c->nice = priority;
540 c->nice_set = true;
541
542 return 0;
543 }
544
545 int config_parse_exec_oom_score_adjust(const char* unit,
546 const char *filename,
547 unsigned line,
548 const char *section,
549 unsigned section_line,
550 const char *lvalue,
551 int ltype,
552 const char *rvalue,
553 void *data,
554 void *userdata) {
555
556 ExecContext *c = data;
557 int oa, r;
558
559 assert(filename);
560 assert(lvalue);
561 assert(rvalue);
562 assert(data);
563
564 r = safe_atoi(rvalue, &oa);
565 if (r < 0) {
566 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
567 return 0;
568 }
569
570 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
571 log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
572 return 0;
573 }
574
575 c->oom_score_adjust = oa;
576 c->oom_score_adjust_set = true;
577
578 return 0;
579 }
580
581 int config_parse_exec(
582 const char *unit,
583 const char *filename,
584 unsigned line,
585 const char *section,
586 unsigned section_line,
587 const char *lvalue,
588 int ltype,
589 const char *rvalue,
590 void *data,
591 void *userdata) {
592
593 ExecCommand **e = data;
594 Unit *u = userdata;
595 const char *p;
596 bool semicolon;
597 int r;
598
599 assert(filename);
600 assert(lvalue);
601 assert(rvalue);
602 assert(e);
603
604 e += ltype;
605 rvalue += strspn(rvalue, WHITESPACE);
606
607 if (isempty(rvalue)) {
608 /* An empty assignment resets the list */
609 *e = exec_command_free_list(*e);
610 return 0;
611 }
612
613 p = rvalue;
614 do {
615 _cleanup_free_ char *path = NULL, *firstword = NULL;
616 ExecCommandFlags flags = 0;
617 bool ignore = false, separate_argv0 = false;
618 _cleanup_free_ ExecCommand *nce = NULL;
619 _cleanup_strv_free_ char **n = NULL;
620 size_t nlen = 0, nbufsize = 0;
621 const char *f;
622
623 semicolon = false;
624
625 r = extract_first_word_and_warn(&p, &firstword, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
626 if (r <= 0)
627 return 0;
628
629 f = firstword;
630 for (;;) {
631 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
632 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
633 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
634 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
635 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
636 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
637 * other sandboxing, with some special exceptions for changing UID.
638 *
639 * The idea is that '!!' may be used to write services that can take benefit of systemd's
640 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
641 * privilege dropping within the daemon if the kernel does not offer that. */
642
643 if (*f == '-' && !(flags & EXEC_COMMAND_IGNORE_FAILURE)) {
644 flags |= EXEC_COMMAND_IGNORE_FAILURE;
645 ignore = true;
646 } else if (*f == '@' && !separate_argv0)
647 separate_argv0 = true;
648 else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
649 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
650 else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
651 flags |= EXEC_COMMAND_NO_SETUID;
652 else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))) {
653 flags &= ~EXEC_COMMAND_NO_SETUID;
654 flags |= EXEC_COMMAND_AMBIENT_MAGIC;
655 } else
656 break;
657 f++;
658 }
659
660 r = unit_full_printf(u, f, &path);
661 if (r < 0) {
662 log_syntax(unit, LOG_ERR, filename, line, r,
663 "Failed to resolve unit specifiers on %s%s: %m",
664 f, ignore ? ", ignoring" : "");
665 return ignore ? 0 : -ENOEXEC;
666 }
667
668 if (isempty(path)) {
669 /* First word is either "-" or "@" with no command. */
670 log_syntax(unit, LOG_ERR, filename, line, 0,
671 "Empty path in command line%s: \"%s\"",
672 ignore ? ", ignoring" : "", rvalue);
673 return ignore ? 0 : -ENOEXEC;
674 }
675 if (!string_is_safe(path)) {
676 log_syntax(unit, LOG_ERR, filename, line, 0,
677 "Executable path contains special characters%s: %s",
678 ignore ? ", ignoring" : "", rvalue);
679 return ignore ? 0 : -ENOEXEC;
680 }
681 if (!path_is_absolute(path)) {
682 log_syntax(unit, LOG_ERR, filename, line, 0,
683 "Executable path is not absolute%s: %s",
684 ignore ? ", ignoring" : "", rvalue);
685 return ignore ? 0 : -ENOEXEC;
686 }
687 if (endswith(path, "/")) {
688 log_syntax(unit, LOG_ERR, filename, line, 0,
689 "Executable path specifies a directory%s: %s",
690 ignore ? ", ignoring" : "", rvalue);
691 return ignore ? 0 : -ENOEXEC;
692 }
693
694 if (!separate_argv0) {
695 char *w = NULL;
696
697 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
698 return log_oom();
699
700 w = strdup(path);
701 if (!w)
702 return log_oom();
703 n[nlen++] = w;
704 n[nlen] = NULL;
705 }
706
707 path_kill_slashes(path);
708
709 while (!isempty(p)) {
710 _cleanup_free_ char *word = NULL, *resolved = NULL;
711
712 /* Check explicitly for an unquoted semicolon as
713 * command separator token. */
714 if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
715 p++;
716 p += strspn(p, WHITESPACE);
717 semicolon = true;
718 break;
719 }
720
721 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
722 * extract_first_word() would return the same for all of those. */
723 if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
724 char *w;
725
726 p += 2;
727 p += strspn(p, WHITESPACE);
728
729 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
730 return log_oom();
731
732 w = strdup(";");
733 if (!w)
734 return log_oom();
735 n[nlen++] = w;
736 n[nlen] = NULL;
737 continue;
738 }
739
740 r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
741 if (r == 0)
742 break;
743 if (r < 0)
744 return ignore ? 0 : -ENOEXEC;
745
746 r = unit_full_printf(u, word, &resolved);
747 if (r < 0) {
748 log_syntax(unit, LOG_ERR, filename, line, r,
749 "Failed to resolve unit specifiers on %s%s: %m",
750 word, ignore ? ", ignoring" : "");
751 return ignore ? 0 : -ENOEXEC;
752 }
753
754 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
755 return log_oom();
756 n[nlen++] = resolved;
757 n[nlen] = NULL;
758 resolved = NULL;
759 }
760
761 if (!n || !n[0]) {
762 log_syntax(unit, LOG_ERR, filename, line, 0,
763 "Empty executable name or zeroeth argument%s: %s",
764 ignore ? ", ignoring" : "", rvalue);
765 return ignore ? 0 : -ENOEXEC;
766 }
767
768 nce = new0(ExecCommand, 1);
769 if (!nce)
770 return log_oom();
771
772 nce->argv = n;
773 nce->path = path;
774 nce->flags = flags;
775
776 exec_command_append_list(e, nce);
777
778 /* Do not _cleanup_free_ these. */
779 n = NULL;
780 path = NULL;
781 nce = NULL;
782
783 rvalue = p;
784 } while (semicolon);
785
786 return 0;
787 }
788
789 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
790 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
791
792 int config_parse_socket_bindtodevice(
793 const char* unit,
794 const char *filename,
795 unsigned line,
796 const char *section,
797 unsigned section_line,
798 const char *lvalue,
799 int ltype,
800 const char *rvalue,
801 void *data,
802 void *userdata) {
803
804 Socket *s = data;
805 char *n;
806
807 assert(filename);
808 assert(lvalue);
809 assert(rvalue);
810 assert(data);
811
812 if (rvalue[0] && !streq(rvalue, "*")) {
813 if (!ifname_valid(rvalue)) {
814 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue);
815 return 0;
816 }
817
818 n = strdup(rvalue);
819 if (!n)
820 return log_oom();
821 } else
822 n = NULL;
823
824 free(s->bind_to_device);
825 s->bind_to_device = n;
826
827 return 0;
828 }
829
830 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input literal specifier");
831 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output literal specifier");
832
833 int config_parse_exec_input(const char *unit,
834 const char *filename,
835 unsigned line,
836 const char *section,
837 unsigned section_line,
838 const char *lvalue,
839 int ltype,
840 const char *rvalue,
841 void *data,
842 void *userdata) {
843 ExecContext *c = data;
844 const char *name;
845 int r;
846
847 assert(data);
848 assert(filename);
849 assert(line);
850 assert(rvalue);
851
852 name = startswith(rvalue, "fd:");
853 if (name) {
854 /* Strip prefix and validate fd name */
855 if (!fdname_is_valid(name)) {
856 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
857 return 0;
858 }
859 c->std_input = EXEC_INPUT_NAMED_FD;
860 r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], name);
861 if (r < 0)
862 log_oom();
863 return r;
864 } else {
865 ExecInput ei = exec_input_from_string(rvalue);
866 if (ei == _EXEC_INPUT_INVALID)
867 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue);
868 else
869 c->std_input = ei;
870 return 0;
871 }
872 }
873
874 int config_parse_exec_output(const char *unit,
875 const char *filename,
876 unsigned line,
877 const char *section,
878 unsigned section_line,
879 const char *lvalue,
880 int ltype,
881 const char *rvalue,
882 void *data,
883 void *userdata) {
884 ExecContext *c = data;
885 ExecOutput eo;
886 const char *name;
887 int r;
888
889 assert(data);
890 assert(filename);
891 assert(line);
892 assert(lvalue);
893 assert(rvalue);
894
895 name = startswith(rvalue, "fd:");
896 if (name) {
897 /* Strip prefix and validate fd name */
898 if (!fdname_is_valid(name)) {
899 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
900 return 0;
901 }
902 eo = EXEC_OUTPUT_NAMED_FD;
903 } else {
904 eo = exec_output_from_string(rvalue);
905 if (eo == _EXEC_OUTPUT_INVALID) {
906 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue);
907 return 0;
908 }
909 }
910
911 if (streq(lvalue, "StandardOutput")) {
912 c->std_output = eo;
913 r = free_and_strdup(&c->stdio_fdname[STDOUT_FILENO], name);
914 if (r < 0)
915 log_oom();
916 return r;
917 } else if (streq(lvalue, "StandardError")) {
918 c->std_error = eo;
919 r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], name);
920 if (r < 0)
921 log_oom();
922 return r;
923 } else {
924 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output property, ignoring: %s", lvalue);
925 return 0;
926 }
927 }
928
929 int config_parse_exec_io_class(const char *unit,
930 const char *filename,
931 unsigned line,
932 const char *section,
933 unsigned section_line,
934 const char *lvalue,
935 int ltype,
936 const char *rvalue,
937 void *data,
938 void *userdata) {
939
940 ExecContext *c = data;
941 int x;
942
943 assert(filename);
944 assert(lvalue);
945 assert(rvalue);
946 assert(data);
947
948 x = ioprio_class_from_string(rvalue);
949 if (x < 0) {
950 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
951 return 0;
952 }
953
954 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
955 c->ioprio_set = true;
956
957 return 0;
958 }
959
960 int config_parse_exec_io_priority(const char *unit,
961 const char *filename,
962 unsigned line,
963 const char *section,
964 unsigned section_line,
965 const char *lvalue,
966 int ltype,
967 const char *rvalue,
968 void *data,
969 void *userdata) {
970
971 ExecContext *c = data;
972 int i, r;
973
974 assert(filename);
975 assert(lvalue);
976 assert(rvalue);
977 assert(data);
978
979 r = ioprio_parse_priority(rvalue, &i);
980 if (r < 0) {
981 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
982 return 0;
983 }
984
985 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
986 c->ioprio_set = true;
987
988 return 0;
989 }
990
991 int config_parse_exec_cpu_sched_policy(const char *unit,
992 const char *filename,
993 unsigned line,
994 const char *section,
995 unsigned section_line,
996 const char *lvalue,
997 int ltype,
998 const char *rvalue,
999 void *data,
1000 void *userdata) {
1001
1002
1003 ExecContext *c = data;
1004 int x;
1005
1006 assert(filename);
1007 assert(lvalue);
1008 assert(rvalue);
1009 assert(data);
1010
1011 x = sched_policy_from_string(rvalue);
1012 if (x < 0) {
1013 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
1014 return 0;
1015 }
1016
1017 c->cpu_sched_policy = x;
1018 /* Moving to or from real-time policy? We need to adjust the priority */
1019 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
1020 c->cpu_sched_set = true;
1021
1022 return 0;
1023 }
1024
1025 int config_parse_exec_cpu_sched_prio(const char *unit,
1026 const char *filename,
1027 unsigned line,
1028 const char *section,
1029 unsigned section_line,
1030 const char *lvalue,
1031 int ltype,
1032 const char *rvalue,
1033 void *data,
1034 void *userdata) {
1035
1036 ExecContext *c = data;
1037 int i, min, max, r;
1038
1039 assert(filename);
1040 assert(lvalue);
1041 assert(rvalue);
1042 assert(data);
1043
1044 r = safe_atoi(rvalue, &i);
1045 if (r < 0) {
1046 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
1047 return 0;
1048 }
1049
1050 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1051 min = sched_get_priority_min(c->cpu_sched_policy);
1052 max = sched_get_priority_max(c->cpu_sched_policy);
1053
1054 if (i < min || i > max) {
1055 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
1056 return 0;
1057 }
1058
1059 c->cpu_sched_priority = i;
1060 c->cpu_sched_set = true;
1061
1062 return 0;
1063 }
1064
1065 int config_parse_exec_cpu_affinity(const char *unit,
1066 const char *filename,
1067 unsigned line,
1068 const char *section,
1069 unsigned section_line,
1070 const char *lvalue,
1071 int ltype,
1072 const char *rvalue,
1073 void *data,
1074 void *userdata) {
1075
1076 ExecContext *c = data;
1077 _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
1078 int ncpus;
1079
1080 assert(filename);
1081 assert(lvalue);
1082 assert(rvalue);
1083 assert(data);
1084
1085 ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
1086 if (ncpus < 0)
1087 return ncpus;
1088
1089 if (c->cpuset)
1090 CPU_FREE(c->cpuset);
1091
1092 if (ncpus == 0)
1093 /* An empty assignment resets the CPU list */
1094 c->cpuset = NULL;
1095 else {
1096 c->cpuset = cpuset;
1097 cpuset = NULL;
1098 }
1099 c->cpuset_ncpus = ncpus;
1100
1101 return 0;
1102 }
1103
1104 int config_parse_exec_secure_bits(const char *unit,
1105 const char *filename,
1106 unsigned line,
1107 const char *section,
1108 unsigned section_line,
1109 const char *lvalue,
1110 int ltype,
1111 const char *rvalue,
1112 void *data,
1113 void *userdata) {
1114
1115 ExecContext *c = data;
1116 int r;
1117
1118 assert(filename);
1119 assert(lvalue);
1120 assert(rvalue);
1121 assert(data);
1122
1123 if (isempty(rvalue)) {
1124 /* An empty assignment resets the field */
1125 c->secure_bits = 0;
1126 return 0;
1127 }
1128
1129 r = secure_bits_from_string(rvalue);
1130 if (r == -ENOMEM)
1131 return log_oom();
1132 if (r < 0) {
1133 log_syntax(unit, LOG_WARNING, filename, line, r,
1134 "Invalid syntax, ignoring: %s", rvalue);
1135 return 0;
1136 }
1137
1138 c->secure_bits = r;
1139
1140 return 0;
1141 }
1142
1143 int config_parse_capability_set(
1144 const char *unit,
1145 const char *filename,
1146 unsigned line,
1147 const char *section,
1148 unsigned section_line,
1149 const char *lvalue,
1150 int ltype,
1151 const char *rvalue,
1152 void *data,
1153 void *userdata) {
1154
1155 uint64_t *capability_set = data;
1156 uint64_t sum = 0, initial = 0;
1157 bool invert = false;
1158 int r;
1159
1160 assert(filename);
1161 assert(lvalue);
1162 assert(rvalue);
1163 assert(data);
1164
1165 if (rvalue[0] == '~') {
1166 invert = true;
1167 rvalue++;
1168 }
1169
1170 if (streq(lvalue, "CapabilityBoundingSet"))
1171 initial = CAP_ALL; /* initialized to all bits on */
1172 /* else "AmbientCapabilities" initialized to all bits off */
1173
1174 r = capability_set_from_string(rvalue, &sum);
1175 if (r == -ENOMEM)
1176 return log_oom();
1177 if (r < 0) {
1178 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word: %s", rvalue);
1179 return 0;
1180 }
1181
1182 if (sum == 0 || *capability_set == initial)
1183 /* "", "~" or uninitialized data -> replace */
1184 *capability_set = invert ? ~sum : sum;
1185 else {
1186 /* previous data -> merge */
1187 if (invert)
1188 *capability_set &= ~sum;
1189 else
1190 *capability_set |= sum;
1191 }
1192
1193 return 0;
1194 }
1195
1196 int config_parse_limit(
1197 const char *unit,
1198 const char *filename,
1199 unsigned line,
1200 const char *section,
1201 unsigned section_line,
1202 const char *lvalue,
1203 int ltype,
1204 const char *rvalue,
1205 void *data,
1206 void *userdata) {
1207
1208 struct rlimit **rl = data, d = {};
1209 int r;
1210
1211 assert(filename);
1212 assert(lvalue);
1213 assert(rvalue);
1214 assert(data);
1215
1216 r = rlimit_parse(ltype, rvalue, &d);
1217 if (r == -EILSEQ) {
1218 log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
1219 return 0;
1220 }
1221 if (r < 0) {
1222 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
1223 return 0;
1224 }
1225
1226 if (rl[ltype])
1227 *rl[ltype] = d;
1228 else {
1229 rl[ltype] = newdup(struct rlimit, &d, 1);
1230 if (!rl[ltype])
1231 return log_oom();
1232 }
1233
1234 return 0;
1235 }
1236
1237 #if HAVE_SYSV_COMPAT
1238 int config_parse_sysv_priority(const char *unit,
1239 const char *filename,
1240 unsigned line,
1241 const char *section,
1242 unsigned section_line,
1243 const char *lvalue,
1244 int ltype,
1245 const char *rvalue,
1246 void *data,
1247 void *userdata) {
1248
1249 int *priority = data;
1250 int i, r;
1251
1252 assert(filename);
1253 assert(lvalue);
1254 assert(rvalue);
1255 assert(data);
1256
1257 r = safe_atoi(rvalue, &i);
1258 if (r < 0 || i < 0) {
1259 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
1260 return 0;
1261 }
1262
1263 *priority = (int) i;
1264 return 0;
1265 }
1266 #endif
1267
1268 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
1269 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1270
1271 int config_parse_exec_mount_flags(
1272 const char *unit,
1273 const char *filename,
1274 unsigned line,
1275 const char *section,
1276 unsigned section_line,
1277 const char *lvalue,
1278 int ltype,
1279 const char *rvalue,
1280 void *data,
1281 void *userdata) {
1282
1283
1284 ExecContext *c = data;
1285 int r;
1286
1287 assert(filename);
1288 assert(lvalue);
1289 assert(rvalue);
1290 assert(data);
1291
1292 r = mount_propagation_flags_from_string(rvalue, &c->mount_flags);
1293 if (r < 0)
1294 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
1295
1296 return 0;
1297 }
1298
1299 int config_parse_exec_selinux_context(
1300 const char *unit,
1301 const char *filename,
1302 unsigned line,
1303 const char *section,
1304 unsigned section_line,
1305 const char *lvalue,
1306 int ltype,
1307 const char *rvalue,
1308 void *data,
1309 void *userdata) {
1310
1311 ExecContext *c = data;
1312 Unit *u = userdata;
1313 bool ignore;
1314 char *k;
1315 int r;
1316
1317 assert(filename);
1318 assert(lvalue);
1319 assert(rvalue);
1320 assert(data);
1321
1322 if (isempty(rvalue)) {
1323 c->selinux_context = mfree(c->selinux_context);
1324 c->selinux_context_ignore = false;
1325 return 0;
1326 }
1327
1328 if (rvalue[0] == '-') {
1329 ignore = true;
1330 rvalue++;
1331 } else
1332 ignore = false;
1333
1334 r = unit_full_printf(u, rvalue, &k);
1335 if (r < 0) {
1336 log_syntax(unit, LOG_ERR, filename, line, r,
1337 "Failed to resolve specifiers%s: %m",
1338 ignore ? ", ignoring" : "");
1339 return ignore ? 0 : -ENOEXEC;
1340 }
1341
1342 free(c->selinux_context);
1343 c->selinux_context = k;
1344 c->selinux_context_ignore = ignore;
1345
1346 return 0;
1347 }
1348
1349 int config_parse_exec_apparmor_profile(
1350 const char *unit,
1351 const char *filename,
1352 unsigned line,
1353 const char *section,
1354 unsigned section_line,
1355 const char *lvalue,
1356 int ltype,
1357 const char *rvalue,
1358 void *data,
1359 void *userdata) {
1360
1361 ExecContext *c = data;
1362 Unit *u = userdata;
1363 bool ignore;
1364 char *k;
1365 int r;
1366
1367 assert(filename);
1368 assert(lvalue);
1369 assert(rvalue);
1370 assert(data);
1371
1372 if (isempty(rvalue)) {
1373 c->apparmor_profile = mfree(c->apparmor_profile);
1374 c->apparmor_profile_ignore = false;
1375 return 0;
1376 }
1377
1378 if (rvalue[0] == '-') {
1379 ignore = true;
1380 rvalue++;
1381 } else
1382 ignore = false;
1383
1384 r = unit_full_printf(u, rvalue, &k);
1385 if (r < 0) {
1386 log_syntax(unit, LOG_ERR, filename, line, r,
1387 "Failed to resolve specifiers%s: %m",
1388 ignore ? ", ignoring" : "");
1389 return ignore ? 0 : -ENOEXEC;
1390 }
1391
1392 free(c->apparmor_profile);
1393 c->apparmor_profile = k;
1394 c->apparmor_profile_ignore = ignore;
1395
1396 return 0;
1397 }
1398
1399 int config_parse_exec_smack_process_label(
1400 const char *unit,
1401 const char *filename,
1402 unsigned line,
1403 const char *section,
1404 unsigned section_line,
1405 const char *lvalue,
1406 int ltype,
1407 const char *rvalue,
1408 void *data,
1409 void *userdata) {
1410
1411 ExecContext *c = data;
1412 Unit *u = userdata;
1413 bool ignore;
1414 char *k;
1415 int r;
1416
1417 assert(filename);
1418 assert(lvalue);
1419 assert(rvalue);
1420 assert(data);
1421
1422 if (isempty(rvalue)) {
1423 c->smack_process_label = mfree(c->smack_process_label);
1424 c->smack_process_label_ignore = false;
1425 return 0;
1426 }
1427
1428 if (rvalue[0] == '-') {
1429 ignore = true;
1430 rvalue++;
1431 } else
1432 ignore = false;
1433
1434 r = unit_full_printf(u, rvalue, &k);
1435 if (r < 0) {
1436 log_syntax(unit, LOG_ERR, filename, line, r,
1437 "Failed to resolve specifiers%s: %m",
1438 ignore ? ", ignoring" : "");
1439 return ignore ? 0 : -ENOEXEC;
1440 }
1441
1442 free(c->smack_process_label);
1443 c->smack_process_label = k;
1444 c->smack_process_label_ignore = ignore;
1445
1446 return 0;
1447 }
1448
1449 int config_parse_timer(const char *unit,
1450 const char *filename,
1451 unsigned line,
1452 const char *section,
1453 unsigned section_line,
1454 const char *lvalue,
1455 int ltype,
1456 const char *rvalue,
1457 void *data,
1458 void *userdata) {
1459
1460 Timer *t = data;
1461 usec_t usec = 0;
1462 TimerValue *v;
1463 TimerBase b;
1464 CalendarSpec *c = NULL;
1465 Unit *u = userdata;
1466 _cleanup_free_ char *k = NULL;
1467 int r;
1468
1469 assert(filename);
1470 assert(lvalue);
1471 assert(rvalue);
1472 assert(data);
1473
1474 if (isempty(rvalue)) {
1475 /* Empty assignment resets list */
1476 timer_free_values(t);
1477 return 0;
1478 }
1479
1480 b = timer_base_from_string(lvalue);
1481 if (b < 0) {
1482 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
1483 return 0;
1484 }
1485
1486 r = unit_full_printf(u, rvalue, &k);
1487 if (r < 0) {
1488 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
1489 return 0;
1490 }
1491
1492 if (b == TIMER_CALENDAR) {
1493 if (calendar_spec_from_string(k, &c) < 0) {
1494 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k);
1495 return 0;
1496 }
1497 } else {
1498 if (parse_sec(k, &usec) < 0) {
1499 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k);
1500 return 0;
1501 }
1502 }
1503
1504 v = new0(TimerValue, 1);
1505 if (!v) {
1506 calendar_spec_free(c);
1507 return log_oom();
1508 }
1509
1510 v->base = b;
1511 v->value = usec;
1512 v->calendar_spec = c;
1513
1514 LIST_PREPEND(value, t->values, v);
1515
1516 return 0;
1517 }
1518
1519 int config_parse_trigger_unit(
1520 const char *unit,
1521 const char *filename,
1522 unsigned line,
1523 const char *section,
1524 unsigned section_line,
1525 const char *lvalue,
1526 int ltype,
1527 const char *rvalue,
1528 void *data,
1529 void *userdata) {
1530
1531 _cleanup_free_ char *p = NULL;
1532 Unit *u = data;
1533 UnitType type;
1534 int r;
1535
1536 assert(filename);
1537 assert(lvalue);
1538 assert(rvalue);
1539 assert(data);
1540
1541 if (!hashmap_isempty(u->dependencies[UNIT_TRIGGERS])) {
1542 log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
1543 return 0;
1544 }
1545
1546 r = unit_name_printf(u, rvalue, &p);
1547 if (r < 0) {
1548 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1549 return 0;
1550 }
1551
1552 type = unit_name_to_type(p);
1553 if (type < 0) {
1554 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
1555 return 0;
1556 }
1557
1558 if (type == u->type) {
1559 log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
1560 return 0;
1561 }
1562
1563 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true, UNIT_DEPENDENCY_FILE);
1564 if (r < 0) {
1565 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
1566 return 0;
1567 }
1568
1569 return 0;
1570 }
1571
1572 int config_parse_path_spec(const char *unit,
1573 const char *filename,
1574 unsigned line,
1575 const char *section,
1576 unsigned section_line,
1577 const char *lvalue,
1578 int ltype,
1579 const char *rvalue,
1580 void *data,
1581 void *userdata) {
1582
1583 Path *p = data;
1584 PathSpec *s;
1585 PathType b;
1586 _cleanup_free_ char *k = NULL;
1587 int r;
1588
1589 assert(filename);
1590 assert(lvalue);
1591 assert(rvalue);
1592 assert(data);
1593
1594 if (isempty(rvalue)) {
1595 /* Empty assignment clears list */
1596 path_free_specs(p);
1597 return 0;
1598 }
1599
1600 b = path_type_from_string(lvalue);
1601 if (b < 0) {
1602 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
1603 return 0;
1604 }
1605
1606 r = unit_full_printf(UNIT(p), rvalue, &k);
1607 if (r < 0) {
1608 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1609 return 0;
1610 }
1611
1612 if (!path_is_absolute(k)) {
1613 log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
1614 return 0;
1615 }
1616
1617 s = new0(PathSpec, 1);
1618 if (!s)
1619 return log_oom();
1620
1621 s->unit = UNIT(p);
1622 s->path = path_kill_slashes(k);
1623 k = NULL;
1624 s->type = b;
1625 s->inotify_fd = -1;
1626
1627 LIST_PREPEND(spec, p->specs, s);
1628
1629 return 0;
1630 }
1631
1632 int config_parse_socket_service(
1633 const char *unit,
1634 const char *filename,
1635 unsigned line,
1636 const char *section,
1637 unsigned section_line,
1638 const char *lvalue,
1639 int ltype,
1640 const char *rvalue,
1641 void *data,
1642 void *userdata) {
1643
1644 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1645 _cleanup_free_ char *p = NULL;
1646 Socket *s = data;
1647 Unit *x;
1648 int r;
1649
1650 assert(filename);
1651 assert(lvalue);
1652 assert(rvalue);
1653 assert(data);
1654
1655 r = unit_name_printf(UNIT(s), rvalue, &p);
1656 if (r < 0) {
1657 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers: %s", rvalue);
1658 return -ENOEXEC;
1659 }
1660
1661 if (!endswith(p, ".service")) {
1662 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service: %s", rvalue);
1663 return -ENOEXEC;
1664 }
1665
1666 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1667 if (r < 0) {
1668 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s: %s", rvalue, bus_error_message(&error, r));
1669 return -ENOEXEC;
1670 }
1671
1672 unit_ref_set(&s->service, x);
1673
1674 return 0;
1675 }
1676
1677 int config_parse_fdname(
1678 const char *unit,
1679 const char *filename,
1680 unsigned line,
1681 const char *section,
1682 unsigned section_line,
1683 const char *lvalue,
1684 int ltype,
1685 const char *rvalue,
1686 void *data,
1687 void *userdata) {
1688
1689 _cleanup_free_ char *p = NULL;
1690 Socket *s = data;
1691 int r;
1692
1693 assert(filename);
1694 assert(lvalue);
1695 assert(rvalue);
1696 assert(data);
1697
1698 if (isempty(rvalue)) {
1699 s->fdname = mfree(s->fdname);
1700 return 0;
1701 }
1702
1703 r = unit_full_printf(UNIT(s), rvalue, &p);
1704 if (r < 0) {
1705 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1706 return 0;
1707 }
1708
1709 if (!fdname_is_valid(p)) {
1710 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
1711 return 0;
1712 }
1713
1714 return free_and_replace(s->fdname, p);
1715 }
1716
1717 int config_parse_service_sockets(
1718 const char *unit,
1719 const char *filename,
1720 unsigned line,
1721 const char *section,
1722 unsigned section_line,
1723 const char *lvalue,
1724 int ltype,
1725 const char *rvalue,
1726 void *data,
1727 void *userdata) {
1728
1729 Service *s = data;
1730 const char *p;
1731 int r;
1732
1733 assert(filename);
1734 assert(lvalue);
1735 assert(rvalue);
1736 assert(data);
1737
1738 p = rvalue;
1739 for (;;) {
1740 _cleanup_free_ char *word = NULL, *k = NULL;
1741
1742 r = extract_first_word(&p, &word, NULL, 0);
1743 if (r == 0)
1744 break;
1745 if (r == -ENOMEM)
1746 return log_oom();
1747 if (r < 0) {
1748 log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
1749 break;
1750 }
1751
1752 r = unit_name_printf(UNIT(s), word, &k);
1753 if (r < 0) {
1754 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1755 continue;
1756 }
1757
1758 if (!endswith(k, ".socket")) {
1759 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
1760 continue;
1761 }
1762
1763 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true, UNIT_DEPENDENCY_FILE);
1764 if (r < 0)
1765 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1766
1767 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true, UNIT_DEPENDENCY_FILE);
1768 if (r < 0)
1769 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1770 }
1771
1772 return 0;
1773 }
1774
1775 int config_parse_bus_name(
1776 const char *unit,
1777 const char *filename,
1778 unsigned line,
1779 const char *section,
1780 unsigned section_line,
1781 const char *lvalue,
1782 int ltype,
1783 const char *rvalue,
1784 void *data,
1785 void *userdata) {
1786
1787 _cleanup_free_ char *k = NULL;
1788 Unit *u = userdata;
1789 int r;
1790
1791 assert(filename);
1792 assert(lvalue);
1793 assert(rvalue);
1794 assert(u);
1795
1796 r = unit_full_printf(u, rvalue, &k);
1797 if (r < 0) {
1798 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1799 return 0;
1800 }
1801
1802 if (!service_name_is_valid(k)) {
1803 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
1804 return 0;
1805 }
1806
1807 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1808 }
1809
1810 int config_parse_service_timeout(
1811 const char *unit,
1812 const char *filename,
1813 unsigned line,
1814 const char *section,
1815 unsigned section_line,
1816 const char *lvalue,
1817 int ltype,
1818 const char *rvalue,
1819 void *data,
1820 void *userdata) {
1821
1822 Service *s = userdata;
1823 usec_t usec;
1824 int r;
1825
1826 assert(filename);
1827 assert(lvalue);
1828 assert(rvalue);
1829 assert(s);
1830
1831 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1832
1833 r = parse_sec(rvalue, &usec);
1834 if (r < 0) {
1835 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1836 return 0;
1837 }
1838
1839 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1840 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1841 * all other timeouts. */
1842 if (usec <= 0)
1843 usec = USEC_INFINITY;
1844
1845 if (!streq(lvalue, "TimeoutStopSec")) {
1846 s->start_timeout_defined = true;
1847 s->timeout_start_usec = usec;
1848 }
1849
1850 if (!streq(lvalue, "TimeoutStartSec"))
1851 s->timeout_stop_usec = usec;
1852
1853 return 0;
1854 }
1855
1856 int config_parse_sec_fix_0(
1857 const char *unit,
1858 const char *filename,
1859 unsigned line,
1860 const char *section,
1861 unsigned section_line,
1862 const char *lvalue,
1863 int ltype,
1864 const char *rvalue,
1865 void *data,
1866 void *userdata) {
1867
1868 usec_t *usec = data;
1869 int r;
1870
1871 assert(filename);
1872 assert(lvalue);
1873 assert(rvalue);
1874 assert(usec);
1875
1876 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1877 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1878 * timeout. */
1879
1880 r = parse_sec_fix_0(rvalue, usec);
1881 if (r < 0) {
1882 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
1883 return 0;
1884 }
1885
1886 return 0;
1887 }
1888
1889 int config_parse_user_group(
1890 const char *unit,
1891 const char *filename,
1892 unsigned line,
1893 const char *section,
1894 unsigned section_line,
1895 const char *lvalue,
1896 int ltype,
1897 const char *rvalue,
1898 void *data,
1899 void *userdata) {
1900
1901 char **user = data, *n;
1902 Unit *u = userdata;
1903 int r;
1904
1905 assert(filename);
1906 assert(lvalue);
1907 assert(rvalue);
1908 assert(u);
1909
1910 if (isempty(rvalue))
1911 n = NULL;
1912 else {
1913 _cleanup_free_ char *k = NULL;
1914
1915 r = unit_full_printf(u, rvalue, &k);
1916 if (r < 0) {
1917 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
1918 return -ENOEXEC;
1919 }
1920
1921 if (!valid_user_group_name_or_id(k)) {
1922 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
1923 return -ENOEXEC;
1924 }
1925
1926 n = k;
1927 k = NULL;
1928 }
1929
1930 free(*user);
1931 *user = n;
1932
1933 return 0;
1934 }
1935
1936 int config_parse_user_group_strv(
1937 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 ***users = data;
1949 Unit *u = userdata;
1950 const char *p;
1951 int r;
1952
1953 assert(filename);
1954 assert(lvalue);
1955 assert(rvalue);
1956 assert(u);
1957
1958 if (isempty(rvalue)) {
1959 *users = strv_free(*users);
1960 return 0;
1961 }
1962
1963 p = rvalue;
1964 for (;;) {
1965 _cleanup_free_ char *word = NULL, *k = NULL;
1966
1967 r = extract_first_word(&p, &word, NULL, 0);
1968 if (r == 0)
1969 break;
1970 if (r == -ENOMEM)
1971 return log_oom();
1972 if (r < 0) {
1973 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax: %s", rvalue);
1974 return -ENOEXEC;
1975 }
1976
1977 r = unit_full_printf(u, word, &k);
1978 if (r < 0) {
1979 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", word);
1980 return -ENOEXEC;
1981 }
1982
1983 if (!valid_user_group_name_or_id(k)) {
1984 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
1985 return -ENOEXEC;
1986 }
1987
1988 r = strv_push(users, k);
1989 if (r < 0)
1990 return log_oom();
1991
1992 k = NULL;
1993 }
1994
1995 return 0;
1996 }
1997
1998 int config_parse_working_directory(
1999 const char *unit,
2000 const char *filename,
2001 unsigned line,
2002 const char *section,
2003 unsigned section_line,
2004 const char *lvalue,
2005 int ltype,
2006 const char *rvalue,
2007 void *data,
2008 void *userdata) {
2009
2010 ExecContext *c = data;
2011 Unit *u = userdata;
2012 bool missing_ok;
2013 int r;
2014
2015 assert(filename);
2016 assert(lvalue);
2017 assert(rvalue);
2018 assert(c);
2019 assert(u);
2020
2021 if (rvalue[0] == '-') {
2022 missing_ok = true;
2023 rvalue++;
2024 } else
2025 missing_ok = false;
2026
2027 if (streq(rvalue, "~")) {
2028 c->working_directory_home = true;
2029 c->working_directory = mfree(c->working_directory);
2030 } else {
2031 _cleanup_free_ char *k = NULL;
2032
2033 r = unit_full_printf(u, rvalue, &k);
2034 if (r < 0) {
2035 log_syntax(unit, LOG_ERR, filename, line, r,
2036 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2037 rvalue, missing_ok ? ", ignoring" : "");
2038 return missing_ok ? 0 : -ENOEXEC;
2039 }
2040
2041 path_kill_slashes(k);
2042
2043 if (!utf8_is_valid(k)) {
2044 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
2045 return missing_ok ? 0 : -ENOEXEC;
2046 }
2047
2048 if (!path_is_absolute(k)) {
2049 log_syntax(unit, LOG_ERR, filename, line, 0,
2050 "Working directory path '%s' is not absolute%s.",
2051 rvalue, missing_ok ? ", ignoring" : "");
2052 return missing_ok ? 0 : -ENOEXEC;
2053 }
2054
2055 c->working_directory_home = false;
2056 free_and_replace(c->working_directory, k);
2057 }
2058
2059 c->working_directory_missing_ok = missing_ok;
2060 return 0;
2061 }
2062
2063 int config_parse_unit_env_file(const char *unit,
2064 const char *filename,
2065 unsigned line,
2066 const char *section,
2067 unsigned section_line,
2068 const char *lvalue,
2069 int ltype,
2070 const char *rvalue,
2071 void *data,
2072 void *userdata) {
2073
2074 char ***env = data;
2075 Unit *u = userdata;
2076 _cleanup_free_ char *n = NULL;
2077 int r;
2078
2079 assert(filename);
2080 assert(lvalue);
2081 assert(rvalue);
2082 assert(data);
2083
2084 if (isempty(rvalue)) {
2085 /* Empty assignment frees the list */
2086 *env = strv_free(*env);
2087 return 0;
2088 }
2089
2090 r = unit_full_printf(u, rvalue, &n);
2091 if (r < 0) {
2092 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2093 return 0;
2094 }
2095
2096 if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
2097 log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
2098 return 0;
2099 }
2100
2101 r = strv_extend(env, n);
2102 if (r < 0)
2103 return log_oom();
2104
2105 return 0;
2106 }
2107
2108 int config_parse_environ(
2109 const char *unit,
2110 const char *filename,
2111 unsigned line,
2112 const char *section,
2113 unsigned section_line,
2114 const char *lvalue,
2115 int ltype,
2116 const char *rvalue,
2117 void *data,
2118 void *userdata) {
2119
2120 Unit *u = userdata;
2121 char ***env = data;
2122 const char *p;
2123 int r;
2124
2125 assert(filename);
2126 assert(lvalue);
2127 assert(rvalue);
2128 assert(data);
2129
2130 if (isempty(rvalue)) {
2131 /* Empty assignment resets the list */
2132 *env = strv_free(*env);
2133 return 0;
2134 }
2135
2136 for (p = rvalue;; ) {
2137 _cleanup_free_ char *word = NULL, *k = NULL;
2138
2139 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
2140 if (r == 0)
2141 return 0;
2142 if (r == -ENOMEM)
2143 return log_oom();
2144 if (r < 0) {
2145 log_syntax(unit, LOG_WARNING, filename, line, r,
2146 "Invalid syntax, ignoring: %s", rvalue);
2147 return 0;
2148 }
2149
2150 if (u) {
2151 r = unit_full_printf(u, word, &k);
2152 if (r < 0) {
2153 log_syntax(unit, LOG_ERR, filename, line, r,
2154 "Failed to resolve specifiers, ignoring: %s", word);
2155 continue;
2156 }
2157 } else {
2158 k = word;
2159 word = NULL;
2160 }
2161
2162 if (!env_assignment_is_valid(k)) {
2163 log_syntax(unit, LOG_ERR, filename, line, 0,
2164 "Invalid environment assignment, ignoring: %s", k);
2165 continue;
2166 }
2167
2168 r = strv_env_replace(env, k);
2169 if (r < 0)
2170 return log_oom();
2171
2172 k = NULL;
2173 }
2174 }
2175
2176 int config_parse_pass_environ(
2177 const char *unit,
2178 const char *filename,
2179 unsigned line,
2180 const char *section,
2181 unsigned section_line,
2182 const char *lvalue,
2183 int ltype,
2184 const char *rvalue,
2185 void *data,
2186 void *userdata) {
2187
2188 const char *whole_rvalue = rvalue;
2189 _cleanup_strv_free_ char **n = NULL;
2190 size_t nlen = 0, nbufsize = 0;
2191 char*** passenv = data;
2192 Unit *u = userdata;
2193 int r;
2194
2195 assert(filename);
2196 assert(lvalue);
2197 assert(rvalue);
2198 assert(data);
2199
2200 if (isempty(rvalue)) {
2201 /* Empty assignment resets the list */
2202 *passenv = strv_free(*passenv);
2203 return 0;
2204 }
2205
2206 for (;;) {
2207 _cleanup_free_ char *word = NULL, *k = NULL;
2208
2209 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
2210 if (r == 0)
2211 break;
2212 if (r == -ENOMEM)
2213 return log_oom();
2214 if (r < 0) {
2215 log_syntax(unit, LOG_ERR, filename, line, r,
2216 "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
2217 break;
2218 }
2219
2220 if (u) {
2221 r = unit_full_printf(u, word, &k);
2222 if (r < 0) {
2223 log_syntax(unit, LOG_ERR, filename, line, r,
2224 "Failed to resolve specifiers, ignoring: %s", word);
2225 continue;
2226 }
2227 } else {
2228 k = word;
2229 word = NULL;
2230 }
2231
2232 if (!env_name_is_valid(k)) {
2233 log_syntax(unit, LOG_ERR, filename, line, 0,
2234 "Invalid environment name for %s, ignoring: %s", lvalue, k);
2235 continue;
2236 }
2237
2238 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2239 return log_oom();
2240
2241 n[nlen++] = k;
2242 n[nlen] = NULL;
2243 k = NULL;
2244 }
2245
2246 if (n) {
2247 r = strv_extend_strv(passenv, n, true);
2248 if (r < 0)
2249 return r;
2250 }
2251
2252 return 0;
2253 }
2254
2255 int config_parse_unset_environ(
2256 const char *unit,
2257 const char *filename,
2258 unsigned line,
2259 const char *section,
2260 unsigned section_line,
2261 const char *lvalue,
2262 int ltype,
2263 const char *rvalue,
2264 void *data,
2265 void *userdata) {
2266
2267 _cleanup_strv_free_ char **n = NULL;
2268 const char *whole_rvalue = rvalue;
2269 size_t nlen = 0, nbufsize = 0;
2270 char*** unsetenv = data;
2271 Unit *u = userdata;
2272 int r;
2273
2274 assert(filename);
2275 assert(lvalue);
2276 assert(rvalue);
2277 assert(data);
2278
2279 if (isempty(rvalue)) {
2280 /* Empty assignment resets the list */
2281 *unsetenv = strv_free(*unsetenv);
2282 return 0;
2283 }
2284
2285 for (;;) {
2286 _cleanup_free_ char *word = NULL, *k = NULL;
2287
2288 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
2289 if (r == 0)
2290 break;
2291 if (r == -ENOMEM)
2292 return log_oom();
2293 if (r < 0) {
2294 log_syntax(unit, LOG_ERR, filename, line, r,
2295 "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
2296 break;
2297 }
2298
2299 if (u) {
2300 r = unit_full_printf(u, word, &k);
2301 if (r < 0) {
2302 log_syntax(unit, LOG_ERR, filename, line, r,
2303 "Failed to resolve specifiers, ignoring: %s", word);
2304 continue;
2305 }
2306 } else {
2307 k = word;
2308 word = NULL;
2309 }
2310
2311 if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
2312 log_syntax(unit, LOG_ERR, filename, line, 0,
2313 "Invalid environment name or assignment %s, ignoring: %s", lvalue, k);
2314 continue;
2315 }
2316
2317 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
2318 return log_oom();
2319
2320 n[nlen++] = k;
2321 n[nlen] = NULL;
2322 k = NULL;
2323 }
2324
2325 if (n) {
2326 r = strv_extend_strv(unsetenv, n, true);
2327 if (r < 0)
2328 return r;
2329 }
2330
2331 return 0;
2332 }
2333
2334 int config_parse_ip_tos(const char *unit,
2335 const char *filename,
2336 unsigned line,
2337 const char *section,
2338 unsigned section_line,
2339 const char *lvalue,
2340 int ltype,
2341 const char *rvalue,
2342 void *data,
2343 void *userdata) {
2344
2345 int *ip_tos = data, x;
2346
2347 assert(filename);
2348 assert(lvalue);
2349 assert(rvalue);
2350 assert(data);
2351
2352 x = ip_tos_from_string(rvalue);
2353 if (x < 0) {
2354 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
2355 return 0;
2356 }
2357
2358 *ip_tos = x;
2359 return 0;
2360 }
2361
2362 int config_parse_unit_condition_path(
2363 const char *unit,
2364 const char *filename,
2365 unsigned line,
2366 const char *section,
2367 unsigned section_line,
2368 const char *lvalue,
2369 int ltype,
2370 const char *rvalue,
2371 void *data,
2372 void *userdata) {
2373
2374 _cleanup_free_ char *p = NULL;
2375 Condition **list = data, *c;
2376 ConditionType t = ltype;
2377 bool trigger, negate;
2378 Unit *u = userdata;
2379 int r;
2380
2381 assert(filename);
2382 assert(lvalue);
2383 assert(rvalue);
2384 assert(data);
2385
2386 if (isempty(rvalue)) {
2387 /* Empty assignment resets the list */
2388 *list = condition_free_list(*list);
2389 return 0;
2390 }
2391
2392 trigger = rvalue[0] == '|';
2393 if (trigger)
2394 rvalue++;
2395
2396 negate = rvalue[0] == '!';
2397 if (negate)
2398 rvalue++;
2399
2400 r = unit_full_printf(u, rvalue, &p);
2401 if (r < 0) {
2402 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2403 return 0;
2404 }
2405
2406 if (!path_is_absolute(p)) {
2407 log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
2408 return 0;
2409 }
2410
2411 c = condition_new(t, p, trigger, negate);
2412 if (!c)
2413 return log_oom();
2414
2415 LIST_PREPEND(conditions, *list, c);
2416 return 0;
2417 }
2418
2419 int config_parse_unit_condition_string(
2420 const char *unit,
2421 const char *filename,
2422 unsigned line,
2423 const char *section,
2424 unsigned section_line,
2425 const char *lvalue,
2426 int ltype,
2427 const char *rvalue,
2428 void *data,
2429 void *userdata) {
2430
2431 _cleanup_free_ char *s = NULL;
2432 Condition **list = data, *c;
2433 ConditionType t = ltype;
2434 bool trigger, negate;
2435 Unit *u = userdata;
2436 int r;
2437
2438 assert(filename);
2439 assert(lvalue);
2440 assert(rvalue);
2441 assert(data);
2442
2443 if (isempty(rvalue)) {
2444 /* Empty assignment resets the list */
2445 *list = condition_free_list(*list);
2446 return 0;
2447 }
2448
2449 trigger = rvalue[0] == '|';
2450 if (trigger)
2451 rvalue++;
2452
2453 negate = rvalue[0] == '!';
2454 if (negate)
2455 rvalue++;
2456
2457 r = unit_full_printf(u, rvalue, &s);
2458 if (r < 0) {
2459 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2460 return 0;
2461 }
2462
2463 c = condition_new(t, s, trigger, negate);
2464 if (!c)
2465 return log_oom();
2466
2467 LIST_PREPEND(conditions, *list, c);
2468 return 0;
2469 }
2470
2471 int config_parse_unit_condition_null(
2472 const char *unit,
2473 const char *filename,
2474 unsigned line,
2475 const char *section,
2476 unsigned section_line,
2477 const char *lvalue,
2478 int ltype,
2479 const char *rvalue,
2480 void *data,
2481 void *userdata) {
2482
2483 Condition **list = data, *c;
2484 bool trigger, negate;
2485 int b;
2486
2487 assert(filename);
2488 assert(lvalue);
2489 assert(rvalue);
2490 assert(data);
2491
2492 if (isempty(rvalue)) {
2493 /* Empty assignment resets the list */
2494 *list = condition_free_list(*list);
2495 return 0;
2496 }
2497
2498 trigger = rvalue[0] == '|';
2499 if (trigger)
2500 rvalue++;
2501
2502 negate = rvalue[0] == '!';
2503 if (negate)
2504 rvalue++;
2505
2506 b = parse_boolean(rvalue);
2507 if (b < 0) {
2508 log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2509 return 0;
2510 }
2511
2512 if (!b)
2513 negate = !negate;
2514
2515 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2516 if (!c)
2517 return log_oom();
2518
2519 LIST_PREPEND(conditions, *list, c);
2520 return 0;
2521 }
2522
2523 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2524 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier");
2525
2526 int config_parse_unit_requires_mounts_for(
2527 const char *unit,
2528 const char *filename,
2529 unsigned line,
2530 const char *section,
2531 unsigned section_line,
2532 const char *lvalue,
2533 int ltype,
2534 const char *rvalue,
2535 void *data,
2536 void *userdata) {
2537
2538 Unit *u = userdata;
2539 const char *p;
2540 int r;
2541
2542 assert(filename);
2543 assert(lvalue);
2544 assert(rvalue);
2545 assert(data);
2546
2547 for (p = rvalue;; ) {
2548 _cleanup_free_ char *word = NULL, *resolved = NULL;
2549
2550 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
2551 if (r == 0)
2552 return 0;
2553 if (r == -ENOMEM)
2554 return log_oom();
2555 if (r < 0) {
2556 log_syntax(unit, LOG_WARNING, filename, line, r,
2557 "Invalid syntax, ignoring: %s", rvalue);
2558 return 0;
2559 }
2560
2561 if (!utf8_is_valid(word)) {
2562 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
2563 continue;
2564 }
2565
2566 r = unit_full_printf(u, word, &resolved);
2567 if (r < 0) {
2568 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit name \"%s\", ignoring: %m", word);
2569 continue;
2570 }
2571
2572 r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
2573 if (r < 0) {
2574 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", resolved);
2575 continue;
2576 }
2577 }
2578 }
2579
2580 int config_parse_documentation(const char *unit,
2581 const char *filename,
2582 unsigned line,
2583 const char *section,
2584 unsigned section_line,
2585 const char *lvalue,
2586 int ltype,
2587 const char *rvalue,
2588 void *data,
2589 void *userdata) {
2590
2591 Unit *u = userdata;
2592 int r;
2593 char **a, **b;
2594
2595 assert(filename);
2596 assert(lvalue);
2597 assert(rvalue);
2598 assert(u);
2599
2600 if (isempty(rvalue)) {
2601 /* Empty assignment resets the list */
2602 u->documentation = strv_free(u->documentation);
2603 return 0;
2604 }
2605
2606 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2607 rvalue, data, userdata);
2608 if (r < 0)
2609 return r;
2610
2611 for (a = b = u->documentation; a && *a; a++) {
2612
2613 if (documentation_url_is_valid(*a))
2614 *(b++) = *a;
2615 else {
2616 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
2617 free(*a);
2618 }
2619 }
2620 if (b)
2621 *b = NULL;
2622
2623 return r;
2624 }
2625
2626 #if HAVE_SECCOMP
2627
2628 static int syscall_filter_parse_one(
2629 const char *unit,
2630 const char *filename,
2631 unsigned line,
2632 ExecContext *c,
2633 bool invert,
2634 const char *t,
2635 bool warn,
2636 int errno_num) {
2637 int r;
2638
2639 if (t[0] == '@') {
2640 const SyscallFilterSet *set;
2641 const char *i;
2642
2643 set = syscall_filter_set_find(t);
2644 if (!set) {
2645 if (warn)
2646 log_syntax(unit, LOG_WARNING, filename, line, 0, "Don't know system call group, ignoring: %s", t);
2647 return 0;
2648 }
2649
2650 NULSTR_FOREACH(i, set->value) {
2651 r = syscall_filter_parse_one(unit, filename, line, c, invert, i, false, errno_num);
2652 if (r < 0)
2653 return r;
2654 }
2655 } else {
2656 int id;
2657
2658 id = seccomp_syscall_resolve_name(t);
2659 if (id == __NR_SCMP_ERROR) {
2660 if (warn)
2661 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
2662 return 0;
2663 }
2664
2665 /* If we previously wanted to forbid a syscall and now
2666 * we want to allow it, then remove it from the list
2667 */
2668 if (!invert == c->syscall_whitelist) {
2669 r = hashmap_put(c->syscall_filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
2670 if (r == 0)
2671 return 0;
2672 if (r < 0)
2673 return log_oom();
2674 } else
2675 (void) hashmap_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2676 }
2677
2678 return 0;
2679 }
2680
2681 int config_parse_syscall_filter(
2682 const char *unit,
2683 const char *filename,
2684 unsigned line,
2685 const char *section,
2686 unsigned section_line,
2687 const char *lvalue,
2688 int ltype,
2689 const char *rvalue,
2690 void *data,
2691 void *userdata) {
2692
2693 ExecContext *c = data;
2694 Unit *u = userdata;
2695 bool invert = false;
2696 const char *p;
2697 int r;
2698
2699 assert(filename);
2700 assert(lvalue);
2701 assert(rvalue);
2702 assert(u);
2703
2704 if (isempty(rvalue)) {
2705 /* Empty assignment resets the list */
2706 c->syscall_filter = hashmap_free(c->syscall_filter);
2707 c->syscall_whitelist = false;
2708 return 0;
2709 }
2710
2711 if (rvalue[0] == '~') {
2712 invert = true;
2713 rvalue++;
2714 }
2715
2716 if (!c->syscall_filter) {
2717 c->syscall_filter = hashmap_new(NULL);
2718 if (!c->syscall_filter)
2719 return log_oom();
2720
2721 if (invert)
2722 /* Allow everything but the ones listed */
2723 c->syscall_whitelist = false;
2724 else {
2725 /* Allow nothing but the ones listed */
2726 c->syscall_whitelist = true;
2727
2728 /* Accept default syscalls if we are on a whitelist */
2729 r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false, -1);
2730 if (r < 0)
2731 return r;
2732 }
2733 }
2734
2735 p = rvalue;
2736 for (;;) {
2737 _cleanup_free_ char *word = NULL, *name = NULL;
2738 int num;
2739
2740 r = extract_first_word(&p, &word, NULL, 0);
2741 if (r == 0)
2742 break;
2743 if (r == -ENOMEM)
2744 return log_oom();
2745 if (r < 0) {
2746 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
2747 break;
2748 }
2749
2750 r = parse_syscall_and_errno(word, &name, &num);
2751 if (r < 0) {
2752 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall:errno, ignoring: %s", word);
2753 continue;
2754 }
2755
2756 r = syscall_filter_parse_one(unit, filename, line, c, invert, name, true, num);
2757 if (r < 0)
2758 return r;
2759 }
2760
2761 return 0;
2762 }
2763
2764 int config_parse_syscall_archs(
2765 const char *unit,
2766 const char *filename,
2767 unsigned line,
2768 const char *section,
2769 unsigned section_line,
2770 const char *lvalue,
2771 int ltype,
2772 const char *rvalue,
2773 void *data,
2774 void *userdata) {
2775
2776 Set **archs = data;
2777 const char *p;
2778 int r;
2779
2780 if (isempty(rvalue)) {
2781 *archs = set_free(*archs);
2782 return 0;
2783 }
2784
2785 r = set_ensure_allocated(archs, NULL);
2786 if (r < 0)
2787 return log_oom();
2788
2789 for (p = rvalue;;) {
2790 _cleanup_free_ char *word = NULL;
2791 uint32_t a;
2792
2793 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
2794 if (r == 0)
2795 return 0;
2796 if (r == -ENOMEM)
2797 return log_oom();
2798 if (r < 0) {
2799 log_syntax(unit, LOG_WARNING, filename, line, r,
2800 "Invalid syntax, ignoring: %s", rvalue);
2801 return 0;
2802 }
2803
2804 r = seccomp_arch_from_string(word, &a);
2805 if (r < 0) {
2806 log_syntax(unit, LOG_ERR, filename, line, r,
2807 "Failed to parse system call architecture \"%s\", ignoring: %m", word);
2808 continue;
2809 }
2810
2811 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2812 if (r < 0)
2813 return log_oom();
2814 }
2815 }
2816
2817 int config_parse_syscall_errno(
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 ExecContext *c = data;
2830 int e;
2831
2832 assert(filename);
2833 assert(lvalue);
2834 assert(rvalue);
2835
2836 if (isempty(rvalue)) {
2837 /* Empty assignment resets to KILL */
2838 c->syscall_errno = 0;
2839 return 0;
2840 }
2841
2842 e = parse_errno(rvalue);
2843 if (e <= 0) {
2844 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
2845 return 0;
2846 }
2847
2848 c->syscall_errno = e;
2849 return 0;
2850 }
2851
2852 int config_parse_address_families(
2853 const char *unit,
2854 const char *filename,
2855 unsigned line,
2856 const char *section,
2857 unsigned section_line,
2858 const char *lvalue,
2859 int ltype,
2860 const char *rvalue,
2861 void *data,
2862 void *userdata) {
2863
2864 ExecContext *c = data;
2865 bool invert = false;
2866 const char *p;
2867 int r;
2868
2869 assert(filename);
2870 assert(lvalue);
2871 assert(rvalue);
2872
2873 if (isempty(rvalue)) {
2874 /* Empty assignment resets the list */
2875 c->address_families = set_free(c->address_families);
2876 c->address_families_whitelist = false;
2877 return 0;
2878 }
2879
2880 if (rvalue[0] == '~') {
2881 invert = true;
2882 rvalue++;
2883 }
2884
2885 if (!c->address_families) {
2886 c->address_families = set_new(NULL);
2887 if (!c->address_families)
2888 return log_oom();
2889
2890 c->address_families_whitelist = !invert;
2891 }
2892
2893 for (p = rvalue;;) {
2894 _cleanup_free_ char *word = NULL;
2895 int af;
2896
2897 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
2898 if (r == 0)
2899 return 0;
2900 if (r == -ENOMEM)
2901 return log_oom();
2902 if (r < 0) {
2903 log_syntax(unit, LOG_WARNING, filename, line, r,
2904 "Invalid syntax, ignoring: %s", rvalue);
2905 return 0;
2906 }
2907
2908 af = af_from_name(word);
2909 if (af <= 0) {
2910 log_syntax(unit, LOG_ERR, filename, line, 0,
2911 "Failed to parse address family \"%s\", ignoring: %m", word);
2912 continue;
2913 }
2914
2915 /* If we previously wanted to forbid an address family and now
2916 * we want to allow it, then just remove it from the list.
2917 */
2918 if (!invert == c->address_families_whitelist) {
2919 r = set_put(c->address_families, INT_TO_PTR(af));
2920 if (r < 0)
2921 return log_oom();
2922 } else
2923 set_remove(c->address_families, INT_TO_PTR(af));
2924 }
2925 }
2926
2927 int config_parse_restrict_namespaces(
2928 const char *unit,
2929 const char *filename,
2930 unsigned line,
2931 const char *section,
2932 unsigned section_line,
2933 const char *lvalue,
2934 int ltype,
2935 const char *rvalue,
2936 void *data,
2937 void *userdata) {
2938
2939 ExecContext *c = data;
2940 bool invert = false;
2941 int r;
2942
2943 if (isempty(rvalue)) {
2944 /* Reset to the default. */
2945 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
2946 return 0;
2947 }
2948
2949 if (rvalue[0] == '~') {
2950 invert = true;
2951 rvalue++;
2952 }
2953
2954 r = parse_boolean(rvalue);
2955 if (r > 0)
2956 c->restrict_namespaces = 0;
2957 else if (r == 0)
2958 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
2959 else {
2960 /* Not a boolean argument, in this case it's a list of namespace types. */
2961
2962 r = namespace_flag_from_string_many(rvalue, &c->restrict_namespaces);
2963 if (r < 0) {
2964 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
2965 return 0;
2966 }
2967 }
2968
2969 if (invert)
2970 c->restrict_namespaces = (~c->restrict_namespaces) & NAMESPACE_FLAGS_ALL;
2971
2972 return 0;
2973 }
2974 #endif
2975
2976 int config_parse_unit_slice(
2977 const char *unit,
2978 const char *filename,
2979 unsigned line,
2980 const char *section,
2981 unsigned section_line,
2982 const char *lvalue,
2983 int ltype,
2984 const char *rvalue,
2985 void *data,
2986 void *userdata) {
2987
2988 _cleanup_free_ char *k = NULL;
2989 Unit *u = userdata, *slice = NULL;
2990 int r;
2991
2992 assert(filename);
2993 assert(lvalue);
2994 assert(rvalue);
2995 assert(u);
2996
2997 r = unit_name_printf(u, rvalue, &k);
2998 if (r < 0) {
2999 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
3000 return 0;
3001 }
3002
3003 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
3004 if (r < 0) {
3005 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
3006 return 0;
3007 }
3008
3009 r = unit_set_slice(u, slice);
3010 if (r < 0) {
3011 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
3012 return 0;
3013 }
3014
3015 return 0;
3016 }
3017
3018 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
3019
3020 int config_parse_cpu_weight(
3021 const char *unit,
3022 const char *filename,
3023 unsigned line,
3024 const char *section,
3025 unsigned section_line,
3026 const char *lvalue,
3027 int ltype,
3028 const char *rvalue,
3029 void *data,
3030 void *userdata) {
3031
3032 uint64_t *weight = data;
3033 int r;
3034
3035 assert(filename);
3036 assert(lvalue);
3037 assert(rvalue);
3038
3039 r = cg_weight_parse(rvalue, weight);
3040 if (r < 0) {
3041 log_syntax(unit, LOG_ERR, filename, line, r, "CPU weight '%s' invalid. Ignoring.", rvalue);
3042 return 0;
3043 }
3044
3045 return 0;
3046 }
3047
3048 int config_parse_cpu_shares(
3049 const char *unit,
3050 const char *filename,
3051 unsigned line,
3052 const char *section,
3053 unsigned section_line,
3054 const char *lvalue,
3055 int ltype,
3056 const char *rvalue,
3057 void *data,
3058 void *userdata) {
3059
3060 uint64_t *shares = data;
3061 int r;
3062
3063 assert(filename);
3064 assert(lvalue);
3065 assert(rvalue);
3066
3067 r = cg_cpu_shares_parse(rvalue, shares);
3068 if (r < 0) {
3069 log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
3070 return 0;
3071 }
3072
3073 return 0;
3074 }
3075
3076 int config_parse_cpu_quota(
3077 const char *unit,
3078 const char *filename,
3079 unsigned line,
3080 const char *section,
3081 unsigned section_line,
3082 const char *lvalue,
3083 int ltype,
3084 const char *rvalue,
3085 void *data,
3086 void *userdata) {
3087
3088 CGroupContext *c = data;
3089 int r;
3090
3091 assert(filename);
3092 assert(lvalue);
3093 assert(rvalue);
3094
3095 if (isempty(rvalue)) {
3096 c->cpu_quota_per_sec_usec = USEC_INFINITY;
3097 return 0;
3098 }
3099
3100 r = parse_percent_unbounded(rvalue);
3101 if (r <= 0) {
3102 log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
3103 return 0;
3104 }
3105
3106 c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
3107 return 0;
3108 }
3109
3110 int config_parse_memory_limit(
3111 const char *unit,
3112 const char *filename,
3113 unsigned line,
3114 const char *section,
3115 unsigned section_line,
3116 const char *lvalue,
3117 int ltype,
3118 const char *rvalue,
3119 void *data,
3120 void *userdata) {
3121
3122 CGroupContext *c = data;
3123 uint64_t bytes = CGROUP_LIMIT_MAX;
3124 int r;
3125
3126 if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
3127
3128 r = parse_percent(rvalue);
3129 if (r < 0) {
3130 r = parse_size(rvalue, 1024, &bytes);
3131 if (r < 0) {
3132 log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
3133 return 0;
3134 }
3135 } else
3136 bytes = physical_memory_scale(r, 100U);
3137
3138 if (bytes <= 0 || bytes >= UINT64_MAX) {
3139 log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
3140 return 0;
3141 }
3142 }
3143
3144 if (streq(lvalue, "MemoryLow"))
3145 c->memory_low = bytes;
3146 else if (streq(lvalue, "MemoryHigh"))
3147 c->memory_high = bytes;
3148 else if (streq(lvalue, "MemoryMax"))
3149 c->memory_max = bytes;
3150 else if (streq(lvalue, "MemorySwapMax"))
3151 c->memory_swap_max = bytes;
3152 else if (streq(lvalue, "MemoryLimit"))
3153 c->memory_limit = bytes;
3154 else
3155 return -EINVAL;
3156
3157 return 0;
3158 }
3159
3160 int config_parse_tasks_max(
3161 const char *unit,
3162 const char *filename,
3163 unsigned line,
3164 const char *section,
3165 unsigned section_line,
3166 const char *lvalue,
3167 int ltype,
3168 const char *rvalue,
3169 void *data,
3170 void *userdata) {
3171
3172 uint64_t *tasks_max = data, v;
3173 Unit *u = userdata;
3174 int r;
3175
3176 if (isempty(rvalue)) {
3177 *tasks_max = u->manager->default_tasks_max;
3178 return 0;
3179 }
3180
3181 if (streq(rvalue, "infinity")) {
3182 *tasks_max = CGROUP_LIMIT_MAX;
3183 return 0;
3184 }
3185
3186 r = parse_percent(rvalue);
3187 if (r < 0) {
3188 r = safe_atou64(rvalue, &v);
3189 if (r < 0) {
3190 log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
3191 return 0;
3192 }
3193 } else
3194 v = system_tasks_max_scale(r, 100U);
3195
3196 if (v <= 0 || v >= UINT64_MAX) {
3197 log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
3198 return 0;
3199 }
3200
3201 *tasks_max = v;
3202 return 0;
3203 }
3204
3205 int config_parse_device_allow(
3206 const char *unit,
3207 const char *filename,
3208 unsigned line,
3209 const char *section,
3210 unsigned section_line,
3211 const char *lvalue,
3212 int ltype,
3213 const char *rvalue,
3214 void *data,
3215 void *userdata) {
3216
3217 _cleanup_free_ char *path = NULL, *t = NULL;
3218 CGroupContext *c = data;
3219 CGroupDeviceAllow *a;
3220 const char *m = NULL;
3221 size_t n;
3222 int r;
3223
3224 if (isempty(rvalue)) {
3225 while (c->device_allow)
3226 cgroup_context_free_device_allow(c, c->device_allow);
3227
3228 return 0;
3229 }
3230
3231 r = unit_full_printf(userdata, rvalue, &t);
3232 if(r < 0) {
3233 log_syntax(unit, LOG_WARNING, filename, line, r,
3234 "Failed to resolve specifiers in %s, ignoring: %m",
3235 rvalue);
3236 }
3237
3238 n = strcspn(t, WHITESPACE);
3239
3240 path = strndup(t, n);
3241 if (!path)
3242 return log_oom();
3243
3244 if (!is_deviceallow_pattern(path)) {
3245 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3246 return 0;
3247 }
3248
3249 m = t + n + strspn(t + n, WHITESPACE);
3250 if (isempty(m))
3251 m = "rwm";
3252
3253 if (!in_charset(m, "rwm")) {
3254 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
3255 return 0;
3256 }
3257
3258 a = new0(CGroupDeviceAllow, 1);
3259 if (!a)
3260 return log_oom();
3261
3262 a->path = path;
3263 path = NULL;
3264 a->r = !!strchr(m, 'r');
3265 a->w = !!strchr(m, 'w');
3266 a->m = !!strchr(m, 'm');
3267
3268 LIST_PREPEND(device_allow, c->device_allow, a);
3269 return 0;
3270 }
3271
3272 int config_parse_io_weight(
3273 const char *unit,
3274 const char *filename,
3275 unsigned line,
3276 const char *section,
3277 unsigned section_line,
3278 const char *lvalue,
3279 int ltype,
3280 const char *rvalue,
3281 void *data,
3282 void *userdata) {
3283
3284 uint64_t *weight = data;
3285 int r;
3286
3287 assert(filename);
3288 assert(lvalue);
3289 assert(rvalue);
3290
3291 r = cg_weight_parse(rvalue, weight);
3292 if (r < 0) {
3293 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
3294 return 0;
3295 }
3296
3297 return 0;
3298 }
3299
3300 int config_parse_io_device_weight(
3301 const char *unit,
3302 const char *filename,
3303 unsigned line,
3304 const char *section,
3305 unsigned section_line,
3306 const char *lvalue,
3307 int ltype,
3308 const char *rvalue,
3309 void *data,
3310 void *userdata) {
3311
3312 _cleanup_free_ char *path = NULL;
3313 CGroupIODeviceWeight *w;
3314 CGroupContext *c = data;
3315 const char *weight;
3316 uint64_t u;
3317 size_t n;
3318 int r;
3319
3320 assert(filename);
3321 assert(lvalue);
3322 assert(rvalue);
3323
3324 if (isempty(rvalue)) {
3325 while (c->io_device_weights)
3326 cgroup_context_free_io_device_weight(c, c->io_device_weights);
3327
3328 return 0;
3329 }
3330
3331 n = strcspn(rvalue, WHITESPACE);
3332 weight = rvalue + n;
3333 weight += strspn(weight, WHITESPACE);
3334
3335 if (isempty(weight)) {
3336 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3337 return 0;
3338 }
3339
3340 path = strndup(rvalue, n);
3341 if (!path)
3342 return log_oom();
3343
3344 if (!path_startswith(path, "/dev")) {
3345 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3346 return 0;
3347 }
3348
3349 r = cg_weight_parse(weight, &u);
3350 if (r < 0) {
3351 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
3352 return 0;
3353 }
3354
3355 assert(u != CGROUP_WEIGHT_INVALID);
3356
3357 w = new0(CGroupIODeviceWeight, 1);
3358 if (!w)
3359 return log_oom();
3360
3361 w->path = path;
3362 path = NULL;
3363
3364 w->weight = u;
3365
3366 LIST_PREPEND(device_weights, c->io_device_weights, w);
3367 return 0;
3368 }
3369
3370 int config_parse_io_limit(
3371 const char *unit,
3372 const char *filename,
3373 unsigned line,
3374 const char *section,
3375 unsigned section_line,
3376 const char *lvalue,
3377 int ltype,
3378 const char *rvalue,
3379 void *data,
3380 void *userdata) {
3381
3382 _cleanup_free_ char *path = NULL;
3383 CGroupIODeviceLimit *l = NULL, *t;
3384 CGroupContext *c = data;
3385 CGroupIOLimitType type;
3386 const char *limit;
3387 uint64_t num;
3388 size_t n;
3389 int r;
3390
3391 assert(filename);
3392 assert(lvalue);
3393 assert(rvalue);
3394
3395 type = cgroup_io_limit_type_from_string(lvalue);
3396 assert(type >= 0);
3397
3398 if (isempty(rvalue)) {
3399 LIST_FOREACH(device_limits, l, c->io_device_limits)
3400 l->limits[type] = cgroup_io_limit_defaults[type];
3401 return 0;
3402 }
3403
3404 n = strcspn(rvalue, WHITESPACE);
3405 limit = rvalue + n;
3406 limit += strspn(limit, WHITESPACE);
3407
3408 if (!*limit) {
3409 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3410 return 0;
3411 }
3412
3413 path = strndup(rvalue, n);
3414 if (!path)
3415 return log_oom();
3416
3417 if (!path_startswith(path, "/dev")) {
3418 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3419 return 0;
3420 }
3421
3422 if (streq("infinity", limit)) {
3423 num = CGROUP_LIMIT_MAX;
3424 } else {
3425 r = parse_size(limit, 1000, &num);
3426 if (r < 0 || num <= 0) {
3427 log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
3428 return 0;
3429 }
3430 }
3431
3432 LIST_FOREACH(device_limits, t, c->io_device_limits) {
3433 if (path_equal(path, t->path)) {
3434 l = t;
3435 break;
3436 }
3437 }
3438
3439 if (!l) {
3440 CGroupIOLimitType ttype;
3441
3442 l = new0(CGroupIODeviceLimit, 1);
3443 if (!l)
3444 return log_oom();
3445
3446 l->path = path;
3447 path = NULL;
3448 for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
3449 l->limits[ttype] = cgroup_io_limit_defaults[ttype];
3450
3451 LIST_PREPEND(device_limits, c->io_device_limits, l);
3452 }
3453
3454 l->limits[type] = num;
3455
3456 return 0;
3457 }
3458
3459 int config_parse_blockio_weight(
3460 const char *unit,
3461 const char *filename,
3462 unsigned line,
3463 const char *section,
3464 unsigned section_line,
3465 const char *lvalue,
3466 int ltype,
3467 const char *rvalue,
3468 void *data,
3469 void *userdata) {
3470
3471 uint64_t *weight = data;
3472 int r;
3473
3474 assert(filename);
3475 assert(lvalue);
3476 assert(rvalue);
3477
3478 r = cg_blkio_weight_parse(rvalue, weight);
3479 if (r < 0) {
3480 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
3481 return 0;
3482 }
3483
3484 return 0;
3485 }
3486
3487 int config_parse_blockio_device_weight(
3488 const char *unit,
3489 const char *filename,
3490 unsigned line,
3491 const char *section,
3492 unsigned section_line,
3493 const char *lvalue,
3494 int ltype,
3495 const char *rvalue,
3496 void *data,
3497 void *userdata) {
3498
3499 _cleanup_free_ char *path = NULL;
3500 CGroupBlockIODeviceWeight *w;
3501 CGroupContext *c = data;
3502 const char *weight;
3503 uint64_t u;
3504 size_t n;
3505 int r;
3506
3507 assert(filename);
3508 assert(lvalue);
3509 assert(rvalue);
3510
3511 if (isempty(rvalue)) {
3512 while (c->blockio_device_weights)
3513 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3514
3515 return 0;
3516 }
3517
3518 n = strcspn(rvalue, WHITESPACE);
3519 weight = rvalue + n;
3520 weight += strspn(weight, WHITESPACE);
3521
3522 if (isempty(weight)) {
3523 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3524 return 0;
3525 }
3526
3527 path = strndup(rvalue, n);
3528 if (!path)
3529 return log_oom();
3530
3531 if (!path_startswith(path, "/dev")) {
3532 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3533 return 0;
3534 }
3535
3536 r = cg_blkio_weight_parse(weight, &u);
3537 if (r < 0) {
3538 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
3539 return 0;
3540 }
3541
3542 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3543
3544 w = new0(CGroupBlockIODeviceWeight, 1);
3545 if (!w)
3546 return log_oom();
3547
3548 w->path = path;
3549 path = NULL;
3550
3551 w->weight = u;
3552
3553 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
3554 return 0;
3555 }
3556
3557 int config_parse_blockio_bandwidth(
3558 const char *unit,
3559 const char *filename,
3560 unsigned line,
3561 const char *section,
3562 unsigned section_line,
3563 const char *lvalue,
3564 int ltype,
3565 const char *rvalue,
3566 void *data,
3567 void *userdata) {
3568
3569 _cleanup_free_ char *path = NULL;
3570 CGroupBlockIODeviceBandwidth *b = NULL, *t;
3571 CGroupContext *c = data;
3572 const char *bandwidth;
3573 uint64_t bytes;
3574 bool read;
3575 size_t n;
3576 int r;
3577
3578 assert(filename);
3579 assert(lvalue);
3580 assert(rvalue);
3581
3582 read = streq("BlockIOReadBandwidth", lvalue);
3583
3584 if (isempty(rvalue)) {
3585 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
3586 b->rbps = CGROUP_LIMIT_MAX;
3587 b->wbps = CGROUP_LIMIT_MAX;
3588 }
3589 return 0;
3590 }
3591
3592 n = strcspn(rvalue, WHITESPACE);
3593 bandwidth = rvalue + n;
3594 bandwidth += strspn(bandwidth, WHITESPACE);
3595
3596 if (!*bandwidth) {
3597 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3598 return 0;
3599 }
3600
3601 path = strndup(rvalue, n);
3602 if (!path)
3603 return log_oom();
3604
3605 if (!path_startswith(path, "/dev")) {
3606 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3607 return 0;
3608 }
3609
3610 r = parse_size(bandwidth, 1000, &bytes);
3611 if (r < 0 || bytes <= 0) {
3612 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
3613 return 0;
3614 }
3615
3616 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
3617 if (path_equal(path, t->path)) {
3618 b = t;
3619 break;
3620 }
3621 }
3622
3623 if (!t) {
3624 b = new0(CGroupBlockIODeviceBandwidth, 1);
3625 if (!b)
3626 return log_oom();
3627
3628 b->path = path;
3629 path = NULL;
3630 b->rbps = CGROUP_LIMIT_MAX;
3631 b->wbps = CGROUP_LIMIT_MAX;
3632
3633 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3634 }
3635
3636 if (read)
3637 b->rbps = bytes;
3638 else
3639 b->wbps = bytes;
3640
3641 return 0;
3642 }
3643
3644 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3645
3646 int config_parse_job_mode_isolate(
3647 const char *unit,
3648 const char *filename,
3649 unsigned line,
3650 const char *section,
3651 unsigned section_line,
3652 const char *lvalue,
3653 int ltype,
3654 const char *rvalue,
3655 void *data,
3656 void *userdata) {
3657
3658 JobMode *m = data;
3659 int r;
3660
3661 assert(filename);
3662 assert(lvalue);
3663 assert(rvalue);
3664
3665 r = parse_boolean(rvalue);
3666 if (r < 0) {
3667 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
3668 return 0;
3669 }
3670
3671 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3672 return 0;
3673 }
3674
3675 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
3676
3677 int config_parse_exec_directories(
3678 const char *unit,
3679 const char *filename,
3680 unsigned line,
3681 const char *section,
3682 unsigned section_line,
3683 const char *lvalue,
3684 int ltype,
3685 const char *rvalue,
3686 void *data,
3687 void *userdata) {
3688
3689 char***rt = data;
3690 Unit *u = userdata;
3691 const char *p;
3692 int r;
3693
3694 assert(filename);
3695 assert(lvalue);
3696 assert(rvalue);
3697 assert(data);
3698
3699 if (isempty(rvalue)) {
3700 /* Empty assignment resets the list */
3701 *rt = strv_free(*rt);
3702 return 0;
3703 }
3704
3705 for (p = rvalue;;) {
3706 _cleanup_free_ char *word = NULL, *k = NULL;
3707
3708 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3709 if (r == -ENOMEM)
3710 return log_oom();
3711 if (r < 0) {
3712 log_syntax(unit, LOG_WARNING, filename, line, r,
3713 "Invalid syntax, ignoring: %s", rvalue);
3714 return 0;
3715 }
3716 if (r == 0)
3717 return 0;
3718
3719 r = unit_full_printf(u, word, &k);
3720 if (r < 0) {
3721 log_syntax(unit, LOG_ERR, filename, line, r,
3722 "Failed to resolve specifiers in \"%s\", ignoring: %m", word);
3723 continue;
3724 }
3725
3726 if (!path_is_safe(k) || path_is_absolute(k)) {
3727 log_syntax(unit, LOG_ERR, filename, line, 0,
3728 "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue);
3729 continue;
3730 }
3731
3732 r = strv_push(rt, k);
3733 if (r < 0)
3734 return log_oom();
3735 k = NULL;
3736 }
3737 }
3738
3739 int config_parse_set_status(
3740 const char *unit,
3741 const char *filename,
3742 unsigned line,
3743 const char *section,
3744 unsigned section_line,
3745 const char *lvalue,
3746 int ltype,
3747 const char *rvalue,
3748 void *data,
3749 void *userdata) {
3750
3751 size_t l;
3752 const char *word, *state;
3753 int r;
3754 ExitStatusSet *status_set = data;
3755
3756 assert(filename);
3757 assert(lvalue);
3758 assert(rvalue);
3759 assert(data);
3760
3761 /* Empty assignment resets the list */
3762 if (isempty(rvalue)) {
3763 exit_status_set_free(status_set);
3764 return 0;
3765 }
3766
3767 FOREACH_WORD(word, l, rvalue, state) {
3768 _cleanup_free_ char *temp;
3769 int val;
3770 Set **set;
3771
3772 temp = strndup(word, l);
3773 if (!temp)
3774 return log_oom();
3775
3776 r = safe_atoi(temp, &val);
3777 if (r < 0) {
3778 val = signal_from_string_try_harder(temp);
3779
3780 if (val <= 0) {
3781 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
3782 continue;
3783 }
3784 set = &status_set->signal;
3785 } else {
3786 if (val < 0 || val > 255) {
3787 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
3788 continue;
3789 }
3790 set = &status_set->status;
3791 }
3792
3793 r = set_ensure_allocated(set, NULL);
3794 if (r < 0)
3795 return log_oom();
3796
3797 r = set_put(*set, INT_TO_PTR(val));
3798 if (r < 0) {
3799 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
3800 return r;
3801 }
3802 }
3803 if (!isempty(state))
3804 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3805
3806 return 0;
3807 }
3808
3809 int config_parse_namespace_path_strv(
3810 const char *unit,
3811 const char *filename,
3812 unsigned line,
3813 const char *section,
3814 unsigned section_line,
3815 const char *lvalue,
3816 int ltype,
3817 const char *rvalue,
3818 void *data,
3819 void *userdata) {
3820
3821 Unit *u = userdata;
3822 char*** sv = data;
3823 const char *cur;
3824 int r;
3825
3826 assert(filename);
3827 assert(lvalue);
3828 assert(rvalue);
3829 assert(data);
3830
3831 if (isempty(rvalue)) {
3832 /* Empty assignment resets the list */
3833 *sv = strv_free(*sv);
3834 return 0;
3835 }
3836
3837 cur = rvalue;
3838 for (;;) {
3839 _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
3840 const char *w;
3841 bool ignore_enoent = false, shall_prefix = false;
3842
3843 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
3844 if (r == 0)
3845 break;
3846 if (r == -ENOMEM)
3847 return log_oom();
3848 if (r < 0) {
3849 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
3850 return 0;
3851 }
3852
3853 if (!utf8_is_valid(word)) {
3854 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3855 continue;
3856 }
3857
3858 w = word;
3859 if (startswith(w, "-")) {
3860 ignore_enoent = true;
3861 w++;
3862 }
3863 if (startswith(w, "+")) {
3864 shall_prefix = true;
3865 w++;
3866 }
3867
3868 r = unit_full_printf(u, w, &resolved);
3869 if (r < 0) {
3870 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s: %m", word);
3871 continue;
3872 }
3873
3874 if (!path_is_absolute(resolved)) {
3875 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
3876 continue;
3877 }
3878
3879 path_kill_slashes(resolved);
3880
3881 joined = strjoin(ignore_enoent ? "-" : "",
3882 shall_prefix ? "+" : "",
3883 resolved);
3884
3885 r = strv_push(sv, joined);
3886 if (r < 0)
3887 return log_oom();
3888
3889 joined = NULL;
3890 }
3891
3892 return 0;
3893 }
3894
3895 int config_parse_bind_paths(
3896 const char *unit,
3897 const char *filename,
3898 unsigned line,
3899 const char *section,
3900 unsigned section_line,
3901 const char *lvalue,
3902 int ltype,
3903 const char *rvalue,
3904 void *data,
3905 void *userdata) {
3906
3907 ExecContext *c = data;
3908 Unit *u = userdata;
3909 const char *p;
3910 int r;
3911
3912 assert(filename);
3913 assert(lvalue);
3914 assert(rvalue);
3915 assert(data);
3916
3917 if (isempty(rvalue)) {
3918 /* Empty assignment resets the list */
3919 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
3920 c->bind_mounts = NULL;
3921 c->n_bind_mounts = 0;
3922 return 0;
3923 }
3924
3925 p = rvalue;
3926 for (;;) {
3927 _cleanup_free_ char *source = NULL, *destination = NULL;
3928 _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
3929 char *s = NULL, *d = NULL;
3930 bool rbind = true, ignore_enoent = false;
3931
3932 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
3933 if (r == 0)
3934 break;
3935 if (r == -ENOMEM)
3936 return log_oom();
3937 if (r < 0) {
3938 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
3939 return 0;
3940 }
3941
3942 r = unit_full_printf(u, source, &sresolved);
3943 if (r < 0) {
3944 log_syntax(unit, LOG_ERR, filename, line, r,
3945 "Failed to resolved specifiers in \"%s\", ignoring: %m", source);
3946 return 0;
3947 }
3948
3949 s = sresolved;
3950 if (s[0] == '-') {
3951 ignore_enoent = true;
3952 s++;
3953 }
3954
3955 if (!utf8_is_valid(s)) {
3956 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, s);
3957 return 0;
3958 }
3959 if (!path_is_absolute(s)) {
3960 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute source path, ignoring: %s", s);
3961 return 0;
3962 }
3963
3964 path_kill_slashes(s);
3965
3966 /* Optionally, the destination is specified. */
3967 if (p && p[-1] == ':') {
3968 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
3969 if (r == -ENOMEM)
3970 return log_oom();
3971 if (r < 0) {
3972 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
3973 return 0;
3974 }
3975 if (r == 0) {
3976 log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':': %s", rvalue);
3977 return 0;
3978 }
3979
3980 r = unit_full_printf(u, destination, &dresolved);
3981 if (r < 0) {
3982 log_syntax(unit, LOG_ERR, filename, line, r,
3983 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
3984 return 0;
3985 }
3986
3987 if (!utf8_is_valid(dresolved)) {
3988 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved);
3989 return 0;
3990 }
3991 if (!path_is_absolute(dresolved)) {
3992 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved);
3993 return 0;
3994 }
3995
3996 d = path_kill_slashes(dresolved);
3997
3998 /* Optionally, there's also a short option string specified */
3999 if (p && p[-1] == ':') {
4000 _cleanup_free_ char *options = NULL;
4001
4002 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
4003 if (r == -ENOMEM)
4004 return log_oom();
4005 if (r < 0) {
4006 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
4007 return 0;
4008 }
4009
4010 if (isempty(options) || streq(options, "rbind"))
4011 rbind = true;
4012 else if (streq(options, "norbind"))
4013 rbind = false;
4014 else {
4015 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
4016 return 0;
4017 }
4018 }
4019 } else
4020 d = s;
4021
4022 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
4023 &(BindMount) {
4024 .source = s,
4025 .destination = d,
4026 .read_only = !!strstr(lvalue, "ReadOnly"),
4027 .recursive = rbind,
4028 .ignore_enoent = ignore_enoent,
4029 });
4030 if (r < 0)
4031 return log_oom();
4032 }
4033
4034 return 0;
4035 }
4036
4037 int config_parse_no_new_privileges(
4038 const char* unit,
4039 const char *filename,
4040 unsigned line,
4041 const char *section,
4042 unsigned section_line,
4043 const char *lvalue,
4044 int ltype,
4045 const char *rvalue,
4046 void *data,
4047 void *userdata) {
4048
4049 ExecContext *c = data;
4050 int k;
4051
4052 assert(filename);
4053 assert(lvalue);
4054 assert(rvalue);
4055 assert(data);
4056
4057 k = parse_boolean(rvalue);
4058 if (k < 0) {
4059 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
4060 return 0;
4061 }
4062
4063 c->no_new_privileges = k;
4064
4065 return 0;
4066 }
4067
4068 int config_parse_protect_home(
4069 const char* unit,
4070 const char *filename,
4071 unsigned line,
4072 const char *section,
4073 unsigned section_line,
4074 const char *lvalue,
4075 int ltype,
4076 const char *rvalue,
4077 void *data,
4078 void *userdata) {
4079
4080 ExecContext *c = data;
4081 int k;
4082
4083 assert(filename);
4084 assert(lvalue);
4085 assert(rvalue);
4086 assert(data);
4087
4088 /* Our enum shall be a superset of booleans, hence first try
4089 * to parse as boolean, and then as enum */
4090
4091 k = parse_boolean(rvalue);
4092 if (k > 0)
4093 c->protect_home = PROTECT_HOME_YES;
4094 else if (k == 0)
4095 c->protect_home = PROTECT_HOME_NO;
4096 else {
4097 ProtectHome h;
4098
4099 h = protect_home_from_string(rvalue);
4100 if (h < 0) {
4101 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
4102 return 0;
4103 }
4104
4105 c->protect_home = h;
4106 }
4107
4108 return 0;
4109 }
4110
4111 int config_parse_protect_system(
4112 const char* unit,
4113 const char *filename,
4114 unsigned line,
4115 const char *section,
4116 unsigned section_line,
4117 const char *lvalue,
4118 int ltype,
4119 const char *rvalue,
4120 void *data,
4121 void *userdata) {
4122
4123 ExecContext *c = data;
4124 int k;
4125
4126 assert(filename);
4127 assert(lvalue);
4128 assert(rvalue);
4129 assert(data);
4130
4131 /* Our enum shall be a superset of booleans, hence first try
4132 * to parse as boolean, and then as enum */
4133
4134 k = parse_boolean(rvalue);
4135 if (k > 0)
4136 c->protect_system = PROTECT_SYSTEM_YES;
4137 else if (k == 0)
4138 c->protect_system = PROTECT_SYSTEM_NO;
4139 else {
4140 ProtectSystem s;
4141
4142 s = protect_system_from_string(rvalue);
4143 if (s < 0) {
4144 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
4145 return 0;
4146 }
4147
4148 c->protect_system = s;
4149 }
4150
4151 return 0;
4152 }
4153
4154 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
4155
4156 int config_parse_job_timeout_sec(
4157 const char* unit,
4158 const char *filename,
4159 unsigned line,
4160 const char *section,
4161 unsigned section_line,
4162 const char *lvalue,
4163 int ltype,
4164 const char *rvalue,
4165 void *data,
4166 void *userdata) {
4167
4168 Unit *u = data;
4169 usec_t usec;
4170 int r;
4171
4172 assert(filename);
4173 assert(lvalue);
4174 assert(rvalue);
4175 assert(u);
4176
4177 r = parse_sec_fix_0(rvalue, &usec);
4178 if (r < 0) {
4179 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
4180 return 0;
4181 }
4182
4183 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4184 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4185 * count. */
4186
4187 if (!u->job_running_timeout_set)
4188 u->job_running_timeout = usec;
4189
4190 u->job_timeout = usec;
4191
4192 return 0;
4193 }
4194
4195 int config_parse_job_running_timeout_sec(
4196 const char* unit,
4197 const char *filename,
4198 unsigned line,
4199 const char *section,
4200 unsigned section_line,
4201 const char *lvalue,
4202 int ltype,
4203 const char *rvalue,
4204 void *data,
4205 void *userdata) {
4206
4207 Unit *u = data;
4208 usec_t usec;
4209 int r;
4210
4211 assert(filename);
4212 assert(lvalue);
4213 assert(rvalue);
4214 assert(u);
4215
4216 r = parse_sec_fix_0(rvalue, &usec);
4217 if (r < 0) {
4218 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
4219 return 0;
4220 }
4221
4222 u->job_running_timeout = usec;
4223 u->job_running_timeout_set = true;
4224
4225 return 0;
4226 }
4227
4228 #define FOLLOW_MAX 8
4229
4230 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
4231 char *id = NULL;
4232 unsigned c = 0;
4233 int fd, r;
4234 FILE *f;
4235
4236 assert(filename);
4237 assert(*filename);
4238 assert(_f);
4239 assert(names);
4240
4241 /* This will update the filename pointer if the loaded file is
4242 * reached by a symlink. The old string will be freed. */
4243
4244 for (;;) {
4245 char *target, *name;
4246
4247 if (c++ >= FOLLOW_MAX)
4248 return -ELOOP;
4249
4250 path_kill_slashes(*filename);
4251
4252 /* Add the file name we are currently looking at to
4253 * the names of this unit, but only if it is a valid
4254 * unit name. */
4255 name = basename(*filename);
4256 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
4257
4258 id = set_get(names, name);
4259 if (!id) {
4260 id = strdup(name);
4261 if (!id)
4262 return -ENOMEM;
4263
4264 r = set_consume(names, id);
4265 if (r < 0)
4266 return r;
4267 }
4268 }
4269
4270 /* Try to open the file name, but don't if its a symlink */
4271 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
4272 if (fd >= 0)
4273 break;
4274
4275 if (errno != ELOOP)
4276 return -errno;
4277
4278 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4279 r = readlink_and_make_absolute(*filename, &target);
4280 if (r < 0)
4281 return r;
4282
4283 free(*filename);
4284 *filename = target;
4285 }
4286
4287 f = fdopen(fd, "re");
4288 if (!f) {
4289 safe_close(fd);
4290 return -errno;
4291 }
4292
4293 *_f = f;
4294 *_final = id;
4295
4296 return 0;
4297 }
4298
4299 static int merge_by_names(Unit **u, Set *names, const char *id) {
4300 char *k;
4301 int r;
4302
4303 assert(u);
4304 assert(*u);
4305 assert(names);
4306
4307 /* Let's try to add in all symlink names we found */
4308 while ((k = set_steal_first(names))) {
4309
4310 /* First try to merge in the other name into our
4311 * unit */
4312 r = unit_merge_by_name(*u, k);
4313 if (r < 0) {
4314 Unit *other;
4315
4316 /* Hmm, we couldn't merge the other unit into
4317 * ours? Then let's try it the other way
4318 * round */
4319
4320 /* If the symlink name we are looking at is unit template, then
4321 we must search for instance of this template */
4322 if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
4323 _cleanup_free_ char *instance = NULL;
4324
4325 r = unit_name_replace_instance(k, (*u)->instance, &instance);
4326 if (r < 0)
4327 return r;
4328
4329 other = manager_get_unit((*u)->manager, instance);
4330 } else
4331 other = manager_get_unit((*u)->manager, k);
4332
4333 free(k);
4334
4335 if (other) {
4336 r = unit_merge(other, *u);
4337 if (r >= 0) {
4338 *u = other;
4339 return merge_by_names(u, names, NULL);
4340 }
4341 }
4342
4343 return r;
4344 }
4345
4346 if (id == k)
4347 unit_choose_id(*u, id);
4348
4349 free(k);
4350 }
4351
4352 return 0;
4353 }
4354
4355 static int load_from_path(Unit *u, const char *path) {
4356 _cleanup_set_free_free_ Set *symlink_names = NULL;
4357 _cleanup_fclose_ FILE *f = NULL;
4358 _cleanup_free_ char *filename = NULL;
4359 char *id = NULL;
4360 Unit *merged;
4361 struct stat st;
4362 int r;
4363
4364 assert(u);
4365 assert(path);
4366
4367 symlink_names = set_new(&string_hash_ops);
4368 if (!symlink_names)
4369 return -ENOMEM;
4370
4371 if (path_is_absolute(path)) {
4372
4373 filename = strdup(path);
4374 if (!filename)
4375 return -ENOMEM;
4376
4377 r = open_follow(&filename, &f, symlink_names, &id);
4378 if (r < 0) {
4379 filename = mfree(filename);
4380 if (r != -ENOENT)
4381 return r;
4382 }
4383
4384 } else {
4385 char **p;
4386
4387 STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
4388
4389 /* Instead of opening the path right away, we manually
4390 * follow all symlinks and add their name to our unit
4391 * name set while doing so */
4392 filename = path_make_absolute(path, *p);
4393 if (!filename)
4394 return -ENOMEM;
4395
4396 if (u->manager->unit_path_cache &&
4397 !set_get(u->manager->unit_path_cache, filename))
4398 r = -ENOENT;
4399 else
4400 r = open_follow(&filename, &f, symlink_names, &id);
4401 if (r >= 0)
4402 break;
4403 filename = mfree(filename);
4404
4405 /* ENOENT means that the file is missing or is a dangling symlink.
4406 * ENOTDIR means that one of paths we expect to be is a directory
4407 * is not a directory, we should just ignore that.
4408 * EACCES means that the directory or file permissions are wrong.
4409 */
4410 if (r == -EACCES)
4411 log_debug_errno(r, "Cannot access \"%s\": %m", filename);
4412 else if (!IN_SET(r, -ENOENT, -ENOTDIR))
4413 return r;
4414
4415 /* Empty the symlink names for the next run */
4416 set_clear_free(symlink_names);
4417 }
4418 }
4419
4420 if (!filename)
4421 /* Hmm, no suitable file found? */
4422 return 0;
4423
4424 if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
4425 log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
4426 return -ELOOP;
4427 }
4428
4429 merged = u;
4430 r = merge_by_names(&merged, symlink_names, id);
4431 if (r < 0)
4432 return r;
4433
4434 if (merged != u) {
4435 u->load_state = UNIT_MERGED;
4436 return 0;
4437 }
4438
4439 if (fstat(fileno(f), &st) < 0)
4440 return -errno;
4441
4442 if (null_or_empty(&st)) {
4443 u->load_state = UNIT_MASKED;
4444 u->fragment_mtime = 0;
4445 } else {
4446 u->load_state = UNIT_LOADED;
4447 u->fragment_mtime = timespec_load(&st.st_mtim);
4448
4449 /* Now, parse the file contents */
4450 r = config_parse(u->id, filename, f,
4451 UNIT_VTABLE(u)->sections,
4452 config_item_perf_lookup, load_fragment_gperf_lookup,
4453 CONFIG_PARSE_ALLOW_INCLUDE, u);
4454 if (r < 0)
4455 return r;
4456 }
4457
4458 free(u->fragment_path);
4459 u->fragment_path = filename;
4460 filename = NULL;
4461
4462 if (u->source_path) {
4463 if (stat(u->source_path, &st) >= 0)
4464 u->source_mtime = timespec_load(&st.st_mtim);
4465 else
4466 u->source_mtime = 0;
4467 }
4468
4469 return 0;
4470 }
4471
4472 int unit_load_fragment(Unit *u) {
4473 int r;
4474 Iterator i;
4475 const char *t;
4476
4477 assert(u);
4478 assert(u->load_state == UNIT_STUB);
4479 assert(u->id);
4480
4481 if (u->transient) {
4482 u->load_state = UNIT_LOADED;
4483 return 0;
4484 }
4485
4486 /* First, try to find the unit under its id. We always look
4487 * for unit files in the default directories, to make it easy
4488 * to override things by placing things in /etc/systemd/system */
4489 r = load_from_path(u, u->id);
4490 if (r < 0)
4491 return r;
4492
4493 /* Try to find an alias we can load this with */
4494 if (u->load_state == UNIT_STUB) {
4495 SET_FOREACH(t, u->names, i) {
4496
4497 if (t == u->id)
4498 continue;
4499
4500 r = load_from_path(u, t);
4501 if (r < 0)
4502 return r;
4503
4504 if (u->load_state != UNIT_STUB)
4505 break;
4506 }
4507 }
4508
4509 /* And now, try looking for it under the suggested (originally linked) path */
4510 if (u->load_state == UNIT_STUB && u->fragment_path) {
4511
4512 r = load_from_path(u, u->fragment_path);
4513 if (r < 0)
4514 return r;
4515
4516 if (u->load_state == UNIT_STUB)
4517 /* Hmm, this didn't work? Then let's get rid
4518 * of the fragment path stored for us, so that
4519 * we don't point to an invalid location. */
4520 u->fragment_path = mfree(u->fragment_path);
4521 }
4522
4523 /* Look for a template */
4524 if (u->load_state == UNIT_STUB && u->instance) {
4525 _cleanup_free_ char *k = NULL;
4526
4527 r = unit_name_template(u->id, &k);
4528 if (r < 0)
4529 return r;
4530
4531 r = load_from_path(u, k);
4532 if (r < 0) {
4533 if (r == -ENOEXEC)
4534 log_unit_notice(u, "Unit configuration has fatal error, unit will not be started.");
4535 return r;
4536 }
4537
4538 if (u->load_state == UNIT_STUB) {
4539 SET_FOREACH(t, u->names, i) {
4540 _cleanup_free_ char *z = NULL;
4541
4542 if (t == u->id)
4543 continue;
4544
4545 r = unit_name_template(t, &z);
4546 if (r < 0)
4547 return r;
4548
4549 r = load_from_path(u, z);
4550 if (r < 0)
4551 return r;
4552
4553 if (u->load_state != UNIT_STUB)
4554 break;
4555 }
4556 }
4557 }
4558
4559 return 0;
4560 }
4561
4562 void unit_dump_config_items(FILE *f) {
4563 static const struct {
4564 const ConfigParserCallback callback;
4565 const char *rvalue;
4566 } table[] = {
4567 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4568 { config_parse_warn_compat, "NOTSUPPORTED" },
4569 #endif
4570 { config_parse_int, "INTEGER" },
4571 { config_parse_unsigned, "UNSIGNED" },
4572 { config_parse_iec_size, "SIZE" },
4573 { config_parse_iec_uint64, "SIZE" },
4574 { config_parse_si_size, "SIZE" },
4575 { config_parse_bool, "BOOLEAN" },
4576 { config_parse_string, "STRING" },
4577 { config_parse_path, "PATH" },
4578 { config_parse_unit_path_printf, "PATH" },
4579 { config_parse_strv, "STRING [...]" },
4580 { config_parse_exec_nice, "NICE" },
4581 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4582 { config_parse_exec_io_class, "IOCLASS" },
4583 { config_parse_exec_io_priority, "IOPRIORITY" },
4584 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4585 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4586 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4587 { config_parse_mode, "MODE" },
4588 { config_parse_unit_env_file, "FILE" },
4589 { config_parse_exec_output, "OUTPUT" },
4590 { config_parse_exec_input, "INPUT" },
4591 { config_parse_log_facility, "FACILITY" },
4592 { config_parse_log_level, "LEVEL" },
4593 { config_parse_exec_secure_bits, "SECUREBITS" },
4594 { config_parse_capability_set, "BOUNDINGSET" },
4595 { config_parse_limit, "LIMIT" },
4596 { config_parse_unit_deps, "UNIT [...]" },
4597 { config_parse_exec, "PATH [ARGUMENT [...]]" },
4598 { config_parse_service_type, "SERVICETYPE" },
4599 { config_parse_service_restart, "SERVICERESTART" },
4600 #if HAVE_SYSV_COMPAT
4601 { config_parse_sysv_priority, "SYSVPRIORITY" },
4602 #endif
4603 { config_parse_kill_mode, "KILLMODE" },
4604 { config_parse_signal, "SIGNAL" },
4605 { config_parse_socket_listen, "SOCKET [...]" },
4606 { config_parse_socket_bind, "SOCKETBIND" },
4607 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
4608 { config_parse_sec, "SECONDS" },
4609 { config_parse_nsec, "NANOSECONDS" },
4610 { config_parse_namespace_path_strv, "PATH [...]" },
4611 { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
4612 { config_parse_unit_requires_mounts_for, "PATH [...]" },
4613 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4614 { config_parse_unit_string_printf, "STRING" },
4615 { config_parse_trigger_unit, "UNIT" },
4616 { config_parse_timer, "TIMER" },
4617 { config_parse_path_spec, "PATH" },
4618 { config_parse_notify_access, "ACCESS" },
4619 { config_parse_ip_tos, "TOS" },
4620 { config_parse_unit_condition_path, "CONDITION" },
4621 { config_parse_unit_condition_string, "CONDITION" },
4622 { config_parse_unit_condition_null, "CONDITION" },
4623 { config_parse_unit_slice, "SLICE" },
4624 { config_parse_documentation, "URL" },
4625 { config_parse_service_timeout, "SECONDS" },
4626 { config_parse_emergency_action, "ACTION" },
4627 { config_parse_set_status, "STATUS" },
4628 { config_parse_service_sockets, "SOCKETS" },
4629 { config_parse_environ, "ENVIRON" },
4630 #if HAVE_SECCOMP
4631 { config_parse_syscall_filter, "SYSCALLS" },
4632 { config_parse_syscall_archs, "ARCHS" },
4633 { config_parse_syscall_errno, "ERRNO" },
4634 { config_parse_address_families, "FAMILIES" },
4635 { config_parse_restrict_namespaces, "NAMESPACES" },
4636 #endif
4637 { config_parse_cpu_shares, "SHARES" },
4638 { config_parse_cpu_weight, "WEIGHT" },
4639 { config_parse_memory_limit, "LIMIT" },
4640 { config_parse_device_allow, "DEVICE" },
4641 { config_parse_device_policy, "POLICY" },
4642 { config_parse_io_limit, "LIMIT" },
4643 { config_parse_io_weight, "WEIGHT" },
4644 { config_parse_io_device_weight, "DEVICEWEIGHT" },
4645 { config_parse_blockio_bandwidth, "BANDWIDTH" },
4646 { config_parse_blockio_weight, "WEIGHT" },
4647 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4648 { config_parse_long, "LONG" },
4649 { config_parse_socket_service, "SERVICE" },
4650 #if HAVE_SELINUX
4651 { config_parse_exec_selinux_context, "LABEL" },
4652 #endif
4653 { config_parse_job_mode, "MODE" },
4654 { config_parse_job_mode_isolate, "BOOLEAN" },
4655 { config_parse_personality, "PERSONALITY" },
4656 };
4657
4658 const char *prev = NULL;
4659 const char *i;
4660
4661 assert(f);
4662
4663 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4664 const char *rvalue = "OTHER", *lvalue;
4665 unsigned j;
4666 size_t prefix_len;
4667 const char *dot;
4668 const ConfigPerfItem *p;
4669
4670 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4671
4672 dot = strchr(i, '.');
4673 lvalue = dot ? dot + 1 : i;
4674 prefix_len = dot-i;
4675
4676 if (dot)
4677 if (!prev || !strneq(prev, i, prefix_len+1)) {
4678 if (prev)
4679 fputc('\n', f);
4680
4681 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
4682 }
4683
4684 for (j = 0; j < ELEMENTSOF(table); j++)
4685 if (p->parse == table[j].callback) {
4686 rvalue = table[j].rvalue;
4687 break;
4688 }
4689
4690 fprintf(f, "%s=%s\n", lvalue, rvalue);
4691 prev = i;
4692 }
4693 }