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