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