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