1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
6 Copyright 2012 Holger Hans Peter Freyther
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.
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.
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/>.
25 #include <linux/oom.h>
31 #include <sys/resource.h>
35 #include "alloc-util.h"
36 #include "bus-error.h"
37 #include "bus-internal.h"
40 #include "capability-util.h"
42 #include "conf-parser.h"
43 #include "cpu-set-util.h"
45 #include "errno-list.h"
49 #include "hexdecoct.h"
52 #include "journal-util.h"
53 #include "load-fragment.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"
62 #include "seccomp-util.h"
64 #include "securebits.h"
65 #include "securebits-util.h"
66 #include "signal-util.h"
67 #include "stat-util.h"
68 #include "string-util.h"
70 #include "unit-name.h"
71 #include "unit-printf.h"
73 #include "user-util.h"
77 int config_parse_warn_compat(
82 unsigned section_line
,
88 Disabled reason
= ltype
;
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
);
96 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
97 "Support for option %s= has been removed and it is ignored", lvalue
);
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
);
108 DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode
, collect_mode
, CollectMode
, "Failed to parse garbage collection mode");
110 int config_parse_unit_deps(
112 const char *filename
,
115 unsigned section_line
,
122 UnitDependency d
= ltype
;
132 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
135 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
141 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
145 r
= unit_name_printf(u
, word
, &k
);
147 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
151 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
159 int config_parse_obsolete_unit_deps(
161 const char *filename
,
164 unsigned section_line
,
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
));
174 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
177 int config_parse_unit_string_printf(
179 const char *filename
,
182 unsigned section_line
,
189 _cleanup_free_
char *k
= NULL
;
198 r
= unit_full_printf(u
, rvalue
, &k
);
200 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
204 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
207 int config_parse_unit_strv_printf(
209 const char *filename
,
212 unsigned section_line
,
220 _cleanup_free_
char *k
= NULL
;
228 r
= unit_full_printf(u
, rvalue
, &k
);
230 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
234 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
237 int config_parse_unit_path_printf(
239 const char *filename
,
242 unsigned section_line
,
249 _cleanup_free_
char *k
= NULL
;
259 r
= unit_full_printf(u
, rvalue
, &k
);
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;
267 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
270 int config_parse_unit_path_strv_printf(
272 const char *filename
,
275 unsigned section_line
,
292 if (isempty(rvalue
)) {
298 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
300 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
306 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
307 "Invalid syntax, ignoring: %s", rvalue
);
311 r
= unit_full_printf(u
, word
, &k
);
313 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
314 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
318 if (!utf8_is_valid(k
)) {
319 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
323 if (!path_is_absolute(k
)) {
324 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
325 "Symlink path is not absolute: %s", k
);
329 path_kill_slashes(k
);
338 int config_parse_socket_listen(const char *unit
,
339 const char *filename
,
342 unsigned section_line
,
349 _cleanup_free_ SocketPort
*p
= NULL
;
361 if (isempty(rvalue
)) {
362 /* An empty assignment removes all ports */
363 socket_free_ports(s
);
367 p
= new0(SocketPort
, 1);
371 if (ltype
!= SOCKET_SOCKET
) {
374 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
376 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
380 path_kill_slashes(p
->path
);
382 } else if (streq(lvalue
, "ListenNetlink")) {
383 _cleanup_free_
char *k
= NULL
;
385 p
->type
= SOCKET_SOCKET
;
386 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
388 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
392 r
= socket_address_parse_netlink(&p
->address
, k
);
394 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
399 _cleanup_free_
char *k
= NULL
;
401 p
->type
= SOCKET_SOCKET
;
402 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
404 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
408 r
= socket_address_parse_and_warn(&p
->address
, k
);
410 if (r
!= -EAFNOSUPPORT
)
411 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
416 if (streq(lvalue
, "ListenStream"))
417 p
->address
.type
= SOCK_STREAM
;
418 else if (streq(lvalue
, "ListenDatagram"))
419 p
->address
.type
= SOCK_DGRAM
;
421 assert(streq(lvalue
, "ListenSequentialPacket"));
422 p
->address
.type
= SOCK_SEQPACKET
;
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
);
432 p
->auxiliary_fds
= NULL
;
433 p
->n_auxiliary_fds
= 0;
437 LIST_FIND_TAIL(port
, s
->ports
, tail
);
438 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
440 LIST_PREPEND(port
, s
->ports
, p
);
446 int config_parse_socket_protocol(const char *unit
,
447 const char *filename
,
450 unsigned section_line
,
465 if (streq(rvalue
, "udplite"))
466 s
->socket_protocol
= IPPROTO_UDPLITE
;
467 else if (streq(rvalue
, "sctp"))
468 s
->socket_protocol
= IPPROTO_SCTP
;
470 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
477 int config_parse_socket_bind(const char *unit
,
478 const char *filename
,
481 unsigned section_line
,
489 SocketAddressBindIPv6Only b
;
498 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
502 r
= parse_boolean(rvalue
);
504 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
508 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
510 s
->bind_ipv6_only
= b
;
515 int config_parse_exec_nice(
517 const char *filename
,
520 unsigned section_line
,
527 ExecContext
*c
= data
;
535 r
= parse_nice(rvalue
, &priority
);
538 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
540 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
551 int config_parse_exec_oom_score_adjust(const char* unit
,
552 const char *filename
,
555 unsigned section_line
,
562 ExecContext
*c
= data
;
570 r
= safe_atoi(rvalue
, &oa
);
572 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
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
);
581 c
->oom_score_adjust
= oa
;
582 c
->oom_score_adjust_set
= true;
587 int config_parse_exec(
589 const char *filename
,
592 unsigned section_line
,
599 ExecCommand
**e
= data
;
611 rvalue
+= strspn(rvalue
, WHITESPACE
);
613 if (isempty(rvalue
)) {
614 /* An empty assignment resets the list */
615 *e
= exec_command_free_list(*e
);
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;
631 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
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.
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. */
649 if (*f
== '-' && !(flags
& EXEC_COMMAND_IGNORE_FAILURE
)) {
650 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
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
;
666 r
= unit_full_printf(u
, f
, &path
);
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
;
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
;
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
;
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
;
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
;
700 if (!separate_argv0
) {
703 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
713 path_kill_slashes(path
);
715 while (!isempty(p
)) {
716 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
718 /* Check explicitly for an unquoted semicolon as
719 * command separator token. */
720 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
722 p
+= strspn(p
, WHITESPACE
);
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]))) {
733 p
+= strspn(p
, WHITESPACE
);
735 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
746 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
750 return ignore
? 0 : -ENOEXEC
;
752 r
= unit_full_printf(u
, word
, &resolved
);
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
;
760 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
762 n
[nlen
++] = resolved
;
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
;
774 nce
= new0(ExecCommand
, 1);
782 exec_command_append_list(e
, nce
);
784 /* Do not _cleanup_free_ these. */
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");
798 int config_parse_socket_bindtodevice(
800 const char *filename
,
803 unsigned section_line
,
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
);
830 free(s
->bind_to_device
);
831 s
->bind_to_device
= n
;
836 int config_parse_exec_input(
838 const char *filename
,
841 unsigned section_line
,
848 ExecContext
*c
= data
;
859 n
= startswith(rvalue
, "fd:");
861 _cleanup_free_
char *resolved
= NULL
;
863 r
= unit_full_printf(u
, n
, &resolved
);
865 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
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
);
874 free_and_replace(c
->stdio_fdname
[STDIN_FILENO
], resolved
);
876 ei
= EXEC_INPUT_NAMED_FD
;
878 } else if ((n
= startswith(rvalue
, "file:"))) {
879 _cleanup_free_
char *resolved
= NULL
;
881 r
= unit_full_printf(u
, n
, &resolved
);
883 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
885 if (!path_is_absolute(resolved
)) {
886 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
890 if (!path_is_normalized(resolved
)) {
891 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name: %s", resolved
);
895 free_and_replace(c
->stdio_file
[STDIN_FILENO
], resolved
);
897 ei
= EXEC_INPUT_FILE
;
900 ei
= exec_input_from_string(rvalue
);
902 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
911 int config_parse_exec_input_text(
913 const char *filename
,
916 unsigned section_line
,
923 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
924 ExecContext
*c
= data
;
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;
942 r
= cunescape(rvalue
, 0, &unescaped
);
944 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode C escaped text: %s", rvalue
);
946 r
= unit_full_printf(u
, unescaped
, &resolved
);
948 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", unescaped
);
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
);
957 p
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
+ 1);
961 *((char*) mempcpy((char*) p
+ c
->stdin_data_size
, resolved
, sz
)) = '\n';
964 c
->stdin_data_size
+= sz
+ 1;
969 int config_parse_exec_input_data(
971 const char *filename
,
974 unsigned section_line
,
981 _cleanup_free_
char *cleaned
= NULL
;
982 _cleanup_free_
void *p
= NULL
;
983 ExecContext
*c
= data
;
993 if (isempty(rvalue
)) {
994 /* Reset if the empty string is assigned */
995 c
->stdin_data
= mfree(c
->stdin_data
);
996 c
->stdin_data_size
= 0;
1000 /* Be tolerant to whitespace. Remove it all before decoding */
1001 cleaned
= strdup(rvalue
);
1004 delete_chars(cleaned
, WHITESPACE
);
1006 r
= unbase64mem(cleaned
, (size_t) -1, &p
, &sz
);
1008 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode base64 data, ignoring: %s", cleaned
);
1012 if (c
->stdin_data_size
+ sz
< c
->stdin_data_size
|| /* check for overflow */
1013 c
->stdin_data_size
+ sz
> EXEC_STDIN_DATA_MAX
) {
1014 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
);
1018 q
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
);
1022 memcpy((uint8_t*) q
+ c
->stdin_data_size
, p
, sz
);
1025 c
->stdin_data_size
+= sz
;
1030 int config_parse_exec_output(
1032 const char *filename
,
1034 const char *section
,
1035 unsigned section_line
,
1042 _cleanup_free_
char *resolved
= NULL
;
1044 ExecContext
*c
= data
;
1055 n
= startswith(rvalue
, "fd:");
1057 r
= unit_full_printf(u
, n
, &resolved
);
1059 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1061 if (isempty(resolved
))
1062 resolved
= mfree(resolved
);
1063 else if (!fdname_is_valid(resolved
)) {
1064 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name: %s", resolved
);
1068 eo
= EXEC_OUTPUT_NAMED_FD
;
1070 } else if ((n
= startswith(rvalue
, "file:"))) {
1072 r
= unit_full_printf(u
, n
, &resolved
);
1074 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1076 if (!path_is_absolute(resolved
)) {
1077 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
1081 if (!path_is_normalized(resolved
)) {
1082 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name, ignoring: %s", resolved
);
1086 eo
= EXEC_OUTPUT_FILE
;
1089 eo
= exec_output_from_string(rvalue
);
1091 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
1096 if (streq(lvalue
, "StandardOutput")) {
1097 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1098 free_and_replace(c
->stdio_fdname
[STDOUT_FILENO
], resolved
);
1100 free_and_replace(c
->stdio_file
[STDOUT_FILENO
], resolved
);
1105 assert(streq(lvalue
, "StandardError"));
1107 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1108 free_and_replace(c
->stdio_fdname
[STDERR_FILENO
], resolved
);
1110 free_and_replace(c
->stdio_file
[STDERR_FILENO
], resolved
);
1118 int config_parse_exec_io_class(const char *unit
,
1119 const char *filename
,
1121 const char *section
,
1122 unsigned section_line
,
1129 ExecContext
*c
= data
;
1137 x
= ioprio_class_from_string(rvalue
);
1139 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
1143 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
1144 c
->ioprio_set
= true;
1149 int config_parse_exec_io_priority(const char *unit
,
1150 const char *filename
,
1152 const char *section
,
1153 unsigned section_line
,
1160 ExecContext
*c
= data
;
1168 r
= ioprio_parse_priority(rvalue
, &i
);
1170 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
1174 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
1175 c
->ioprio_set
= true;
1180 int config_parse_exec_cpu_sched_policy(const char *unit
,
1181 const char *filename
,
1183 const char *section
,
1184 unsigned section_line
,
1192 ExecContext
*c
= data
;
1200 x
= sched_policy_from_string(rvalue
);
1202 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1206 c
->cpu_sched_policy
= x
;
1207 /* Moving to or from real-time policy? We need to adjust the priority */
1208 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1209 c
->cpu_sched_set
= true;
1214 int config_parse_exec_cpu_sched_prio(const char *unit
,
1215 const char *filename
,
1217 const char *section
,
1218 unsigned section_line
,
1225 ExecContext
*c
= data
;
1233 r
= safe_atoi(rvalue
, &i
);
1235 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1239 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1240 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1241 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1243 if (i
< min
|| i
> max
) {
1244 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1248 c
->cpu_sched_priority
= i
;
1249 c
->cpu_sched_set
= true;
1254 int config_parse_exec_cpu_affinity(const char *unit
,
1255 const char *filename
,
1257 const char *section
,
1258 unsigned section_line
,
1265 ExecContext
*c
= data
;
1266 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1274 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1279 CPU_FREE(c
->cpuset
);
1282 /* An empty assignment resets the CPU list */
1288 c
->cpuset_ncpus
= ncpus
;
1293 int config_parse_exec_secure_bits(const char *unit
,
1294 const char *filename
,
1296 const char *section
,
1297 unsigned section_line
,
1304 ExecContext
*c
= data
;
1312 if (isempty(rvalue
)) {
1313 /* An empty assignment resets the field */
1318 r
= secure_bits_from_string(rvalue
);
1322 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1323 "Invalid syntax, ignoring: %s", rvalue
);
1332 int config_parse_capability_set(
1334 const char *filename
,
1336 const char *section
,
1337 unsigned section_line
,
1344 uint64_t *capability_set
= data
;
1345 uint64_t sum
= 0, initial
= 0;
1346 bool invert
= false;
1354 if (rvalue
[0] == '~') {
1359 if (streq(lvalue
, "CapabilityBoundingSet"))
1360 initial
= CAP_ALL
; /* initialized to all bits on */
1361 /* else "AmbientCapabilities" initialized to all bits off */
1363 r
= capability_set_from_string(rvalue
, &sum
);
1367 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1371 if (sum
== 0 || *capability_set
== initial
)
1372 /* "", "~" or uninitialized data -> replace */
1373 *capability_set
= invert
? ~sum
: sum
;
1375 /* previous data -> merge */
1377 *capability_set
&= ~sum
;
1379 *capability_set
|= sum
;
1385 int config_parse_limit(
1387 const char *filename
,
1389 const char *section
,
1390 unsigned section_line
,
1397 struct rlimit
**rl
= data
, d
= {};
1405 r
= rlimit_parse(ltype
, rvalue
, &d
);
1407 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1411 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1418 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1426 #if HAVE_SYSV_COMPAT
1427 int config_parse_sysv_priority(const char *unit
,
1428 const char *filename
,
1430 const char *section
,
1431 unsigned section_line
,
1438 int *priority
= data
;
1446 r
= safe_atoi(rvalue
, &i
);
1447 if (r
< 0 || i
< 0) {
1448 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1452 *priority
= (int) i
;
1457 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1458 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1460 int config_parse_exec_mount_flags(
1462 const char *filename
,
1464 const char *section
,
1465 unsigned section_line
,
1473 ExecContext
*c
= data
;
1481 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1483 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1488 int config_parse_exec_selinux_context(
1490 const char *filename
,
1492 const char *section
,
1493 unsigned section_line
,
1500 ExecContext
*c
= data
;
1511 if (isempty(rvalue
)) {
1512 c
->selinux_context
= mfree(c
->selinux_context
);
1513 c
->selinux_context_ignore
= false;
1517 if (rvalue
[0] == '-') {
1523 r
= unit_full_printf(u
, rvalue
, &k
);
1525 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1526 "Failed to resolve specifiers%s: %m",
1527 ignore
? ", ignoring" : "");
1528 return ignore
? 0 : -ENOEXEC
;
1531 free(c
->selinux_context
);
1532 c
->selinux_context
= k
;
1533 c
->selinux_context_ignore
= ignore
;
1538 int config_parse_exec_apparmor_profile(
1540 const char *filename
,
1542 const char *section
,
1543 unsigned section_line
,
1550 ExecContext
*c
= data
;
1561 if (isempty(rvalue
)) {
1562 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1563 c
->apparmor_profile_ignore
= false;
1567 if (rvalue
[0] == '-') {
1573 r
= unit_full_printf(u
, rvalue
, &k
);
1575 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1576 "Failed to resolve specifiers%s: %m",
1577 ignore
? ", ignoring" : "");
1578 return ignore
? 0 : -ENOEXEC
;
1581 free(c
->apparmor_profile
);
1582 c
->apparmor_profile
= k
;
1583 c
->apparmor_profile_ignore
= ignore
;
1588 int config_parse_exec_smack_process_label(
1590 const char *filename
,
1592 const char *section
,
1593 unsigned section_line
,
1600 ExecContext
*c
= data
;
1611 if (isempty(rvalue
)) {
1612 c
->smack_process_label
= mfree(c
->smack_process_label
);
1613 c
->smack_process_label_ignore
= false;
1617 if (rvalue
[0] == '-') {
1623 r
= unit_full_printf(u
, rvalue
, &k
);
1625 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1626 "Failed to resolve specifiers%s: %m",
1627 ignore
? ", ignoring" : "");
1628 return ignore
? 0 : -ENOEXEC
;
1631 free(c
->smack_process_label
);
1632 c
->smack_process_label
= k
;
1633 c
->smack_process_label_ignore
= ignore
;
1638 int config_parse_timer(const char *unit
,
1639 const char *filename
,
1641 const char *section
,
1642 unsigned section_line
,
1653 CalendarSpec
*c
= NULL
;
1655 _cleanup_free_
char *k
= NULL
;
1663 if (isempty(rvalue
)) {
1664 /* Empty assignment resets list */
1665 timer_free_values(t
);
1669 b
= timer_base_from_string(lvalue
);
1671 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1675 r
= unit_full_printf(u
, rvalue
, &k
);
1677 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1681 if (b
== TIMER_CALENDAR
) {
1682 if (calendar_spec_from_string(k
, &c
) < 0) {
1683 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1687 if (parse_sec(k
, &usec
) < 0) {
1688 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1693 v
= new0(TimerValue
, 1);
1695 calendar_spec_free(c
);
1701 v
->calendar_spec
= c
;
1703 LIST_PREPEND(value
, t
->values
, v
);
1708 int config_parse_trigger_unit(
1710 const char *filename
,
1712 const char *section
,
1713 unsigned section_line
,
1720 _cleanup_free_
char *p
= NULL
;
1730 if (!hashmap_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1731 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1735 r
= unit_name_printf(u
, rvalue
, &p
);
1737 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1741 type
= unit_name_to_type(p
);
1743 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1747 if (type
== u
->type
) {
1748 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1752 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1754 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1761 int config_parse_path_spec(const char *unit
,
1762 const char *filename
,
1764 const char *section
,
1765 unsigned section_line
,
1775 _cleanup_free_
char *k
= NULL
;
1783 if (isempty(rvalue
)) {
1784 /* Empty assignment clears list */
1789 b
= path_type_from_string(lvalue
);
1791 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1795 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1797 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1801 if (!path_is_absolute(k
)) {
1802 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1806 s
= new0(PathSpec
, 1);
1811 s
->path
= path_kill_slashes(k
);
1816 LIST_PREPEND(spec
, p
->specs
, s
);
1821 int config_parse_socket_service(
1823 const char *filename
,
1825 const char *section
,
1826 unsigned section_line
,
1833 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1834 _cleanup_free_
char *p
= NULL
;
1844 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1846 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1850 if (!endswith(p
, ".service")) {
1851 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1855 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1857 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1861 unit_ref_set(&s
->service
, x
);
1866 int config_parse_fdname(
1868 const char *filename
,
1870 const char *section
,
1871 unsigned section_line
,
1878 _cleanup_free_
char *p
= NULL
;
1887 if (isempty(rvalue
)) {
1888 s
->fdname
= mfree(s
->fdname
);
1892 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1894 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1898 if (!fdname_is_valid(p
)) {
1899 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1903 return free_and_replace(s
->fdname
, p
);
1906 int config_parse_service_sockets(
1908 const char *filename
,
1910 const char *section
,
1911 unsigned section_line
,
1929 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1931 r
= extract_first_word(&p
, &word
, NULL
, 0);
1937 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1941 r
= unit_name_printf(UNIT(s
), word
, &k
);
1943 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1947 if (!endswith(k
, ".socket")) {
1948 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1952 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1954 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1956 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1958 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1964 int config_parse_bus_name(
1966 const char *filename
,
1968 const char *section
,
1969 unsigned section_line
,
1976 _cleanup_free_
char *k
= NULL
;
1985 r
= unit_full_printf(u
, rvalue
, &k
);
1987 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1991 if (!service_name_is_valid(k
)) {
1992 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1996 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1999 int config_parse_service_timeout(
2001 const char *filename
,
2003 const char *section
,
2004 unsigned section_line
,
2011 Service
*s
= userdata
;
2020 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
2022 r
= parse_sec(rvalue
, &usec
);
2024 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2028 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
2029 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
2030 * all other timeouts. */
2032 usec
= USEC_INFINITY
;
2034 if (!streq(lvalue
, "TimeoutStopSec")) {
2035 s
->start_timeout_defined
= true;
2036 s
->timeout_start_usec
= usec
;
2039 if (!streq(lvalue
, "TimeoutStartSec"))
2040 s
->timeout_stop_usec
= usec
;
2045 int config_parse_sec_fix_0(
2047 const char *filename
,
2049 const char *section
,
2050 unsigned section_line
,
2057 usec_t
*usec
= data
;
2065 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
2066 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
2069 r
= parse_sec_fix_0(rvalue
, usec
);
2071 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2078 int config_parse_user_group(
2080 const char *filename
,
2082 const char *section
,
2083 unsigned section_line
,
2090 char **user
= data
, *n
;
2099 if (isempty(rvalue
))
2102 _cleanup_free_
char *k
= NULL
;
2104 r
= unit_full_printf(u
, rvalue
, &k
);
2106 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
2110 if (!valid_user_group_name_or_id(k
)) {
2111 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2125 int config_parse_user_group_strv(
2127 const char *filename
,
2129 const char *section
,
2130 unsigned section_line
,
2137 char ***users
= data
;
2147 if (isempty(rvalue
)) {
2148 *users
= strv_free(*users
);
2154 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2156 r
= extract_first_word(&p
, &word
, NULL
, 0);
2162 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
2166 r
= unit_full_printf(u
, word
, &k
);
2168 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
2172 if (!valid_user_group_name_or_id(k
)) {
2173 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2177 r
= strv_push(users
, k
);
2187 int config_parse_working_directory(
2189 const char *filename
,
2191 const char *section
,
2192 unsigned section_line
,
2199 ExecContext
*c
= data
;
2210 if (rvalue
[0] == '-') {
2216 if (streq(rvalue
, "~")) {
2217 c
->working_directory_home
= true;
2218 c
->working_directory
= mfree(c
->working_directory
);
2220 _cleanup_free_
char *k
= NULL
;
2222 r
= unit_full_printf(u
, rvalue
, &k
);
2224 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2225 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2226 rvalue
, missing_ok
? ", ignoring" : "");
2227 return missing_ok
? 0 : -ENOEXEC
;
2230 path_kill_slashes(k
);
2232 if (!utf8_is_valid(k
)) {
2233 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2234 return missing_ok
? 0 : -ENOEXEC
;
2237 if (!path_is_absolute(k
)) {
2238 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2239 "Working directory path '%s' is not absolute%s.",
2240 rvalue
, missing_ok
? ", ignoring" : "");
2241 return missing_ok
? 0 : -ENOEXEC
;
2244 c
->working_directory_home
= false;
2245 free_and_replace(c
->working_directory
, k
);
2248 c
->working_directory_missing_ok
= missing_ok
;
2252 int config_parse_unit_env_file(const char *unit
,
2253 const char *filename
,
2255 const char *section
,
2256 unsigned section_line
,
2265 _cleanup_free_
char *n
= NULL
;
2273 if (isempty(rvalue
)) {
2274 /* Empty assignment frees the list */
2275 *env
= strv_free(*env
);
2279 r
= unit_full_printf(u
, rvalue
, &n
);
2281 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2285 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2286 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2290 r
= strv_extend(env
, n
);
2297 int config_parse_environ(
2299 const char *filename
,
2301 const char *section
,
2302 unsigned section_line
,
2319 if (isempty(rvalue
)) {
2320 /* Empty assignment resets the list */
2321 *env
= strv_free(*env
);
2325 for (p
= rvalue
;; ) {
2326 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2328 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2334 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2335 "Invalid syntax, ignoring: %s", rvalue
);
2340 r
= unit_full_printf(u
, word
, &k
);
2342 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2343 "Failed to resolve specifiers, ignoring: %s", word
);
2351 if (!env_assignment_is_valid(k
)) {
2352 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2353 "Invalid environment assignment, ignoring: %s", k
);
2357 r
= strv_env_replace(env
, k
);
2365 int config_parse_pass_environ(
2367 const char *filename
,
2369 const char *section
,
2370 unsigned section_line
,
2377 const char *whole_rvalue
= rvalue
;
2378 _cleanup_strv_free_
char **n
= NULL
;
2379 size_t nlen
= 0, nbufsize
= 0;
2380 char*** passenv
= data
;
2389 if (isempty(rvalue
)) {
2390 /* Empty assignment resets the list */
2391 *passenv
= strv_free(*passenv
);
2396 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2398 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2404 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2405 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2410 r
= unit_full_printf(u
, word
, &k
);
2412 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2413 "Failed to resolve specifiers, ignoring: %s", word
);
2421 if (!env_name_is_valid(k
)) {
2422 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2423 "Invalid environment name for %s, ignoring: %s", lvalue
, k
);
2427 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2436 r
= strv_extend_strv(passenv
, n
, true);
2444 int config_parse_unset_environ(
2446 const char *filename
,
2448 const char *section
,
2449 unsigned section_line
,
2456 _cleanup_strv_free_
char **n
= NULL
;
2457 const char *whole_rvalue
= rvalue
;
2458 size_t nlen
= 0, nbufsize
= 0;
2459 char*** unsetenv
= data
;
2468 if (isempty(rvalue
)) {
2469 /* Empty assignment resets the list */
2470 *unsetenv
= strv_free(*unsetenv
);
2475 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2477 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2484 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2489 r
= unit_full_printf(u
, word
, &k
);
2491 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2492 "Failed to resolve specifiers, ignoring: %s", word
);
2500 if (!env_assignment_is_valid(k
) && !env_name_is_valid(k
)) {
2501 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2502 "Invalid environment name or assignment %s, ignoring: %s", lvalue
, k
);
2506 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2515 r
= strv_extend_strv(unsetenv
, n
, true);
2523 int config_parse_log_extra_fields(
2525 const char *filename
,
2527 const char *section
,
2528 unsigned section_line
,
2535 ExecContext
*c
= data
;
2545 if (isempty(rvalue
)) {
2546 exec_context_free_log_extra_fields(c
);
2550 for (p
= rvalue
;; ) {
2551 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2555 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2561 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2565 r
= unit_full_printf(u
, word
, &k
);
2567 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring field: %m", word
);
2571 eq
= strchr(k
, '=');
2573 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field lacks '=' character, ignoring field: %s", k
);
2577 if (!journal_field_valid(k
, eq
-k
, false)) {
2578 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field name is invalid, ignoring field: %s", k
);
2582 t
= realloc_multiply(c
->log_extra_fields
, sizeof(struct iovec
), c
->n_log_extra_fields
+1);
2586 c
->log_extra_fields
= t
;
2587 c
->log_extra_fields
[c
->n_log_extra_fields
++] = IOVEC_MAKE_STRING(k
);
2595 int config_parse_ip_tos(const char *unit
,
2596 const char *filename
,
2598 const char *section
,
2599 unsigned section_line
,
2606 int *ip_tos
= data
, x
;
2613 x
= ip_tos_from_string(rvalue
);
2615 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2623 int config_parse_unit_condition_path(
2625 const char *filename
,
2627 const char *section
,
2628 unsigned section_line
,
2635 _cleanup_free_
char *p
= NULL
;
2636 Condition
**list
= data
, *c
;
2637 ConditionType t
= ltype
;
2638 bool trigger
, negate
;
2647 if (isempty(rvalue
)) {
2648 /* Empty assignment resets the list */
2649 *list
= condition_free_list(*list
);
2653 trigger
= rvalue
[0] == '|';
2657 negate
= rvalue
[0] == '!';
2661 r
= unit_full_printf(u
, rvalue
, &p
);
2663 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2667 if (!path_is_absolute(p
)) {
2668 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2672 c
= condition_new(t
, p
, trigger
, negate
);
2676 LIST_PREPEND(conditions
, *list
, c
);
2680 int config_parse_unit_condition_string(
2682 const char *filename
,
2684 const char *section
,
2685 unsigned section_line
,
2692 _cleanup_free_
char *s
= NULL
;
2693 Condition
**list
= data
, *c
;
2694 ConditionType t
= ltype
;
2695 bool trigger
, negate
;
2704 if (isempty(rvalue
)) {
2705 /* Empty assignment resets the list */
2706 *list
= condition_free_list(*list
);
2710 trigger
= rvalue
[0] == '|';
2714 negate
= rvalue
[0] == '!';
2718 r
= unit_full_printf(u
, rvalue
, &s
);
2720 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2724 c
= condition_new(t
, s
, trigger
, negate
);
2728 LIST_PREPEND(conditions
, *list
, c
);
2732 int config_parse_unit_condition_null(
2734 const char *filename
,
2736 const char *section
,
2737 unsigned section_line
,
2744 Condition
**list
= data
, *c
;
2745 bool trigger
, negate
;
2753 if (isempty(rvalue
)) {
2754 /* Empty assignment resets the list */
2755 *list
= condition_free_list(*list
);
2759 trigger
= rvalue
[0] == '|';
2763 negate
= rvalue
[0] == '!';
2767 b
= parse_boolean(rvalue
);
2769 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2776 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2780 LIST_PREPEND(conditions
, *list
, c
);
2784 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2785 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2787 int config_parse_unit_requires_mounts_for(
2789 const char *filename
,
2791 const char *section
,
2792 unsigned section_line
,
2808 for (p
= rvalue
;; ) {
2809 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2811 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2817 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2818 "Invalid syntax, ignoring: %s", rvalue
);
2822 if (!utf8_is_valid(word
)) {
2823 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2827 r
= unit_full_printf(u
, word
, &resolved
);
2829 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2833 r
= unit_require_mounts_for(u
, resolved
, UNIT_DEPENDENCY_FILE
);
2835 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2841 int config_parse_documentation(const char *unit
,
2842 const char *filename
,
2844 const char *section
,
2845 unsigned section_line
,
2861 if (isempty(rvalue
)) {
2862 /* Empty assignment resets the list */
2863 u
->documentation
= strv_free(u
->documentation
);
2867 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2868 rvalue
, data
, userdata
);
2872 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2874 if (documentation_url_is_valid(*a
))
2877 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2889 static int syscall_filter_parse_one(
2891 const char *filename
,
2901 const SyscallFilterSet
*set
;
2904 set
= syscall_filter_set_find(t
);
2907 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown system call group, ignoring: %s", t
);
2911 NULSTR_FOREACH(i
, set
->value
) {
2912 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false, errno_num
);
2919 id
= seccomp_syscall_resolve_name(t
);
2920 if (id
== __NR_SCMP_ERROR
) {
2922 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2926 /* If we previously wanted to forbid a syscall and now
2927 * we want to allow it, then remove it from the list.
2929 if (!invert
== c
->syscall_whitelist
) {
2930 r
= hashmap_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1), INT_TO_PTR(errno_num
));
2936 (void) hashmap_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2942 int config_parse_syscall_filter(
2944 const char *filename
,
2946 const char *section
,
2947 unsigned section_line
,
2954 ExecContext
*c
= data
;
2956 bool invert
= false;
2965 if (isempty(rvalue
)) {
2966 /* Empty assignment resets the list */
2967 c
->syscall_filter
= hashmap_free(c
->syscall_filter
);
2968 c
->syscall_whitelist
= false;
2972 if (rvalue
[0] == '~') {
2977 if (!c
->syscall_filter
) {
2978 c
->syscall_filter
= hashmap_new(NULL
);
2979 if (!c
->syscall_filter
)
2983 /* Allow everything but the ones listed */
2984 c
->syscall_whitelist
= false;
2986 /* Allow nothing but the ones listed */
2987 c
->syscall_whitelist
= true;
2989 /* Accept default syscalls if we are on a whitelist */
2990 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false, -1);
2998 _cleanup_free_
char *word
= NULL
, *name
= NULL
;
3001 r
= extract_first_word(&p
, &word
, NULL
, 0);
3007 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
3011 r
= parse_syscall_and_errno(word
, &name
, &num
);
3013 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse syscall:errno, ignoring: %s", word
);
3017 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, name
, true, num
);
3025 int config_parse_syscall_archs(
3027 const char *filename
,
3029 const char *section
,
3030 unsigned section_line
,
3041 if (isempty(rvalue
)) {
3042 *archs
= set_free(*archs
);
3046 r
= set_ensure_allocated(archs
, NULL
);
3050 for (p
= rvalue
;;) {
3051 _cleanup_free_
char *word
= NULL
;
3054 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3060 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3061 "Invalid syntax, ignoring: %s", rvalue
);
3065 r
= seccomp_arch_from_string(word
, &a
);
3067 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3068 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
3072 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
3078 int config_parse_syscall_errno(
3080 const char *filename
,
3082 const char *section
,
3083 unsigned section_line
,
3090 ExecContext
*c
= data
;
3097 if (isempty(rvalue
)) {
3098 /* Empty assignment resets to KILL */
3099 c
->syscall_errno
= 0;
3103 e
= parse_errno(rvalue
);
3105 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
3109 c
->syscall_errno
= e
;
3113 int config_parse_address_families(
3115 const char *filename
,
3117 const char *section
,
3118 unsigned section_line
,
3125 ExecContext
*c
= data
;
3126 bool invert
= false;
3134 if (isempty(rvalue
)) {
3135 /* Empty assignment resets the list */
3136 c
->address_families
= set_free(c
->address_families
);
3137 c
->address_families_whitelist
= false;
3141 if (rvalue
[0] == '~') {
3146 if (!c
->address_families
) {
3147 c
->address_families
= set_new(NULL
);
3148 if (!c
->address_families
)
3151 c
->address_families_whitelist
= !invert
;
3154 for (p
= rvalue
;;) {
3155 _cleanup_free_
char *word
= NULL
;
3158 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3164 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3165 "Invalid syntax, ignoring: %s", rvalue
);
3169 af
= af_from_name(word
);
3171 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3172 "Failed to parse address family \"%s\", ignoring: %m", word
);
3176 /* If we previously wanted to forbid an address family and now
3177 * we want to allow it, then just remove it from the list.
3179 if (!invert
== c
->address_families_whitelist
) {
3180 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
3184 set_remove(c
->address_families
, INT_TO_PTR(af
));
3188 int config_parse_restrict_namespaces(
3190 const char *filename
,
3192 const char *section
,
3193 unsigned section_line
,
3200 ExecContext
*c
= data
;
3201 bool invert
= false;
3204 if (isempty(rvalue
)) {
3205 /* Reset to the default. */
3206 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3210 if (rvalue
[0] == '~') {
3215 r
= parse_boolean(rvalue
);
3217 c
->restrict_namespaces
= 0;
3219 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3221 /* Not a boolean argument, in this case it's a list of namespace types. */
3223 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
3225 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
3231 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
3237 int config_parse_unit_slice(
3239 const char *filename
,
3241 const char *section
,
3242 unsigned section_line
,
3249 _cleanup_free_
char *k
= NULL
;
3250 Unit
*u
= userdata
, *slice
= NULL
;
3258 r
= unit_name_printf(u
, rvalue
, &k
);
3260 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3264 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3266 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3270 r
= unit_set_slice(u
, slice
);
3272 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3279 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3281 int config_parse_cpu_weight(
3283 const char *filename
,
3285 const char *section
,
3286 unsigned section_line
,
3293 uint64_t *weight
= data
;
3300 r
= cg_weight_parse(rvalue
, weight
);
3302 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3309 int config_parse_cpu_shares(
3311 const char *filename
,
3313 const char *section
,
3314 unsigned section_line
,
3321 uint64_t *shares
= data
;
3328 r
= cg_cpu_shares_parse(rvalue
, shares
);
3330 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3337 int config_parse_cpu_quota(
3339 const char *filename
,
3341 const char *section
,
3342 unsigned section_line
,
3349 CGroupContext
*c
= data
;
3356 if (isempty(rvalue
)) {
3357 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3361 r
= parse_percent_unbounded(rvalue
);
3363 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3367 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3371 int config_parse_memory_limit(
3373 const char *filename
,
3375 const char *section
,
3376 unsigned section_line
,
3383 CGroupContext
*c
= data
;
3384 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3387 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3389 r
= parse_percent(rvalue
);
3391 r
= parse_size(rvalue
, 1024, &bytes
);
3393 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3397 bytes
= physical_memory_scale(r
, 100U);
3399 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3400 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3405 if (streq(lvalue
, "MemoryLow"))
3406 c
->memory_low
= bytes
;
3407 else if (streq(lvalue
, "MemoryHigh"))
3408 c
->memory_high
= bytes
;
3409 else if (streq(lvalue
, "MemoryMax"))
3410 c
->memory_max
= bytes
;
3411 else if (streq(lvalue
, "MemorySwapMax"))
3412 c
->memory_swap_max
= bytes
;
3413 else if (streq(lvalue
, "MemoryLimit"))
3414 c
->memory_limit
= bytes
;
3421 int config_parse_tasks_max(
3423 const char *filename
,
3425 const char *section
,
3426 unsigned section_line
,
3433 uint64_t *tasks_max
= data
, v
;
3437 if (isempty(rvalue
)) {
3438 *tasks_max
= u
->manager
->default_tasks_max
;
3442 if (streq(rvalue
, "infinity")) {
3443 *tasks_max
= CGROUP_LIMIT_MAX
;
3447 r
= parse_percent(rvalue
);
3449 r
= safe_atou64(rvalue
, &v
);
3451 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3455 v
= system_tasks_max_scale(r
, 100U);
3457 if (v
<= 0 || v
>= UINT64_MAX
) {
3458 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3466 int config_parse_delegate(
3468 const char *filename
,
3470 const char *section
,
3471 unsigned section_line
,
3478 CGroupContext
*c
= data
;
3481 /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
3482 * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
3483 * mask to delegate. */
3485 if (isempty(rvalue
)) {
3487 c
->delegate_controllers
= 0;
3491 r
= parse_boolean(rvalue
);
3493 const char *p
= rvalue
;
3494 CGroupMask mask
= 0;
3497 _cleanup_free_
char *word
= NULL
;
3498 CGroupController cc
;
3500 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3506 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
3510 cc
= cgroup_controller_from_string(word
);
3512 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid controller name '%s', ignoring", rvalue
);
3516 mask
|= CGROUP_CONTROLLER_TO_MASK(cc
);
3520 c
->delegate_controllers
|= mask
;
3524 c
->delegate_controllers
= _CGROUP_MASK_ALL
;
3526 c
->delegate
= false;
3527 c
->delegate_controllers
= 0;
3533 int config_parse_device_allow(
3535 const char *filename
,
3537 const char *section
,
3538 unsigned section_line
,
3545 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3546 CGroupContext
*c
= data
;
3547 CGroupDeviceAllow
*a
;
3548 const char *m
= NULL
;
3552 if (isempty(rvalue
)) {
3553 while (c
->device_allow
)
3554 cgroup_context_free_device_allow(c
, c
->device_allow
);
3559 r
= unit_full_printf(userdata
, rvalue
, &t
);
3561 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3562 "Failed to resolve specifiers in %s, ignoring: %m",
3566 n
= strcspn(t
, WHITESPACE
);
3568 path
= strndup(t
, n
);
3572 if (!is_deviceallow_pattern(path
)) {
3573 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3577 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3581 if (!in_charset(m
, "rwm")) {
3582 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3586 a
= new0(CGroupDeviceAllow
, 1);
3592 a
->r
= !!strchr(m
, 'r');
3593 a
->w
= !!strchr(m
, 'w');
3594 a
->m
= !!strchr(m
, 'm');
3596 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3600 int config_parse_io_weight(
3602 const char *filename
,
3604 const char *section
,
3605 unsigned section_line
,
3612 uint64_t *weight
= data
;
3619 r
= cg_weight_parse(rvalue
, weight
);
3621 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3628 int config_parse_io_device_weight(
3630 const char *filename
,
3632 const char *section
,
3633 unsigned section_line
,
3640 _cleanup_free_
char *path
= NULL
;
3641 CGroupIODeviceWeight
*w
;
3642 CGroupContext
*c
= data
;
3652 if (isempty(rvalue
)) {
3653 while (c
->io_device_weights
)
3654 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3659 n
= strcspn(rvalue
, WHITESPACE
);
3660 weight
= rvalue
+ n
;
3661 weight
+= strspn(weight
, WHITESPACE
);
3663 if (isempty(weight
)) {
3664 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3668 path
= strndup(rvalue
, n
);
3672 if (!path_startswith(path
, "/dev")) {
3673 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3677 r
= cg_weight_parse(weight
, &u
);
3679 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3683 assert(u
!= CGROUP_WEIGHT_INVALID
);
3685 w
= new0(CGroupIODeviceWeight
, 1);
3694 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3698 int config_parse_io_limit(
3700 const char *filename
,
3702 const char *section
,
3703 unsigned section_line
,
3710 _cleanup_free_
char *path
= NULL
;
3711 CGroupIODeviceLimit
*l
= NULL
, *t
;
3712 CGroupContext
*c
= data
;
3713 CGroupIOLimitType type
;
3723 type
= cgroup_io_limit_type_from_string(lvalue
);
3726 if (isempty(rvalue
)) {
3727 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3728 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3732 n
= strcspn(rvalue
, WHITESPACE
);
3734 limit
+= strspn(limit
, WHITESPACE
);
3737 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3741 path
= strndup(rvalue
, n
);
3745 if (!path_startswith(path
, "/dev")) {
3746 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3750 if (streq("infinity", limit
)) {
3751 num
= CGROUP_LIMIT_MAX
;
3753 r
= parse_size(limit
, 1000, &num
);
3754 if (r
< 0 || num
<= 0) {
3755 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3760 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3761 if (path_equal(path
, t
->path
)) {
3768 CGroupIOLimitType ttype
;
3770 l
= new0(CGroupIODeviceLimit
, 1);
3776 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3777 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3779 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3782 l
->limits
[type
] = num
;
3787 int config_parse_blockio_weight(
3789 const char *filename
,
3791 const char *section
,
3792 unsigned section_line
,
3799 uint64_t *weight
= data
;
3806 r
= cg_blkio_weight_parse(rvalue
, weight
);
3808 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3815 int config_parse_blockio_device_weight(
3817 const char *filename
,
3819 const char *section
,
3820 unsigned section_line
,
3827 _cleanup_free_
char *path
= NULL
;
3828 CGroupBlockIODeviceWeight
*w
;
3829 CGroupContext
*c
= data
;
3839 if (isempty(rvalue
)) {
3840 while (c
->blockio_device_weights
)
3841 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3846 n
= strcspn(rvalue
, WHITESPACE
);
3847 weight
= rvalue
+ n
;
3848 weight
+= strspn(weight
, WHITESPACE
);
3850 if (isempty(weight
)) {
3851 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3855 path
= strndup(rvalue
, n
);
3859 if (!path_startswith(path
, "/dev")) {
3860 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3864 r
= cg_blkio_weight_parse(weight
, &u
);
3866 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3870 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3872 w
= new0(CGroupBlockIODeviceWeight
, 1);
3881 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3885 int config_parse_blockio_bandwidth(
3887 const char *filename
,
3889 const char *section
,
3890 unsigned section_line
,
3897 _cleanup_free_
char *path
= NULL
;
3898 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3899 CGroupContext
*c
= data
;
3900 const char *bandwidth
;
3910 read
= streq("BlockIOReadBandwidth", lvalue
);
3912 if (isempty(rvalue
)) {
3913 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3914 b
->rbps
= CGROUP_LIMIT_MAX
;
3915 b
->wbps
= CGROUP_LIMIT_MAX
;
3920 n
= strcspn(rvalue
, WHITESPACE
);
3921 bandwidth
= rvalue
+ n
;
3922 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3925 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3929 path
= strndup(rvalue
, n
);
3933 if (!path_startswith(path
, "/dev")) {
3934 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3938 r
= parse_size(bandwidth
, 1000, &bytes
);
3939 if (r
< 0 || bytes
<= 0) {
3940 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3944 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3945 if (path_equal(path
, t
->path
)) {
3952 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3958 b
->rbps
= CGROUP_LIMIT_MAX
;
3959 b
->wbps
= CGROUP_LIMIT_MAX
;
3961 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3972 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3974 int config_parse_job_mode_isolate(
3976 const char *filename
,
3978 const char *section
,
3979 unsigned section_line
,
3993 r
= parse_boolean(rvalue
);
3995 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3999 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
4003 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
4005 int config_parse_exec_directories(
4007 const char *filename
,
4009 const char *section
,
4010 unsigned section_line
,
4027 if (isempty(rvalue
)) {
4028 /* Empty assignment resets the list */
4029 *rt
= strv_free(*rt
);
4033 for (p
= rvalue
;;) {
4034 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
4036 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
4040 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
4041 "Invalid syntax, ignoring: %s", rvalue
);
4047 r
= unit_full_printf(u
, word
, &k
);
4049 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4050 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
4054 if (!path_is_normalized(k
) || path_is_absolute(k
)) {
4055 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
4056 "%s= path is not valid, ignoring assignment: %s", lvalue
, rvalue
);
4060 r
= strv_push(rt
, k
);
4067 int config_parse_set_status(
4069 const char *filename
,
4071 const char *section
,
4072 unsigned section_line
,
4080 const char *word
, *state
;
4082 ExitStatusSet
*status_set
= data
;
4089 /* Empty assignment resets the list */
4090 if (isempty(rvalue
)) {
4091 exit_status_set_free(status_set
);
4095 FOREACH_WORD(word
, l
, rvalue
, state
) {
4096 _cleanup_free_
char *temp
;
4100 temp
= strndup(word
, l
);
4104 r
= safe_atoi(temp
, &val
);
4106 val
= signal_from_string_try_harder(temp
);
4109 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
4112 set
= &status_set
->signal
;
4114 if (val
< 0 || val
> 255) {
4115 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
4118 set
= &status_set
->status
;
4121 r
= set_ensure_allocated(set
, NULL
);
4125 r
= set_put(*set
, INT_TO_PTR(val
));
4127 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
4131 if (!isempty(state
))
4132 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
4137 int config_parse_namespace_path_strv(
4139 const char *filename
,
4141 const char *section
,
4142 unsigned section_line
,
4159 if (isempty(rvalue
)) {
4160 /* Empty assignment resets the list */
4161 *sv
= strv_free(*sv
);
4167 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
4169 bool ignore_enoent
= false, shall_prefix
= false;
4171 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
4177 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
4181 if (!utf8_is_valid(word
)) {
4182 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
4187 if (startswith(w
, "-")) {
4188 ignore_enoent
= true;
4191 if (startswith(w
, "+")) {
4192 shall_prefix
= true;
4196 r
= unit_full_printf(u
, w
, &resolved
);
4198 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
4202 if (!path_is_absolute(resolved
)) {
4203 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
4207 path_kill_slashes(resolved
);
4209 joined
= strjoin(ignore_enoent
? "-" : "",
4210 shall_prefix
? "+" : "",
4213 r
= strv_push(sv
, joined
);
4223 int config_parse_bind_paths(
4225 const char *filename
,
4227 const char *section
,
4228 unsigned section_line
,
4235 ExecContext
*c
= data
;
4245 if (isempty(rvalue
)) {
4246 /* Empty assignment resets the list */
4247 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
4248 c
->bind_mounts
= NULL
;
4249 c
->n_bind_mounts
= 0;
4255 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
4256 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
4257 char *s
= NULL
, *d
= NULL
;
4258 bool rbind
= true, ignore_enoent
= false;
4260 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4266 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4270 r
= unit_full_printf(u
, source
, &sresolved
);
4272 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4273 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
4279 ignore_enoent
= true;
4283 if (!utf8_is_valid(s
)) {
4284 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
4287 if (!path_is_absolute(s
)) {
4288 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
4292 path_kill_slashes(s
);
4294 /* Optionally, the destination is specified. */
4295 if (p
&& p
[-1] == ':') {
4296 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4300 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4304 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
4308 r
= unit_full_printf(u
, destination
, &dresolved
);
4310 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4311 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
4315 if (!utf8_is_valid(dresolved
)) {
4316 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
4319 if (!path_is_absolute(dresolved
)) {
4320 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
4324 d
= path_kill_slashes(dresolved
);
4326 /* Optionally, there's also a short option string specified */
4327 if (p
&& p
[-1] == ':') {
4328 _cleanup_free_
char *options
= NULL
;
4330 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
4334 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4338 if (isempty(options
) || streq(options
, "rbind"))
4340 else if (streq(options
, "norbind"))
4343 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4350 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4354 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4356 .ignore_enoent
= ignore_enoent
,
4365 int config_parse_no_new_privileges(
4367 const char *filename
,
4369 const char *section
,
4370 unsigned section_line
,
4377 ExecContext
*c
= data
;
4385 k
= parse_boolean(rvalue
);
4387 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4391 c
->no_new_privileges
= k
;
4396 int config_parse_protect_home(
4398 const char *filename
,
4400 const char *section
,
4401 unsigned section_line
,
4408 ExecContext
*c
= data
;
4416 /* Our enum shall be a superset of booleans, hence first try
4417 * to parse as boolean, and then as enum */
4419 k
= parse_boolean(rvalue
);
4421 c
->protect_home
= PROTECT_HOME_YES
;
4423 c
->protect_home
= PROTECT_HOME_NO
;
4427 h
= protect_home_from_string(rvalue
);
4429 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4433 c
->protect_home
= h
;
4439 int config_parse_protect_system(
4441 const char *filename
,
4443 const char *section
,
4444 unsigned section_line
,
4451 ExecContext
*c
= data
;
4459 /* Our enum shall be a superset of booleans, hence first try
4460 * to parse as boolean, and then as enum */
4462 k
= parse_boolean(rvalue
);
4464 c
->protect_system
= PROTECT_SYSTEM_YES
;
4466 c
->protect_system
= PROTECT_SYSTEM_NO
;
4470 s
= protect_system_from_string(rvalue
);
4472 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4476 c
->protect_system
= s
;
4482 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode
, exec_keyring_mode
, ExecKeyringMode
, "Failed to parse keyring mode");
4484 int config_parse_job_timeout_sec(
4486 const char *filename
,
4488 const char *section
,
4489 unsigned section_line
,
4505 r
= parse_sec_fix_0(rvalue
, &usec
);
4507 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue
);
4511 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4512 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4515 if (!u
->job_running_timeout_set
)
4516 u
->job_running_timeout
= usec
;
4518 u
->job_timeout
= usec
;
4523 int config_parse_job_running_timeout_sec(
4525 const char *filename
,
4527 const char *section
,
4528 unsigned section_line
,
4544 r
= parse_sec_fix_0(rvalue
, &usec
);
4546 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue
);
4550 u
->job_running_timeout
= usec
;
4551 u
->job_running_timeout_set
= true;
4556 #define FOLLOW_MAX 8
4558 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4569 /* This will update the filename pointer if the loaded file is
4570 * reached by a symlink. The old string will be freed. */
4573 char *target
, *name
;
4575 if (c
++ >= FOLLOW_MAX
)
4578 path_kill_slashes(*filename
);
4580 /* Add the file name we are currently looking at to
4581 * the names of this unit, but only if it is a valid
4583 name
= basename(*filename
);
4584 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4586 id
= set_get(names
, name
);
4592 r
= set_consume(names
, id
);
4598 /* Try to open the file name, but don't if its a symlink */
4599 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4606 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4607 r
= readlink_and_make_absolute(*filename
, &target
);
4615 f
= fdopen(fd
, "re");
4627 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4635 /* Let's try to add in all symlink names we found */
4636 while ((k
= set_steal_first(names
))) {
4638 /* First try to merge in the other name into our
4640 r
= unit_merge_by_name(*u
, k
);
4644 /* Hmm, we couldn't merge the other unit into
4645 * ours? Then let's try it the other way
4648 /* If the symlink name we are looking at is unit template, then
4649 we must search for instance of this template */
4650 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4651 _cleanup_free_
char *instance
= NULL
;
4653 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4657 other
= manager_get_unit((*u
)->manager
, instance
);
4659 other
= manager_get_unit((*u
)->manager
, k
);
4664 r
= unit_merge(other
, *u
);
4667 return merge_by_names(u
, names
, NULL
);
4675 unit_choose_id(*u
, id
);
4683 static int load_from_path(Unit
*u
, const char *path
) {
4684 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4685 _cleanup_fclose_
FILE *f
= NULL
;
4686 _cleanup_free_
char *filename
= NULL
;
4695 symlink_names
= set_new(&string_hash_ops
);
4699 if (path_is_absolute(path
)) {
4701 filename
= strdup(path
);
4705 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4707 filename
= mfree(filename
);
4715 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4717 /* Instead of opening the path right away, we manually
4718 * follow all symlinks and add their name to our unit
4719 * name set while doing so */
4720 filename
= path_make_absolute(path
, *p
);
4724 if (u
->manager
->unit_path_cache
&&
4725 !set_get(u
->manager
->unit_path_cache
, filename
))
4728 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4731 filename
= mfree(filename
);
4733 /* ENOENT means that the file is missing or is a dangling symlink.
4734 * ENOTDIR means that one of paths we expect to be is a directory
4735 * is not a directory, we should just ignore that.
4736 * EACCES means that the directory or file permissions are wrong.
4739 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4740 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4743 /* Empty the symlink names for the next run */
4744 set_clear_free(symlink_names
);
4749 /* Hmm, no suitable file found? */
4752 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4753 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4758 r
= merge_by_names(&merged
, symlink_names
, id
);
4763 u
->load_state
= UNIT_MERGED
;
4767 if (fstat(fileno(f
), &st
) < 0)
4770 if (null_or_empty(&st
)) {
4771 u
->load_state
= UNIT_MASKED
;
4772 u
->fragment_mtime
= 0;
4774 u
->load_state
= UNIT_LOADED
;
4775 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4777 /* Now, parse the file contents */
4778 r
= config_parse(u
->id
, filename
, f
,
4779 UNIT_VTABLE(u
)->sections
,
4780 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4781 CONFIG_PARSE_ALLOW_INCLUDE
, u
);
4786 free(u
->fragment_path
);
4787 u
->fragment_path
= filename
;
4790 if (u
->source_path
) {
4791 if (stat(u
->source_path
, &st
) >= 0)
4792 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4794 u
->source_mtime
= 0;
4800 int unit_load_fragment(Unit
*u
) {
4806 assert(u
->load_state
== UNIT_STUB
);
4810 u
->load_state
= UNIT_LOADED
;
4814 /* First, try to find the unit under its id. We always look
4815 * for unit files in the default directories, to make it easy
4816 * to override things by placing things in /etc/systemd/system */
4817 r
= load_from_path(u
, u
->id
);
4821 /* Try to find an alias we can load this with */
4822 if (u
->load_state
== UNIT_STUB
) {
4823 SET_FOREACH(t
, u
->names
, i
) {
4828 r
= load_from_path(u
, t
);
4832 if (u
->load_state
!= UNIT_STUB
)
4837 /* And now, try looking for it under the suggested (originally linked) path */
4838 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4840 r
= load_from_path(u
, u
->fragment_path
);
4844 if (u
->load_state
== UNIT_STUB
)
4845 /* Hmm, this didn't work? Then let's get rid
4846 * of the fragment path stored for us, so that
4847 * we don't point to an invalid location. */
4848 u
->fragment_path
= mfree(u
->fragment_path
);
4851 /* Look for a template */
4852 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4853 _cleanup_free_
char *k
= NULL
;
4855 r
= unit_name_template(u
->id
, &k
);
4859 r
= load_from_path(u
, k
);
4862 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4866 if (u
->load_state
== UNIT_STUB
) {
4867 SET_FOREACH(t
, u
->names
, i
) {
4868 _cleanup_free_
char *z
= NULL
;
4873 r
= unit_name_template(t
, &z
);
4877 r
= load_from_path(u
, z
);
4881 if (u
->load_state
!= UNIT_STUB
)
4890 void unit_dump_config_items(FILE *f
) {
4891 static const struct {
4892 const ConfigParserCallback callback
;
4895 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4896 { config_parse_warn_compat
, "NOTSUPPORTED" },
4898 { config_parse_int
, "INTEGER" },
4899 { config_parse_unsigned
, "UNSIGNED" },
4900 { config_parse_iec_size
, "SIZE" },
4901 { config_parse_iec_uint64
, "SIZE" },
4902 { config_parse_si_size
, "SIZE" },
4903 { config_parse_bool
, "BOOLEAN" },
4904 { config_parse_string
, "STRING" },
4905 { config_parse_path
, "PATH" },
4906 { config_parse_unit_path_printf
, "PATH" },
4907 { config_parse_strv
, "STRING [...]" },
4908 { config_parse_exec_nice
, "NICE" },
4909 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4910 { config_parse_exec_io_class
, "IOCLASS" },
4911 { config_parse_exec_io_priority
, "IOPRIORITY" },
4912 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4913 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4914 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4915 { config_parse_mode
, "MODE" },
4916 { config_parse_unit_env_file
, "FILE" },
4917 { config_parse_exec_output
, "OUTPUT" },
4918 { config_parse_exec_input
, "INPUT" },
4919 { config_parse_log_facility
, "FACILITY" },
4920 { config_parse_log_level
, "LEVEL" },
4921 { config_parse_exec_secure_bits
, "SECUREBITS" },
4922 { config_parse_capability_set
, "BOUNDINGSET" },
4923 { config_parse_limit
, "LIMIT" },
4924 { config_parse_unit_deps
, "UNIT [...]" },
4925 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4926 { config_parse_service_type
, "SERVICETYPE" },
4927 { config_parse_service_restart
, "SERVICERESTART" },
4928 #if HAVE_SYSV_COMPAT
4929 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4931 { config_parse_kill_mode
, "KILLMODE" },
4932 { config_parse_signal
, "SIGNAL" },
4933 { config_parse_socket_listen
, "SOCKET [...]" },
4934 { config_parse_socket_bind
, "SOCKETBIND" },
4935 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4936 { config_parse_sec
, "SECONDS" },
4937 { config_parse_nsec
, "NANOSECONDS" },
4938 { config_parse_namespace_path_strv
, "PATH [...]" },
4939 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4940 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4941 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4942 { config_parse_unit_string_printf
, "STRING" },
4943 { config_parse_trigger_unit
, "UNIT" },
4944 { config_parse_timer
, "TIMER" },
4945 { config_parse_path_spec
, "PATH" },
4946 { config_parse_notify_access
, "ACCESS" },
4947 { config_parse_ip_tos
, "TOS" },
4948 { config_parse_unit_condition_path
, "CONDITION" },
4949 { config_parse_unit_condition_string
, "CONDITION" },
4950 { config_parse_unit_condition_null
, "CONDITION" },
4951 { config_parse_unit_slice
, "SLICE" },
4952 { config_parse_documentation
, "URL" },
4953 { config_parse_service_timeout
, "SECONDS" },
4954 { config_parse_emergency_action
, "ACTION" },
4955 { config_parse_set_status
, "STATUS" },
4956 { config_parse_service_sockets
, "SOCKETS" },
4957 { config_parse_environ
, "ENVIRON" },
4959 { config_parse_syscall_filter
, "SYSCALLS" },
4960 { config_parse_syscall_archs
, "ARCHS" },
4961 { config_parse_syscall_errno
, "ERRNO" },
4962 { config_parse_address_families
, "FAMILIES" },
4963 { config_parse_restrict_namespaces
, "NAMESPACES" },
4965 { config_parse_cpu_shares
, "SHARES" },
4966 { config_parse_cpu_weight
, "WEIGHT" },
4967 { config_parse_memory_limit
, "LIMIT" },
4968 { config_parse_device_allow
, "DEVICE" },
4969 { config_parse_device_policy
, "POLICY" },
4970 { config_parse_io_limit
, "LIMIT" },
4971 { config_parse_io_weight
, "WEIGHT" },
4972 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4973 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4974 { config_parse_blockio_weight
, "WEIGHT" },
4975 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4976 { config_parse_long
, "LONG" },
4977 { config_parse_socket_service
, "SERVICE" },
4979 { config_parse_exec_selinux_context
, "LABEL" },
4981 { config_parse_job_mode
, "MODE" },
4982 { config_parse_job_mode_isolate
, "BOOLEAN" },
4983 { config_parse_personality
, "PERSONALITY" },
4986 const char *prev
= NULL
;
4991 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4992 const char *rvalue
= "OTHER", *lvalue
;
4996 const ConfigPerfItem
*p
;
4998 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
5000 dot
= strchr(i
, '.');
5001 lvalue
= dot
? dot
+ 1 : i
;
5005 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
5009 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
5012 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
5013 if (p
->parse
== table
[j
].callback
) {
5014 rvalue
= table
[j
].rvalue
;
5018 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);