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