]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/load-fragment.c
Merge pull request #6931 from poettering/job-timeout-sec
[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);
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 (!set_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);
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);
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);
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);
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 r;
2637
2638 if (t[0] == '@') {
2639 const SyscallFilterSet *set;
2640 const char *i;
2641
2642 set = syscall_filter_set_find(t);
2643 if (!set) {
2644 if (warn)
2645 log_syntax(unit, LOG_WARNING, filename, line, 0, "Don't know system call group, ignoring: %s", t);
2646 return 0;
2647 }
2648
2649 NULSTR_FOREACH(i, set->value) {
2650 r = syscall_filter_parse_one(unit, filename, line, c, invert, i, false);
2651 if (r < 0)
2652 return r;
2653 }
2654 } else {
2655 int id;
2656
2657 id = seccomp_syscall_resolve_name(t);
2658 if (id == __NR_SCMP_ERROR) {
2659 if (warn)
2660 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
2661 return 0;
2662 }
2663
2664 /* If we previously wanted to forbid a syscall and now
2665 * we want to allow it, then remove it from the list
2666 */
2667 if (!invert == c->syscall_whitelist) {
2668 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2669 if (r == 0)
2670 return 0;
2671 if (r < 0)
2672 return log_oom();
2673 } else
2674 (void) set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2675 }
2676
2677 return 0;
2678 }
2679
2680 int config_parse_syscall_filter(
2681 const char *unit,
2682 const char *filename,
2683 unsigned line,
2684 const char *section,
2685 unsigned section_line,
2686 const char *lvalue,
2687 int ltype,
2688 const char *rvalue,
2689 void *data,
2690 void *userdata) {
2691
2692 ExecContext *c = data;
2693 Unit *u = userdata;
2694 bool invert = false;
2695 const char *p;
2696 int r;
2697
2698 assert(filename);
2699 assert(lvalue);
2700 assert(rvalue);
2701 assert(u);
2702
2703 if (isempty(rvalue)) {
2704 /* Empty assignment resets the list */
2705 c->syscall_filter = set_free(c->syscall_filter);
2706 c->syscall_whitelist = false;
2707 return 0;
2708 }
2709
2710 if (rvalue[0] == '~') {
2711 invert = true;
2712 rvalue++;
2713 }
2714
2715 if (!c->syscall_filter) {
2716 c->syscall_filter = set_new(NULL);
2717 if (!c->syscall_filter)
2718 return log_oom();
2719
2720 if (invert)
2721 /* Allow everything but the ones listed */
2722 c->syscall_whitelist = false;
2723 else {
2724 /* Allow nothing but the ones listed */
2725 c->syscall_whitelist = true;
2726
2727 /* Accept default syscalls if we are on a whitelist */
2728 r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false);
2729 if (r < 0)
2730 return r;
2731 }
2732 }
2733
2734 p = rvalue;
2735 for (;;) {
2736 _cleanup_free_ char *word = NULL;
2737
2738 r = extract_first_word(&p, &word, NULL, 0);
2739 if (r == 0)
2740 break;
2741 if (r == -ENOMEM)
2742 return log_oom();
2743 if (r < 0) {
2744 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
2745 break;
2746 }
2747
2748 r = syscall_filter_parse_one(unit, filename, line, c, invert, word, true);
2749 if (r < 0)
2750 return r;
2751 }
2752
2753 return 0;
2754 }
2755
2756 int config_parse_syscall_archs(
2757 const char *unit,
2758 const char *filename,
2759 unsigned line,
2760 const char *section,
2761 unsigned section_line,
2762 const char *lvalue,
2763 int ltype,
2764 const char *rvalue,
2765 void *data,
2766 void *userdata) {
2767
2768 Set **archs = data;
2769 const char *p;
2770 int r;
2771
2772 if (isempty(rvalue)) {
2773 *archs = set_free(*archs);
2774 return 0;
2775 }
2776
2777 r = set_ensure_allocated(archs, NULL);
2778 if (r < 0)
2779 return log_oom();
2780
2781 for (p = rvalue;;) {
2782 _cleanup_free_ char *word = NULL;
2783 uint32_t a;
2784
2785 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
2786 if (r == 0)
2787 return 0;
2788 if (r == -ENOMEM)
2789 return log_oom();
2790 if (r < 0) {
2791 log_syntax(unit, LOG_WARNING, filename, line, r,
2792 "Invalid syntax, ignoring: %s", rvalue);
2793 return 0;
2794 }
2795
2796 r = seccomp_arch_from_string(word, &a);
2797 if (r < 0) {
2798 log_syntax(unit, LOG_ERR, filename, line, r,
2799 "Failed to parse system call architecture \"%s\", ignoring: %m", word);
2800 continue;
2801 }
2802
2803 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2804 if (r < 0)
2805 return log_oom();
2806 }
2807 }
2808
2809 int config_parse_syscall_errno(
2810 const char *unit,
2811 const char *filename,
2812 unsigned line,
2813 const char *section,
2814 unsigned section_line,
2815 const char *lvalue,
2816 int ltype,
2817 const char *rvalue,
2818 void *data,
2819 void *userdata) {
2820
2821 ExecContext *c = data;
2822 int e;
2823
2824 assert(filename);
2825 assert(lvalue);
2826 assert(rvalue);
2827
2828 if (isempty(rvalue)) {
2829 /* Empty assignment resets to KILL */
2830 c->syscall_errno = 0;
2831 return 0;
2832 }
2833
2834 e = errno_from_name(rvalue);
2835 if (e < 0) {
2836 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
2837 return 0;
2838 }
2839
2840 c->syscall_errno = e;
2841 return 0;
2842 }
2843
2844 int config_parse_address_families(
2845 const char *unit,
2846 const char *filename,
2847 unsigned line,
2848 const char *section,
2849 unsigned section_line,
2850 const char *lvalue,
2851 int ltype,
2852 const char *rvalue,
2853 void *data,
2854 void *userdata) {
2855
2856 ExecContext *c = data;
2857 bool invert = false;
2858 const char *p;
2859 int r;
2860
2861 assert(filename);
2862 assert(lvalue);
2863 assert(rvalue);
2864
2865 if (isempty(rvalue)) {
2866 /* Empty assignment resets the list */
2867 c->address_families = set_free(c->address_families);
2868 c->address_families_whitelist = false;
2869 return 0;
2870 }
2871
2872 if (rvalue[0] == '~') {
2873 invert = true;
2874 rvalue++;
2875 }
2876
2877 if (!c->address_families) {
2878 c->address_families = set_new(NULL);
2879 if (!c->address_families)
2880 return log_oom();
2881
2882 c->address_families_whitelist = !invert;
2883 }
2884
2885 for (p = rvalue;;) {
2886 _cleanup_free_ char *word = NULL;
2887 int af;
2888
2889 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
2890 if (r == 0)
2891 return 0;
2892 if (r == -ENOMEM)
2893 return log_oom();
2894 if (r < 0) {
2895 log_syntax(unit, LOG_WARNING, filename, line, r,
2896 "Invalid syntax, ignoring: %s", rvalue);
2897 return 0;
2898 }
2899
2900 af = af_from_name(word);
2901 if (af <= 0) {
2902 log_syntax(unit, LOG_ERR, filename, line, 0,
2903 "Failed to parse address family \"%s\", ignoring: %m", word);
2904 continue;
2905 }
2906
2907 /* If we previously wanted to forbid an address family and now
2908 * we want to allow it, then just remove it from the list.
2909 */
2910 if (!invert == c->address_families_whitelist) {
2911 r = set_put(c->address_families, INT_TO_PTR(af));
2912 if (r < 0)
2913 return log_oom();
2914 } else
2915 set_remove(c->address_families, INT_TO_PTR(af));
2916 }
2917 }
2918
2919 int config_parse_restrict_namespaces(
2920 const char *unit,
2921 const char *filename,
2922 unsigned line,
2923 const char *section,
2924 unsigned section_line,
2925 const char *lvalue,
2926 int ltype,
2927 const char *rvalue,
2928 void *data,
2929 void *userdata) {
2930
2931 ExecContext *c = data;
2932 bool invert = false;
2933 int r;
2934
2935 if (isempty(rvalue)) {
2936 /* Reset to the default. */
2937 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
2938 return 0;
2939 }
2940
2941 if (rvalue[0] == '~') {
2942 invert = true;
2943 rvalue++;
2944 }
2945
2946 r = parse_boolean(rvalue);
2947 if (r > 0)
2948 c->restrict_namespaces = 0;
2949 else if (r == 0)
2950 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
2951 else {
2952 /* Not a boolean argument, in this case it's a list of namespace types. */
2953
2954 r = namespace_flag_from_string_many(rvalue, &c->restrict_namespaces);
2955 if (r < 0) {
2956 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
2957 return 0;
2958 }
2959 }
2960
2961 if (invert)
2962 c->restrict_namespaces = (~c->restrict_namespaces) & NAMESPACE_FLAGS_ALL;
2963
2964 return 0;
2965 }
2966 #endif
2967
2968 int config_parse_unit_slice(
2969 const char *unit,
2970 const char *filename,
2971 unsigned line,
2972 const char *section,
2973 unsigned section_line,
2974 const char *lvalue,
2975 int ltype,
2976 const char *rvalue,
2977 void *data,
2978 void *userdata) {
2979
2980 _cleanup_free_ char *k = NULL;
2981 Unit *u = userdata, *slice = NULL;
2982 int r;
2983
2984 assert(filename);
2985 assert(lvalue);
2986 assert(rvalue);
2987 assert(u);
2988
2989 r = unit_name_printf(u, rvalue, &k);
2990 if (r < 0) {
2991 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2992 return 0;
2993 }
2994
2995 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2996 if (r < 0) {
2997 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k);
2998 return 0;
2999 }
3000
3001 r = unit_set_slice(u, slice);
3002 if (r < 0) {
3003 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
3004 return 0;
3005 }
3006
3007 return 0;
3008 }
3009
3010 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
3011
3012 int config_parse_cpu_weight(
3013 const char *unit,
3014 const char *filename,
3015 unsigned line,
3016 const char *section,
3017 unsigned section_line,
3018 const char *lvalue,
3019 int ltype,
3020 const char *rvalue,
3021 void *data,
3022 void *userdata) {
3023
3024 uint64_t *weight = data;
3025 int r;
3026
3027 assert(filename);
3028 assert(lvalue);
3029 assert(rvalue);
3030
3031 r = cg_weight_parse(rvalue, weight);
3032 if (r < 0) {
3033 log_syntax(unit, LOG_ERR, filename, line, r, "CPU weight '%s' invalid. Ignoring.", rvalue);
3034 return 0;
3035 }
3036
3037 return 0;
3038 }
3039
3040 int config_parse_cpu_shares(
3041 const char *unit,
3042 const char *filename,
3043 unsigned line,
3044 const char *section,
3045 unsigned section_line,
3046 const char *lvalue,
3047 int ltype,
3048 const char *rvalue,
3049 void *data,
3050 void *userdata) {
3051
3052 uint64_t *shares = data;
3053 int r;
3054
3055 assert(filename);
3056 assert(lvalue);
3057 assert(rvalue);
3058
3059 r = cg_cpu_shares_parse(rvalue, shares);
3060 if (r < 0) {
3061 log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
3062 return 0;
3063 }
3064
3065 return 0;
3066 }
3067
3068 int config_parse_cpu_quota(
3069 const char *unit,
3070 const char *filename,
3071 unsigned line,
3072 const char *section,
3073 unsigned section_line,
3074 const char *lvalue,
3075 int ltype,
3076 const char *rvalue,
3077 void *data,
3078 void *userdata) {
3079
3080 CGroupContext *c = data;
3081 int r;
3082
3083 assert(filename);
3084 assert(lvalue);
3085 assert(rvalue);
3086
3087 if (isempty(rvalue)) {
3088 c->cpu_quota_per_sec_usec = USEC_INFINITY;
3089 return 0;
3090 }
3091
3092 r = parse_percent_unbounded(rvalue);
3093 if (r <= 0) {
3094 log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
3095 return 0;
3096 }
3097
3098 c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
3099 return 0;
3100 }
3101
3102 int config_parse_memory_limit(
3103 const char *unit,
3104 const char *filename,
3105 unsigned line,
3106 const char *section,
3107 unsigned section_line,
3108 const char *lvalue,
3109 int ltype,
3110 const char *rvalue,
3111 void *data,
3112 void *userdata) {
3113
3114 CGroupContext *c = data;
3115 uint64_t bytes = CGROUP_LIMIT_MAX;
3116 int r;
3117
3118 if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
3119
3120 r = parse_percent(rvalue);
3121 if (r < 0) {
3122 r = parse_size(rvalue, 1024, &bytes);
3123 if (r < 0) {
3124 log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
3125 return 0;
3126 }
3127 } else
3128 bytes = physical_memory_scale(r, 100U);
3129
3130 if (bytes <= 0 || bytes >= UINT64_MAX) {
3131 log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
3132 return 0;
3133 }
3134 }
3135
3136 if (streq(lvalue, "MemoryLow"))
3137 c->memory_low = bytes;
3138 else if (streq(lvalue, "MemoryHigh"))
3139 c->memory_high = bytes;
3140 else if (streq(lvalue, "MemoryMax"))
3141 c->memory_max = bytes;
3142 else if (streq(lvalue, "MemorySwapMax"))
3143 c->memory_swap_max = bytes;
3144 else if (streq(lvalue, "MemoryLimit"))
3145 c->memory_limit = bytes;
3146 else
3147 return -EINVAL;
3148
3149 return 0;
3150 }
3151
3152 int config_parse_tasks_max(
3153 const char *unit,
3154 const char *filename,
3155 unsigned line,
3156 const char *section,
3157 unsigned section_line,
3158 const char *lvalue,
3159 int ltype,
3160 const char *rvalue,
3161 void *data,
3162 void *userdata) {
3163
3164 uint64_t *tasks_max = data, v;
3165 Unit *u = userdata;
3166 int r;
3167
3168 if (isempty(rvalue)) {
3169 *tasks_max = u->manager->default_tasks_max;
3170 return 0;
3171 }
3172
3173 if (streq(rvalue, "infinity")) {
3174 *tasks_max = CGROUP_LIMIT_MAX;
3175 return 0;
3176 }
3177
3178 r = parse_percent(rvalue);
3179 if (r < 0) {
3180 r = safe_atou64(rvalue, &v);
3181 if (r < 0) {
3182 log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
3183 return 0;
3184 }
3185 } else
3186 v = system_tasks_max_scale(r, 100U);
3187
3188 if (v <= 0 || v >= UINT64_MAX) {
3189 log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
3190 return 0;
3191 }
3192
3193 *tasks_max = v;
3194 return 0;
3195 }
3196
3197 int config_parse_device_allow(
3198 const char *unit,
3199 const char *filename,
3200 unsigned line,
3201 const char *section,
3202 unsigned section_line,
3203 const char *lvalue,
3204 int ltype,
3205 const char *rvalue,
3206 void *data,
3207 void *userdata) {
3208
3209 _cleanup_free_ char *path = NULL, *t = NULL;
3210 CGroupContext *c = data;
3211 CGroupDeviceAllow *a;
3212 const char *m = NULL;
3213 size_t n;
3214 int r;
3215
3216 if (isempty(rvalue)) {
3217 while (c->device_allow)
3218 cgroup_context_free_device_allow(c, c->device_allow);
3219
3220 return 0;
3221 }
3222
3223 r = unit_full_printf(userdata, rvalue, &t);
3224 if(r < 0) {
3225 log_syntax(unit, LOG_WARNING, filename, line, r,
3226 "Failed to resolve specifiers in %s, ignoring: %m",
3227 rvalue);
3228 }
3229
3230 n = strcspn(t, WHITESPACE);
3231
3232 path = strndup(t, n);
3233 if (!path)
3234 return log_oom();
3235
3236 if (!is_deviceallow_pattern(path)) {
3237 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3238 return 0;
3239 }
3240
3241 m = t + n + strspn(t + n, WHITESPACE);
3242 if (isempty(m))
3243 m = "rwm";
3244
3245 if (!in_charset(m, "rwm")) {
3246 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
3247 return 0;
3248 }
3249
3250 a = new0(CGroupDeviceAllow, 1);
3251 if (!a)
3252 return log_oom();
3253
3254 a->path = path;
3255 path = NULL;
3256 a->r = !!strchr(m, 'r');
3257 a->w = !!strchr(m, 'w');
3258 a->m = !!strchr(m, 'm');
3259
3260 LIST_PREPEND(device_allow, c->device_allow, a);
3261 return 0;
3262 }
3263
3264 int config_parse_io_weight(
3265 const char *unit,
3266 const char *filename,
3267 unsigned line,
3268 const char *section,
3269 unsigned section_line,
3270 const char *lvalue,
3271 int ltype,
3272 const char *rvalue,
3273 void *data,
3274 void *userdata) {
3275
3276 uint64_t *weight = data;
3277 int r;
3278
3279 assert(filename);
3280 assert(lvalue);
3281 assert(rvalue);
3282
3283 r = cg_weight_parse(rvalue, weight);
3284 if (r < 0) {
3285 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
3286 return 0;
3287 }
3288
3289 return 0;
3290 }
3291
3292 int config_parse_io_device_weight(
3293 const char *unit,
3294 const char *filename,
3295 unsigned line,
3296 const char *section,
3297 unsigned section_line,
3298 const char *lvalue,
3299 int ltype,
3300 const char *rvalue,
3301 void *data,
3302 void *userdata) {
3303
3304 _cleanup_free_ char *path = NULL;
3305 CGroupIODeviceWeight *w;
3306 CGroupContext *c = data;
3307 const char *weight;
3308 uint64_t u;
3309 size_t n;
3310 int r;
3311
3312 assert(filename);
3313 assert(lvalue);
3314 assert(rvalue);
3315
3316 if (isempty(rvalue)) {
3317 while (c->io_device_weights)
3318 cgroup_context_free_io_device_weight(c, c->io_device_weights);
3319
3320 return 0;
3321 }
3322
3323 n = strcspn(rvalue, WHITESPACE);
3324 weight = rvalue + n;
3325 weight += strspn(weight, WHITESPACE);
3326
3327 if (isempty(weight)) {
3328 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3329 return 0;
3330 }
3331
3332 path = strndup(rvalue, n);
3333 if (!path)
3334 return log_oom();
3335
3336 if (!path_startswith(path, "/dev")) {
3337 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3338 return 0;
3339 }
3340
3341 r = cg_weight_parse(weight, &u);
3342 if (r < 0) {
3343 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
3344 return 0;
3345 }
3346
3347 assert(u != CGROUP_WEIGHT_INVALID);
3348
3349 w = new0(CGroupIODeviceWeight, 1);
3350 if (!w)
3351 return log_oom();
3352
3353 w->path = path;
3354 path = NULL;
3355
3356 w->weight = u;
3357
3358 LIST_PREPEND(device_weights, c->io_device_weights, w);
3359 return 0;
3360 }
3361
3362 int config_parse_io_limit(
3363 const char *unit,
3364 const char *filename,
3365 unsigned line,
3366 const char *section,
3367 unsigned section_line,
3368 const char *lvalue,
3369 int ltype,
3370 const char *rvalue,
3371 void *data,
3372 void *userdata) {
3373
3374 _cleanup_free_ char *path = NULL;
3375 CGroupIODeviceLimit *l = NULL, *t;
3376 CGroupContext *c = data;
3377 CGroupIOLimitType type;
3378 const char *limit;
3379 uint64_t num;
3380 size_t n;
3381 int r;
3382
3383 assert(filename);
3384 assert(lvalue);
3385 assert(rvalue);
3386
3387 type = cgroup_io_limit_type_from_string(lvalue);
3388 assert(type >= 0);
3389
3390 if (isempty(rvalue)) {
3391 LIST_FOREACH(device_limits, l, c->io_device_limits)
3392 l->limits[type] = cgroup_io_limit_defaults[type];
3393 return 0;
3394 }
3395
3396 n = strcspn(rvalue, WHITESPACE);
3397 limit = rvalue + n;
3398 limit += strspn(limit, WHITESPACE);
3399
3400 if (!*limit) {
3401 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3402 return 0;
3403 }
3404
3405 path = strndup(rvalue, n);
3406 if (!path)
3407 return log_oom();
3408
3409 if (!path_startswith(path, "/dev")) {
3410 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3411 return 0;
3412 }
3413
3414 if (streq("infinity", limit)) {
3415 num = CGROUP_LIMIT_MAX;
3416 } else {
3417 r = parse_size(limit, 1000, &num);
3418 if (r < 0 || num <= 0) {
3419 log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
3420 return 0;
3421 }
3422 }
3423
3424 LIST_FOREACH(device_limits, t, c->io_device_limits) {
3425 if (path_equal(path, t->path)) {
3426 l = t;
3427 break;
3428 }
3429 }
3430
3431 if (!l) {
3432 CGroupIOLimitType ttype;
3433
3434 l = new0(CGroupIODeviceLimit, 1);
3435 if (!l)
3436 return log_oom();
3437
3438 l->path = path;
3439 path = NULL;
3440 for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
3441 l->limits[ttype] = cgroup_io_limit_defaults[ttype];
3442
3443 LIST_PREPEND(device_limits, c->io_device_limits, l);
3444 }
3445
3446 l->limits[type] = num;
3447
3448 return 0;
3449 }
3450
3451 int config_parse_blockio_weight(
3452 const char *unit,
3453 const char *filename,
3454 unsigned line,
3455 const char *section,
3456 unsigned section_line,
3457 const char *lvalue,
3458 int ltype,
3459 const char *rvalue,
3460 void *data,
3461 void *userdata) {
3462
3463 uint64_t *weight = data;
3464 int r;
3465
3466 assert(filename);
3467 assert(lvalue);
3468 assert(rvalue);
3469
3470 r = cg_blkio_weight_parse(rvalue, weight);
3471 if (r < 0) {
3472 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
3473 return 0;
3474 }
3475
3476 return 0;
3477 }
3478
3479 int config_parse_blockio_device_weight(
3480 const char *unit,
3481 const char *filename,
3482 unsigned line,
3483 const char *section,
3484 unsigned section_line,
3485 const char *lvalue,
3486 int ltype,
3487 const char *rvalue,
3488 void *data,
3489 void *userdata) {
3490
3491 _cleanup_free_ char *path = NULL;
3492 CGroupBlockIODeviceWeight *w;
3493 CGroupContext *c = data;
3494 const char *weight;
3495 uint64_t u;
3496 size_t n;
3497 int r;
3498
3499 assert(filename);
3500 assert(lvalue);
3501 assert(rvalue);
3502
3503 if (isempty(rvalue)) {
3504 while (c->blockio_device_weights)
3505 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
3506
3507 return 0;
3508 }
3509
3510 n = strcspn(rvalue, WHITESPACE);
3511 weight = rvalue + n;
3512 weight += strspn(weight, WHITESPACE);
3513
3514 if (isempty(weight)) {
3515 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
3516 return 0;
3517 }
3518
3519 path = strndup(rvalue, n);
3520 if (!path)
3521 return log_oom();
3522
3523 if (!path_startswith(path, "/dev")) {
3524 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3525 return 0;
3526 }
3527
3528 r = cg_blkio_weight_parse(weight, &u);
3529 if (r < 0) {
3530 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
3531 return 0;
3532 }
3533
3534 assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
3535
3536 w = new0(CGroupBlockIODeviceWeight, 1);
3537 if (!w)
3538 return log_oom();
3539
3540 w->path = path;
3541 path = NULL;
3542
3543 w->weight = u;
3544
3545 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
3546 return 0;
3547 }
3548
3549 int config_parse_blockio_bandwidth(
3550 const char *unit,
3551 const char *filename,
3552 unsigned line,
3553 const char *section,
3554 unsigned section_line,
3555 const char *lvalue,
3556 int ltype,
3557 const char *rvalue,
3558 void *data,
3559 void *userdata) {
3560
3561 _cleanup_free_ char *path = NULL;
3562 CGroupBlockIODeviceBandwidth *b = NULL, *t;
3563 CGroupContext *c = data;
3564 const char *bandwidth;
3565 uint64_t bytes;
3566 bool read;
3567 size_t n;
3568 int r;
3569
3570 assert(filename);
3571 assert(lvalue);
3572 assert(rvalue);
3573
3574 read = streq("BlockIOReadBandwidth", lvalue);
3575
3576 if (isempty(rvalue)) {
3577 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
3578 b->rbps = CGROUP_LIMIT_MAX;
3579 b->wbps = CGROUP_LIMIT_MAX;
3580 }
3581 return 0;
3582 }
3583
3584 n = strcspn(rvalue, WHITESPACE);
3585 bandwidth = rvalue + n;
3586 bandwidth += strspn(bandwidth, WHITESPACE);
3587
3588 if (!*bandwidth) {
3589 log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3590 return 0;
3591 }
3592
3593 path = strndup(rvalue, n);
3594 if (!path)
3595 return log_oom();
3596
3597 if (!path_startswith(path, "/dev")) {
3598 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
3599 return 0;
3600 }
3601
3602 r = parse_size(bandwidth, 1000, &bytes);
3603 if (r < 0 || bytes <= 0) {
3604 log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
3605 return 0;
3606 }
3607
3608 LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
3609 if (path_equal(path, t->path)) {
3610 b = t;
3611 break;
3612 }
3613 }
3614
3615 if (!t) {
3616 b = new0(CGroupBlockIODeviceBandwidth, 1);
3617 if (!b)
3618 return log_oom();
3619
3620 b->path = path;
3621 path = NULL;
3622 b->rbps = CGROUP_LIMIT_MAX;
3623 b->wbps = CGROUP_LIMIT_MAX;
3624
3625 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3626 }
3627
3628 if (read)
3629 b->rbps = bytes;
3630 else
3631 b->wbps = bytes;
3632
3633 return 0;
3634 }
3635
3636 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3637
3638 int config_parse_job_mode_isolate(
3639 const char *unit,
3640 const char *filename,
3641 unsigned line,
3642 const char *section,
3643 unsigned section_line,
3644 const char *lvalue,
3645 int ltype,
3646 const char *rvalue,
3647 void *data,
3648 void *userdata) {
3649
3650 JobMode *m = data;
3651 int r;
3652
3653 assert(filename);
3654 assert(lvalue);
3655 assert(rvalue);
3656
3657 r = parse_boolean(rvalue);
3658 if (r < 0) {
3659 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
3660 return 0;
3661 }
3662
3663 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3664 return 0;
3665 }
3666
3667 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
3668
3669 int config_parse_exec_directories(
3670 const char *unit,
3671 const char *filename,
3672 unsigned line,
3673 const char *section,
3674 unsigned section_line,
3675 const char *lvalue,
3676 int ltype,
3677 const char *rvalue,
3678 void *data,
3679 void *userdata) {
3680
3681 char***rt = data;
3682 Unit *u = userdata;
3683 const char *p;
3684 int r;
3685
3686 assert(filename);
3687 assert(lvalue);
3688 assert(rvalue);
3689 assert(data);
3690
3691 if (isempty(rvalue)) {
3692 /* Empty assignment resets the list */
3693 *rt = strv_free(*rt);
3694 return 0;
3695 }
3696
3697 for (p = rvalue;;) {
3698 _cleanup_free_ char *word = NULL, *k = NULL;
3699
3700 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
3701 if (r == -ENOMEM)
3702 return log_oom();
3703 if (r < 0) {
3704 log_syntax(unit, LOG_WARNING, filename, line, r,
3705 "Invalid syntax, ignoring: %s", rvalue);
3706 return 0;
3707 }
3708 if (r == 0)
3709 return 0;
3710
3711 r = unit_full_printf(u, word, &k);
3712 if (r < 0) {
3713 log_syntax(unit, LOG_ERR, filename, line, r,
3714 "Failed to resolve specifiers in \"%s\", ignoring: %m", word);
3715 continue;
3716 }
3717
3718 if (!path_is_safe(k) || path_is_absolute(k)) {
3719 log_syntax(unit, LOG_ERR, filename, line, 0,
3720 "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue);
3721 continue;
3722 }
3723
3724 r = strv_push(rt, k);
3725 if (r < 0)
3726 return log_oom();
3727 k = NULL;
3728 }
3729 }
3730
3731 int config_parse_set_status(
3732 const char *unit,
3733 const char *filename,
3734 unsigned line,
3735 const char *section,
3736 unsigned section_line,
3737 const char *lvalue,
3738 int ltype,
3739 const char *rvalue,
3740 void *data,
3741 void *userdata) {
3742
3743 size_t l;
3744 const char *word, *state;
3745 int r;
3746 ExitStatusSet *status_set = data;
3747
3748 assert(filename);
3749 assert(lvalue);
3750 assert(rvalue);
3751 assert(data);
3752
3753 /* Empty assignment resets the list */
3754 if (isempty(rvalue)) {
3755 exit_status_set_free(status_set);
3756 return 0;
3757 }
3758
3759 FOREACH_WORD(word, l, rvalue, state) {
3760 _cleanup_free_ char *temp;
3761 int val;
3762 Set **set;
3763
3764 temp = strndup(word, l);
3765 if (!temp)
3766 return log_oom();
3767
3768 r = safe_atoi(temp, &val);
3769 if (r < 0) {
3770 val = signal_from_string_try_harder(temp);
3771
3772 if (val <= 0) {
3773 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
3774 continue;
3775 }
3776 set = &status_set->signal;
3777 } else {
3778 if (val < 0 || val > 255) {
3779 log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
3780 continue;
3781 }
3782 set = &status_set->status;
3783 }
3784
3785 r = set_ensure_allocated(set, NULL);
3786 if (r < 0)
3787 return log_oom();
3788
3789 r = set_put(*set, INT_TO_PTR(val));
3790 if (r < 0) {
3791 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
3792 return r;
3793 }
3794 }
3795 if (!isempty(state))
3796 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
3797
3798 return 0;
3799 }
3800
3801 int config_parse_namespace_path_strv(
3802 const char *unit,
3803 const char *filename,
3804 unsigned line,
3805 const char *section,
3806 unsigned section_line,
3807 const char *lvalue,
3808 int ltype,
3809 const char *rvalue,
3810 void *data,
3811 void *userdata) {
3812
3813 Unit *u = userdata;
3814 char*** sv = data;
3815 const char *cur;
3816 int r;
3817
3818 assert(filename);
3819 assert(lvalue);
3820 assert(rvalue);
3821 assert(data);
3822
3823 if (isempty(rvalue)) {
3824 /* Empty assignment resets the list */
3825 *sv = strv_free(*sv);
3826 return 0;
3827 }
3828
3829 cur = rvalue;
3830 for (;;) {
3831 _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
3832 const char *w;
3833 bool ignore_enoent = false, shall_prefix = false;
3834
3835 r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
3836 if (r == 0)
3837 break;
3838 if (r == -ENOMEM)
3839 return log_oom();
3840 if (r < 0) {
3841 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
3842 return 0;
3843 }
3844
3845 if (!utf8_is_valid(word)) {
3846 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
3847 continue;
3848 }
3849
3850 w = word;
3851 if (startswith(w, "-")) {
3852 ignore_enoent = true;
3853 w++;
3854 }
3855 if (startswith(w, "+")) {
3856 shall_prefix = true;
3857 w++;
3858 }
3859
3860 r = unit_full_printf(u, w, &resolved);
3861 if (r < 0) {
3862 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s: %m", word);
3863 continue;
3864 }
3865
3866 if (!path_is_absolute(resolved)) {
3867 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
3868 continue;
3869 }
3870
3871 path_kill_slashes(resolved);
3872
3873 joined = strjoin(ignore_enoent ? "-" : "",
3874 shall_prefix ? "+" : "",
3875 resolved);
3876
3877 r = strv_push(sv, joined);
3878 if (r < 0)
3879 return log_oom();
3880
3881 joined = NULL;
3882 }
3883
3884 return 0;
3885 }
3886
3887 int config_parse_bind_paths(
3888 const char *unit,
3889 const char *filename,
3890 unsigned line,
3891 const char *section,
3892 unsigned section_line,
3893 const char *lvalue,
3894 int ltype,
3895 const char *rvalue,
3896 void *data,
3897 void *userdata) {
3898
3899 ExecContext *c = data;
3900 Unit *u = userdata;
3901 const char *p;
3902 int r;
3903
3904 assert(filename);
3905 assert(lvalue);
3906 assert(rvalue);
3907 assert(data);
3908
3909 if (isempty(rvalue)) {
3910 /* Empty assignment resets the list */
3911 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
3912 c->bind_mounts = NULL;
3913 c->n_bind_mounts = 0;
3914 return 0;
3915 }
3916
3917 p = rvalue;
3918 for (;;) {
3919 _cleanup_free_ char *source = NULL, *destination = NULL;
3920 _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
3921 char *s = NULL, *d = NULL;
3922 bool rbind = true, ignore_enoent = false;
3923
3924 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
3925 if (r == 0)
3926 break;
3927 if (r == -ENOMEM)
3928 return log_oom();
3929 if (r < 0) {
3930 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
3931 return 0;
3932 }
3933
3934 r = unit_full_printf(u, source, &sresolved);
3935 if (r < 0) {
3936 log_syntax(unit, LOG_ERR, filename, line, r,
3937 "Failed to resolved specifiers in \"%s\", ignoring: %m", source);
3938 return 0;
3939 }
3940
3941 s = sresolved;
3942 if (s[0] == '-') {
3943 ignore_enoent = true;
3944 s++;
3945 }
3946
3947 if (!utf8_is_valid(s)) {
3948 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, s);
3949 return 0;
3950 }
3951 if (!path_is_absolute(s)) {
3952 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute source path, ignoring: %s", s);
3953 return 0;
3954 }
3955
3956 path_kill_slashes(s);
3957
3958 /* Optionally, the destination is specified. */
3959 if (p && p[-1] == ':') {
3960 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
3961 if (r == -ENOMEM)
3962 return log_oom();
3963 if (r < 0) {
3964 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
3965 return 0;
3966 }
3967 if (r == 0) {
3968 log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':': %s", rvalue);
3969 return 0;
3970 }
3971
3972 r = unit_full_printf(u, destination, &dresolved);
3973 if (r < 0) {
3974 log_syntax(unit, LOG_ERR, filename, line, r,
3975 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
3976 return 0;
3977 }
3978
3979 if (!utf8_is_valid(dresolved)) {
3980 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved);
3981 return 0;
3982 }
3983 if (!path_is_absolute(dresolved)) {
3984 log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved);
3985 return 0;
3986 }
3987
3988 d = path_kill_slashes(dresolved);
3989
3990 /* Optionally, there's also a short option string specified */
3991 if (p && p[-1] == ':') {
3992 _cleanup_free_ char *options = NULL;
3993
3994 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
3995 if (r == -ENOMEM)
3996 return log_oom();
3997 if (r < 0) {
3998 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
3999 return 0;
4000 }
4001
4002 if (isempty(options) || streq(options, "rbind"))
4003 rbind = true;
4004 else if (streq(options, "norbind"))
4005 rbind = false;
4006 else {
4007 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
4008 return 0;
4009 }
4010 }
4011 } else
4012 d = s;
4013
4014 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
4015 &(BindMount) {
4016 .source = s,
4017 .destination = d,
4018 .read_only = !!strstr(lvalue, "ReadOnly"),
4019 .recursive = rbind,
4020 .ignore_enoent = ignore_enoent,
4021 });
4022 if (r < 0)
4023 return log_oom();
4024 }
4025
4026 return 0;
4027 }
4028
4029 int config_parse_no_new_privileges(
4030 const char* unit,
4031 const char *filename,
4032 unsigned line,
4033 const char *section,
4034 unsigned section_line,
4035 const char *lvalue,
4036 int ltype,
4037 const char *rvalue,
4038 void *data,
4039 void *userdata) {
4040
4041 ExecContext *c = data;
4042 int k;
4043
4044 assert(filename);
4045 assert(lvalue);
4046 assert(rvalue);
4047 assert(data);
4048
4049 k = parse_boolean(rvalue);
4050 if (k < 0) {
4051 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
4052 return 0;
4053 }
4054
4055 c->no_new_privileges = k;
4056
4057 return 0;
4058 }
4059
4060 int config_parse_protect_home(
4061 const char* unit,
4062 const char *filename,
4063 unsigned line,
4064 const char *section,
4065 unsigned section_line,
4066 const char *lvalue,
4067 int ltype,
4068 const char *rvalue,
4069 void *data,
4070 void *userdata) {
4071
4072 ExecContext *c = data;
4073 int k;
4074
4075 assert(filename);
4076 assert(lvalue);
4077 assert(rvalue);
4078 assert(data);
4079
4080 /* Our enum shall be a superset of booleans, hence first try
4081 * to parse as boolean, and then as enum */
4082
4083 k = parse_boolean(rvalue);
4084 if (k > 0)
4085 c->protect_home = PROTECT_HOME_YES;
4086 else if (k == 0)
4087 c->protect_home = PROTECT_HOME_NO;
4088 else {
4089 ProtectHome h;
4090
4091 h = protect_home_from_string(rvalue);
4092 if (h < 0) {
4093 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
4094 return 0;
4095 }
4096
4097 c->protect_home = h;
4098 }
4099
4100 return 0;
4101 }
4102
4103 int config_parse_protect_system(
4104 const char* unit,
4105 const char *filename,
4106 unsigned line,
4107 const char *section,
4108 unsigned section_line,
4109 const char *lvalue,
4110 int ltype,
4111 const char *rvalue,
4112 void *data,
4113 void *userdata) {
4114
4115 ExecContext *c = data;
4116 int k;
4117
4118 assert(filename);
4119 assert(lvalue);
4120 assert(rvalue);
4121 assert(data);
4122
4123 /* Our enum shall be a superset of booleans, hence first try
4124 * to parse as boolean, and then as enum */
4125
4126 k = parse_boolean(rvalue);
4127 if (k > 0)
4128 c->protect_system = PROTECT_SYSTEM_YES;
4129 else if (k == 0)
4130 c->protect_system = PROTECT_SYSTEM_NO;
4131 else {
4132 ProtectSystem s;
4133
4134 s = protect_system_from_string(rvalue);
4135 if (s < 0) {
4136 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
4137 return 0;
4138 }
4139
4140 c->protect_system = s;
4141 }
4142
4143 return 0;
4144 }
4145
4146 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
4147
4148 int config_parse_job_timeout_sec(
4149 const char* unit,
4150 const char *filename,
4151 unsigned line,
4152 const char *section,
4153 unsigned section_line,
4154 const char *lvalue,
4155 int ltype,
4156 const char *rvalue,
4157 void *data,
4158 void *userdata) {
4159
4160 Unit *u = data;
4161 usec_t usec;
4162 int r;
4163
4164 assert(filename);
4165 assert(lvalue);
4166 assert(rvalue);
4167 assert(u);
4168
4169 r = parse_sec_fix_0(rvalue, &usec);
4170 if (r < 0) {
4171 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
4172 return 0;
4173 }
4174
4175 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4176 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4177 * count. */
4178
4179 if (!u->job_running_timeout_set)
4180 u->job_running_timeout = usec;
4181
4182 u->job_timeout = usec;
4183
4184 return 0;
4185 }
4186
4187 int config_parse_job_running_timeout_sec(
4188 const char* unit,
4189 const char *filename,
4190 unsigned line,
4191 const char *section,
4192 unsigned section_line,
4193 const char *lvalue,
4194 int ltype,
4195 const char *rvalue,
4196 void *data,
4197 void *userdata) {
4198
4199 Unit *u = data;
4200 usec_t usec;
4201 int r;
4202
4203 assert(filename);
4204 assert(lvalue);
4205 assert(rvalue);
4206 assert(u);
4207
4208 r = parse_sec_fix_0(rvalue, &usec);
4209 if (r < 0) {
4210 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
4211 return 0;
4212 }
4213
4214 u->job_running_timeout = usec;
4215 u->job_running_timeout_set = true;
4216
4217 return 0;
4218 }
4219
4220 #define FOLLOW_MAX 8
4221
4222 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
4223 char *id = NULL;
4224 unsigned c = 0;
4225 int fd, r;
4226 FILE *f;
4227
4228 assert(filename);
4229 assert(*filename);
4230 assert(_f);
4231 assert(names);
4232
4233 /* This will update the filename pointer if the loaded file is
4234 * reached by a symlink. The old string will be freed. */
4235
4236 for (;;) {
4237 char *target, *name;
4238
4239 if (c++ >= FOLLOW_MAX)
4240 return -ELOOP;
4241
4242 path_kill_slashes(*filename);
4243
4244 /* Add the file name we are currently looking at to
4245 * the names of this unit, but only if it is a valid
4246 * unit name. */
4247 name = basename(*filename);
4248 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
4249
4250 id = set_get(names, name);
4251 if (!id) {
4252 id = strdup(name);
4253 if (!id)
4254 return -ENOMEM;
4255
4256 r = set_consume(names, id);
4257 if (r < 0)
4258 return r;
4259 }
4260 }
4261
4262 /* Try to open the file name, but don't if its a symlink */
4263 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
4264 if (fd >= 0)
4265 break;
4266
4267 if (errno != ELOOP)
4268 return -errno;
4269
4270 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4271 r = readlink_and_make_absolute(*filename, &target);
4272 if (r < 0)
4273 return r;
4274
4275 free(*filename);
4276 *filename = target;
4277 }
4278
4279 f = fdopen(fd, "re");
4280 if (!f) {
4281 safe_close(fd);
4282 return -errno;
4283 }
4284
4285 *_f = f;
4286 *_final = id;
4287
4288 return 0;
4289 }
4290
4291 static int merge_by_names(Unit **u, Set *names, const char *id) {
4292 char *k;
4293 int r;
4294
4295 assert(u);
4296 assert(*u);
4297 assert(names);
4298
4299 /* Let's try to add in all symlink names we found */
4300 while ((k = set_steal_first(names))) {
4301
4302 /* First try to merge in the other name into our
4303 * unit */
4304 r = unit_merge_by_name(*u, k);
4305 if (r < 0) {
4306 Unit *other;
4307
4308 /* Hmm, we couldn't merge the other unit into
4309 * ours? Then let's try it the other way
4310 * round */
4311
4312 /* If the symlink name we are looking at is unit template, then
4313 we must search for instance of this template */
4314 if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
4315 _cleanup_free_ char *instance = NULL;
4316
4317 r = unit_name_replace_instance(k, (*u)->instance, &instance);
4318 if (r < 0)
4319 return r;
4320
4321 other = manager_get_unit((*u)->manager, instance);
4322 } else
4323 other = manager_get_unit((*u)->manager, k);
4324
4325 free(k);
4326
4327 if (other) {
4328 r = unit_merge(other, *u);
4329 if (r >= 0) {
4330 *u = other;
4331 return merge_by_names(u, names, NULL);
4332 }
4333 }
4334
4335 return r;
4336 }
4337
4338 if (id == k)
4339 unit_choose_id(*u, id);
4340
4341 free(k);
4342 }
4343
4344 return 0;
4345 }
4346
4347 static int load_from_path(Unit *u, const char *path) {
4348 _cleanup_set_free_free_ Set *symlink_names = NULL;
4349 _cleanup_fclose_ FILE *f = NULL;
4350 _cleanup_free_ char *filename = NULL;
4351 char *id = NULL;
4352 Unit *merged;
4353 struct stat st;
4354 int r;
4355
4356 assert(u);
4357 assert(path);
4358
4359 symlink_names = set_new(&string_hash_ops);
4360 if (!symlink_names)
4361 return -ENOMEM;
4362
4363 if (path_is_absolute(path)) {
4364
4365 filename = strdup(path);
4366 if (!filename)
4367 return -ENOMEM;
4368
4369 r = open_follow(&filename, &f, symlink_names, &id);
4370 if (r < 0) {
4371 filename = mfree(filename);
4372 if (r != -ENOENT)
4373 return r;
4374 }
4375
4376 } else {
4377 char **p;
4378
4379 STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
4380
4381 /* Instead of opening the path right away, we manually
4382 * follow all symlinks and add their name to our unit
4383 * name set while doing so */
4384 filename = path_make_absolute(path, *p);
4385 if (!filename)
4386 return -ENOMEM;
4387
4388 if (u->manager->unit_path_cache &&
4389 !set_get(u->manager->unit_path_cache, filename))
4390 r = -ENOENT;
4391 else
4392 r = open_follow(&filename, &f, symlink_names, &id);
4393 if (r >= 0)
4394 break;
4395 filename = mfree(filename);
4396
4397 /* ENOENT means that the file is missing or is a dangling symlink.
4398 * ENOTDIR means that one of paths we expect to be is a directory
4399 * is not a directory, we should just ignore that.
4400 * EACCES means that the directory or file permissions are wrong.
4401 */
4402 if (r == -EACCES)
4403 log_debug_errno(r, "Cannot access \"%s\": %m", filename);
4404 else if (!IN_SET(r, -ENOENT, -ENOTDIR))
4405 return r;
4406
4407 /* Empty the symlink names for the next run */
4408 set_clear_free(symlink_names);
4409 }
4410 }
4411
4412 if (!filename)
4413 /* Hmm, no suitable file found? */
4414 return 0;
4415
4416 if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
4417 log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
4418 return -ELOOP;
4419 }
4420
4421 merged = u;
4422 r = merge_by_names(&merged, symlink_names, id);
4423 if (r < 0)
4424 return r;
4425
4426 if (merged != u) {
4427 u->load_state = UNIT_MERGED;
4428 return 0;
4429 }
4430
4431 if (fstat(fileno(f), &st) < 0)
4432 return -errno;
4433
4434 if (null_or_empty(&st)) {
4435 u->load_state = UNIT_MASKED;
4436 u->fragment_mtime = 0;
4437 } else {
4438 u->load_state = UNIT_LOADED;
4439 u->fragment_mtime = timespec_load(&st.st_mtim);
4440
4441 /* Now, parse the file contents */
4442 r = config_parse(u->id, filename, f,
4443 UNIT_VTABLE(u)->sections,
4444 config_item_perf_lookup, load_fragment_gperf_lookup,
4445 false, true, false, u);
4446 if (r < 0)
4447 return r;
4448 }
4449
4450 free(u->fragment_path);
4451 u->fragment_path = filename;
4452 filename = NULL;
4453
4454 if (u->source_path) {
4455 if (stat(u->source_path, &st) >= 0)
4456 u->source_mtime = timespec_load(&st.st_mtim);
4457 else
4458 u->source_mtime = 0;
4459 }
4460
4461 return 0;
4462 }
4463
4464 int unit_load_fragment(Unit *u) {
4465 int r;
4466 Iterator i;
4467 const char *t;
4468
4469 assert(u);
4470 assert(u->load_state == UNIT_STUB);
4471 assert(u->id);
4472
4473 if (u->transient) {
4474 u->load_state = UNIT_LOADED;
4475 return 0;
4476 }
4477
4478 /* First, try to find the unit under its id. We always look
4479 * for unit files in the default directories, to make it easy
4480 * to override things by placing things in /etc/systemd/system */
4481 r = load_from_path(u, u->id);
4482 if (r < 0)
4483 return r;
4484
4485 /* Try to find an alias we can load this with */
4486 if (u->load_state == UNIT_STUB) {
4487 SET_FOREACH(t, u->names, i) {
4488
4489 if (t == u->id)
4490 continue;
4491
4492 r = load_from_path(u, t);
4493 if (r < 0)
4494 return r;
4495
4496 if (u->load_state != UNIT_STUB)
4497 break;
4498 }
4499 }
4500
4501 /* And now, try looking for it under the suggested (originally linked) path */
4502 if (u->load_state == UNIT_STUB && u->fragment_path) {
4503
4504 r = load_from_path(u, u->fragment_path);
4505 if (r < 0)
4506 return r;
4507
4508 if (u->load_state == UNIT_STUB)
4509 /* Hmm, this didn't work? Then let's get rid
4510 * of the fragment path stored for us, so that
4511 * we don't point to an invalid location. */
4512 u->fragment_path = mfree(u->fragment_path);
4513 }
4514
4515 /* Look for a template */
4516 if (u->load_state == UNIT_STUB && u->instance) {
4517 _cleanup_free_ char *k = NULL;
4518
4519 r = unit_name_template(u->id, &k);
4520 if (r < 0)
4521 return r;
4522
4523 r = load_from_path(u, k);
4524 if (r < 0) {
4525 if (r == -ENOEXEC)
4526 log_unit_notice(u, "Unit configuration has fatal error, unit will not be started.");
4527 return r;
4528 }
4529
4530 if (u->load_state == UNIT_STUB) {
4531 SET_FOREACH(t, u->names, i) {
4532 _cleanup_free_ char *z = NULL;
4533
4534 if (t == u->id)
4535 continue;
4536
4537 r = unit_name_template(t, &z);
4538 if (r < 0)
4539 return r;
4540
4541 r = load_from_path(u, z);
4542 if (r < 0)
4543 return r;
4544
4545 if (u->load_state != UNIT_STUB)
4546 break;
4547 }
4548 }
4549 }
4550
4551 return 0;
4552 }
4553
4554 void unit_dump_config_items(FILE *f) {
4555 static const struct {
4556 const ConfigParserCallback callback;
4557 const char *rvalue;
4558 } table[] = {
4559 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4560 { config_parse_warn_compat, "NOTSUPPORTED" },
4561 #endif
4562 { config_parse_int, "INTEGER" },
4563 { config_parse_unsigned, "UNSIGNED" },
4564 { config_parse_iec_size, "SIZE" },
4565 { config_parse_iec_uint64, "SIZE" },
4566 { config_parse_si_size, "SIZE" },
4567 { config_parse_bool, "BOOLEAN" },
4568 { config_parse_string, "STRING" },
4569 { config_parse_path, "PATH" },
4570 { config_parse_unit_path_printf, "PATH" },
4571 { config_parse_strv, "STRING [...]" },
4572 { config_parse_exec_nice, "NICE" },
4573 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
4574 { config_parse_exec_io_class, "IOCLASS" },
4575 { config_parse_exec_io_priority, "IOPRIORITY" },
4576 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
4577 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
4578 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
4579 { config_parse_mode, "MODE" },
4580 { config_parse_unit_env_file, "FILE" },
4581 { config_parse_exec_output, "OUTPUT" },
4582 { config_parse_exec_input, "INPUT" },
4583 { config_parse_log_facility, "FACILITY" },
4584 { config_parse_log_level, "LEVEL" },
4585 { config_parse_exec_secure_bits, "SECUREBITS" },
4586 { config_parse_capability_set, "BOUNDINGSET" },
4587 { config_parse_limit, "LIMIT" },
4588 { config_parse_unit_deps, "UNIT [...]" },
4589 { config_parse_exec, "PATH [ARGUMENT [...]]" },
4590 { config_parse_service_type, "SERVICETYPE" },
4591 { config_parse_service_restart, "SERVICERESTART" },
4592 #if HAVE_SYSV_COMPAT
4593 { config_parse_sysv_priority, "SYSVPRIORITY" },
4594 #endif
4595 { config_parse_kill_mode, "KILLMODE" },
4596 { config_parse_signal, "SIGNAL" },
4597 { config_parse_socket_listen, "SOCKET [...]" },
4598 { config_parse_socket_bind, "SOCKETBIND" },
4599 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
4600 { config_parse_sec, "SECONDS" },
4601 { config_parse_nsec, "NANOSECONDS" },
4602 { config_parse_namespace_path_strv, "PATH [...]" },
4603 { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
4604 { config_parse_unit_requires_mounts_for, "PATH [...]" },
4605 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
4606 { config_parse_unit_string_printf, "STRING" },
4607 { config_parse_trigger_unit, "UNIT" },
4608 { config_parse_timer, "TIMER" },
4609 { config_parse_path_spec, "PATH" },
4610 { config_parse_notify_access, "ACCESS" },
4611 { config_parse_ip_tos, "TOS" },
4612 { config_parse_unit_condition_path, "CONDITION" },
4613 { config_parse_unit_condition_string, "CONDITION" },
4614 { config_parse_unit_condition_null, "CONDITION" },
4615 { config_parse_unit_slice, "SLICE" },
4616 { config_parse_documentation, "URL" },
4617 { config_parse_service_timeout, "SECONDS" },
4618 { config_parse_emergency_action, "ACTION" },
4619 { config_parse_set_status, "STATUS" },
4620 { config_parse_service_sockets, "SOCKETS" },
4621 { config_parse_environ, "ENVIRON" },
4622 #if HAVE_SECCOMP
4623 { config_parse_syscall_filter, "SYSCALLS" },
4624 { config_parse_syscall_archs, "ARCHS" },
4625 { config_parse_syscall_errno, "ERRNO" },
4626 { config_parse_address_families, "FAMILIES" },
4627 { config_parse_restrict_namespaces, "NAMESPACES" },
4628 #endif
4629 { config_parse_cpu_shares, "SHARES" },
4630 { config_parse_cpu_weight, "WEIGHT" },
4631 { config_parse_memory_limit, "LIMIT" },
4632 { config_parse_device_allow, "DEVICE" },
4633 { config_parse_device_policy, "POLICY" },
4634 { config_parse_io_limit, "LIMIT" },
4635 { config_parse_io_weight, "WEIGHT" },
4636 { config_parse_io_device_weight, "DEVICEWEIGHT" },
4637 { config_parse_blockio_bandwidth, "BANDWIDTH" },
4638 { config_parse_blockio_weight, "WEIGHT" },
4639 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
4640 { config_parse_long, "LONG" },
4641 { config_parse_socket_service, "SERVICE" },
4642 #if HAVE_SELINUX
4643 { config_parse_exec_selinux_context, "LABEL" },
4644 #endif
4645 { config_parse_job_mode, "MODE" },
4646 { config_parse_job_mode_isolate, "BOOLEAN" },
4647 { config_parse_personality, "PERSONALITY" },
4648 };
4649
4650 const char *prev = NULL;
4651 const char *i;
4652
4653 assert(f);
4654
4655 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
4656 const char *rvalue = "OTHER", *lvalue;
4657 unsigned j;
4658 size_t prefix_len;
4659 const char *dot;
4660 const ConfigPerfItem *p;
4661
4662 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
4663
4664 dot = strchr(i, '.');
4665 lvalue = dot ? dot + 1 : i;
4666 prefix_len = dot-i;
4667
4668 if (dot)
4669 if (!prev || !strneq(prev, i, prefix_len+1)) {
4670 if (prev)
4671 fputc('\n', f);
4672
4673 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
4674 }
4675
4676 for (j = 0; j < ELEMENTSOF(table); j++)
4677 if (p->parse == table[j].callback) {
4678 rvalue = table[j].rvalue;
4679 break;
4680 }
4681
4682 fprintf(f, "%s=%s\n", lvalue, rvalue);
4683 prev = i;
4684 }
4685 }