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