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