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 "socket-protocol-list.h"
68 #include "stat-util.h"
69 #include "string-util.h"
71 #include "unit-name.h"
72 #include "unit-printf.h"
74 #include "user-util.h"
78 int config_parse_warn_compat(
83 unsigned section_line
,
89 Disabled reason
= ltype
;
92 case DISABLED_CONFIGURATION
:
93 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
94 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
97 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
98 "Support for option %s= has been removed and it is ignored", lvalue
);
100 case DISABLED_EXPERIMENTAL
:
101 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
102 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
109 DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode
, collect_mode
, CollectMode
, "Failed to parse garbage collection mode");
111 int config_parse_unit_deps(
113 const char *filename
,
116 unsigned section_line
,
123 UnitDependency d
= ltype
;
133 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
136 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
142 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
146 r
= unit_name_printf(u
, word
, &k
);
148 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
152 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
154 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
160 int config_parse_obsolete_unit_deps(
162 const char *filename
,
165 unsigned section_line
,
172 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
173 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
175 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
178 int config_parse_unit_string_printf(
180 const char *filename
,
183 unsigned section_line
,
190 _cleanup_free_
char *k
= NULL
;
199 r
= unit_full_printf(u
, rvalue
, &k
);
201 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
205 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
208 int config_parse_unit_strv_printf(
210 const char *filename
,
213 unsigned section_line
,
221 _cleanup_free_
char *k
= NULL
;
229 r
= unit_full_printf(u
, rvalue
, &k
);
231 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
235 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
238 int config_parse_unit_path_printf(
240 const char *filename
,
243 unsigned section_line
,
250 _cleanup_free_
char *k
= NULL
;
260 r
= unit_full_printf(u
, rvalue
, &k
);
262 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
263 "Failed to resolve unit specifiers on %s%s: %m",
264 fatal
? "" : ", ignoring", rvalue
);
265 return fatal
? -ENOEXEC
: 0;
268 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
271 int config_parse_unit_path_strv_printf(
273 const char *filename
,
276 unsigned section_line
,
293 if (isempty(rvalue
)) {
299 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
301 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
307 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
308 "Invalid syntax, ignoring: %s", rvalue
);
312 r
= unit_full_printf(u
, word
, &k
);
314 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
315 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
319 if (!utf8_is_valid(k
)) {
320 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
324 if (!path_is_absolute(k
)) {
325 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
326 "Symlink path is not absolute: %s", k
);
330 path_kill_slashes(k
);
339 int config_parse_socket_listen(const char *unit
,
340 const char *filename
,
343 unsigned section_line
,
350 _cleanup_free_ SocketPort
*p
= NULL
;
362 if (isempty(rvalue
)) {
363 /* An empty assignment removes all ports */
364 socket_free_ports(s
);
368 p
= new0(SocketPort
, 1);
372 if (ltype
!= SOCKET_SOCKET
) {
375 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
377 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
381 path_kill_slashes(p
->path
);
383 } else if (streq(lvalue
, "ListenNetlink")) {
384 _cleanup_free_
char *k
= NULL
;
386 p
->type
= SOCKET_SOCKET
;
387 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
389 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
393 r
= socket_address_parse_netlink(&p
->address
, k
);
395 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
400 _cleanup_free_
char *k
= NULL
;
402 p
->type
= SOCKET_SOCKET
;
403 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
405 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
409 r
= socket_address_parse_and_warn(&p
->address
, k
);
411 if (r
!= -EAFNOSUPPORT
)
412 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
417 if (streq(lvalue
, "ListenStream"))
418 p
->address
.type
= SOCK_STREAM
;
419 else if (streq(lvalue
, "ListenDatagram"))
420 p
->address
.type
= SOCK_DGRAM
;
422 assert(streq(lvalue
, "ListenSequentialPacket"));
423 p
->address
.type
= SOCK_SEQPACKET
;
426 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
427 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
433 p
->auxiliary_fds
= NULL
;
434 p
->n_auxiliary_fds
= 0;
437 LIST_FIND_TAIL(port
, s
->ports
, tail
);
438 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
445 int config_parse_socket_protocol(const char *unit
,
446 const char *filename
,
449 unsigned section_line
,
465 r
= socket_protocol_from_name(rvalue
);
467 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid socket protocol, ignoring: %s", rvalue
);
469 } else if (!IN_SET(r
, IPPROTO_UDPLITE
, IPPROTO_SCTP
)) {
470 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
474 s
->socket_protocol
= r
;
479 int config_parse_socket_bind(const char *unit
,
480 const char *filename
,
483 unsigned section_line
,
491 SocketAddressBindIPv6Only b
;
500 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
504 r
= parse_boolean(rvalue
);
506 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
510 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
512 s
->bind_ipv6_only
= b
;
517 int config_parse_exec_nice(
519 const char *filename
,
522 unsigned section_line
,
529 ExecContext
*c
= data
;
537 r
= parse_nice(rvalue
, &priority
);
540 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
542 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
553 int config_parse_exec_oom_score_adjust(const char* unit
,
554 const char *filename
,
557 unsigned section_line
,
564 ExecContext
*c
= data
;
572 r
= safe_atoi(rvalue
, &oa
);
574 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
578 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
579 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
583 c
->oom_score_adjust
= oa
;
584 c
->oom_score_adjust_set
= true;
589 int config_parse_exec(
591 const char *filename
,
594 unsigned section_line
,
601 ExecCommand
**e
= data
;
613 rvalue
+= strspn(rvalue
, WHITESPACE
);
615 if (isempty(rvalue
)) {
616 /* An empty assignment resets the list */
617 *e
= exec_command_free_list(*e
);
623 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
624 ExecCommandFlags flags
= 0;
625 bool ignore
= false, separate_argv0
= false;
626 _cleanup_free_ ExecCommand
*nce
= NULL
;
627 _cleanup_strv_free_
char **n
= NULL
;
628 size_t nlen
= 0, nbufsize
= 0;
633 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
639 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
640 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
641 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
642 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
643 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
644 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
645 * other sandboxing, with some special exceptions for changing UID.
647 * The idea is that '!!' may be used to write services that can take benefit of systemd's
648 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
649 * privilege dropping within the daemon if the kernel does not offer that. */
651 if (*f
== '-' && !(flags
& EXEC_COMMAND_IGNORE_FAILURE
)) {
652 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
654 } else if (*f
== '@' && !separate_argv0
)
655 separate_argv0
= true;
656 else if (*f
== '+' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
657 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
658 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
659 flags
|= EXEC_COMMAND_NO_SETUID
;
660 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
661 flags
&= ~EXEC_COMMAND_NO_SETUID
;
662 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
668 r
= unit_full_printf(u
, f
, &path
);
670 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
671 "Failed to resolve unit specifiers on %s%s: %m",
672 f
, ignore
? ", ignoring" : "");
673 return ignore
? 0 : -ENOEXEC
;
677 /* First word is either "-" or "@" with no command. */
678 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
679 "Empty path in command line%s: \"%s\"",
680 ignore
? ", ignoring" : "", rvalue
);
681 return ignore
? 0 : -ENOEXEC
;
683 if (!string_is_safe(path
)) {
684 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
685 "Executable path contains special characters%s: %s",
686 ignore
? ", ignoring" : "", rvalue
);
687 return ignore
? 0 : -ENOEXEC
;
689 if (!path_is_absolute(path
)) {
690 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
691 "Executable path is not absolute%s: %s",
692 ignore
? ", ignoring" : "", rvalue
);
693 return ignore
? 0 : -ENOEXEC
;
695 if (endswith(path
, "/")) {
696 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
697 "Executable path specifies a directory%s: %s",
698 ignore
? ", ignoring" : "", rvalue
);
699 return ignore
? 0 : -ENOEXEC
;
702 if (!separate_argv0
) {
705 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
715 path_kill_slashes(path
);
717 while (!isempty(p
)) {
718 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
720 /* Check explicitly for an unquoted semicolon as
721 * command separator token. */
722 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
724 p
+= strspn(p
, WHITESPACE
);
729 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
730 * extract_first_word() would return the same for all of those. */
731 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
735 p
+= strspn(p
, WHITESPACE
);
737 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
748 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
752 return ignore
? 0 : -ENOEXEC
;
754 r
= unit_full_printf(u
, word
, &resolved
);
756 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
757 "Failed to resolve unit specifiers on %s%s: %m",
758 word
, ignore
? ", ignoring" : "");
759 return ignore
? 0 : -ENOEXEC
;
762 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
764 n
[nlen
++] = resolved
;
770 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
771 "Empty executable name or zeroeth argument%s: %s",
772 ignore
? ", ignoring" : "", rvalue
);
773 return ignore
? 0 : -ENOEXEC
;
776 nce
= new0(ExecCommand
, 1);
784 exec_command_append_list(e
, nce
);
786 /* Do not _cleanup_free_ these. */
797 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
798 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
800 int config_parse_socket_bindtodevice(
802 const char *filename
,
805 unsigned section_line
,
820 if (rvalue
[0] && !streq(rvalue
, "*")) {
821 if (!ifname_valid(rvalue
)) {
822 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
832 free(s
->bind_to_device
);
833 s
->bind_to_device
= n
;
838 int config_parse_exec_input(
840 const char *filename
,
843 unsigned section_line
,
850 ExecContext
*c
= data
;
861 n
= startswith(rvalue
, "fd:");
863 _cleanup_free_
char *resolved
= NULL
;
865 r
= unit_full_printf(u
, n
, &resolved
);
867 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
869 if (isempty(resolved
))
870 resolved
= mfree(resolved
);
871 else if (!fdname_is_valid(resolved
)) {
872 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name: %s", resolved
);
876 free_and_replace(c
->stdio_fdname
[STDIN_FILENO
], resolved
);
878 ei
= EXEC_INPUT_NAMED_FD
;
880 } else if ((n
= startswith(rvalue
, "file:"))) {
881 _cleanup_free_
char *resolved
= NULL
;
883 r
= unit_full_printf(u
, n
, &resolved
);
885 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
887 if (!path_is_absolute(resolved
)) {
888 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
892 if (!path_is_normalized(resolved
)) {
893 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name: %s", resolved
);
897 free_and_replace(c
->stdio_file
[STDIN_FILENO
], resolved
);
899 ei
= EXEC_INPUT_FILE
;
902 ei
= exec_input_from_string(rvalue
);
904 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
913 int config_parse_exec_input_text(
915 const char *filename
,
918 unsigned section_line
,
925 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
926 ExecContext
*c
= data
;
937 if (isempty(rvalue
)) {
938 /* Reset if the empty string is assigned */
939 c
->stdin_data
= mfree(c
->stdin_data
);
940 c
->stdin_data_size
= 0;
944 r
= cunescape(rvalue
, 0, &unescaped
);
946 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode C escaped text: %s", rvalue
);
948 r
= unit_full_printf(u
, unescaped
, &resolved
);
950 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", unescaped
);
952 sz
= strlen(resolved
);
953 if (c
->stdin_data_size
+ sz
+ 1 < c
->stdin_data_size
|| /* check for overflow */
954 c
->stdin_data_size
+ sz
+ 1 > EXEC_STDIN_DATA_MAX
) {
955 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c
->stdin_data_size
+ sz
, (size_t) EXEC_STDIN_DATA_MAX
);
959 p
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
+ 1);
963 *((char*) mempcpy((char*) p
+ c
->stdin_data_size
, resolved
, sz
)) = '\n';
966 c
->stdin_data_size
+= sz
+ 1;
971 int config_parse_exec_input_data(
973 const char *filename
,
976 unsigned section_line
,
983 _cleanup_free_
void *p
= NULL
;
984 ExecContext
*c
= data
;
994 if (isempty(rvalue
)) {
995 /* Reset if the empty string is assigned */
996 c
->stdin_data
= mfree(c
->stdin_data
);
997 c
->stdin_data_size
= 0;
1001 r
= unbase64mem(rvalue
, (size_t) -1, &p
, &sz
);
1003 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode base64 data, ignoring: %s", rvalue
);
1007 if (c
->stdin_data_size
+ sz
< c
->stdin_data_size
|| /* check for overflow */
1008 c
->stdin_data_size
+ sz
> EXEC_STDIN_DATA_MAX
) {
1009 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c
->stdin_data_size
+ sz
, (size_t) EXEC_STDIN_DATA_MAX
);
1013 q
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
);
1017 memcpy((uint8_t*) q
+ c
->stdin_data_size
, p
, sz
);
1020 c
->stdin_data_size
+= sz
;
1025 int config_parse_exec_output(
1027 const char *filename
,
1029 const char *section
,
1030 unsigned section_line
,
1037 _cleanup_free_
char *resolved
= NULL
;
1039 ExecContext
*c
= data
;
1050 n
= startswith(rvalue
, "fd:");
1052 r
= unit_full_printf(u
, n
, &resolved
);
1054 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1056 if (isempty(resolved
))
1057 resolved
= mfree(resolved
);
1058 else if (!fdname_is_valid(resolved
)) {
1059 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name: %s", resolved
);
1063 eo
= EXEC_OUTPUT_NAMED_FD
;
1065 } else if ((n
= startswith(rvalue
, "file:"))) {
1067 r
= unit_full_printf(u
, n
, &resolved
);
1069 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1071 if (!path_is_absolute(resolved
)) {
1072 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
1076 if (!path_is_normalized(resolved
)) {
1077 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name, ignoring: %s", resolved
);
1081 eo
= EXEC_OUTPUT_FILE
;
1084 eo
= exec_output_from_string(rvalue
);
1086 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
1091 if (streq(lvalue
, "StandardOutput")) {
1092 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1093 free_and_replace(c
->stdio_fdname
[STDOUT_FILENO
], resolved
);
1095 free_and_replace(c
->stdio_file
[STDOUT_FILENO
], resolved
);
1100 assert(streq(lvalue
, "StandardError"));
1102 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1103 free_and_replace(c
->stdio_fdname
[STDERR_FILENO
], resolved
);
1105 free_and_replace(c
->stdio_file
[STDERR_FILENO
], resolved
);
1113 int config_parse_exec_io_class(const char *unit
,
1114 const char *filename
,
1116 const char *section
,
1117 unsigned section_line
,
1124 ExecContext
*c
= data
;
1132 x
= ioprio_class_from_string(rvalue
);
1134 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
1138 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
1139 c
->ioprio_set
= true;
1144 int config_parse_exec_io_priority(const char *unit
,
1145 const char *filename
,
1147 const char *section
,
1148 unsigned section_line
,
1155 ExecContext
*c
= data
;
1163 r
= ioprio_parse_priority(rvalue
, &i
);
1165 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
1169 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
1170 c
->ioprio_set
= true;
1175 int config_parse_exec_cpu_sched_policy(const char *unit
,
1176 const char *filename
,
1178 const char *section
,
1179 unsigned section_line
,
1187 ExecContext
*c
= data
;
1195 x
= sched_policy_from_string(rvalue
);
1197 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1201 c
->cpu_sched_policy
= x
;
1202 /* Moving to or from real-time policy? We need to adjust the priority */
1203 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1204 c
->cpu_sched_set
= true;
1209 int config_parse_exec_cpu_sched_prio(const char *unit
,
1210 const char *filename
,
1212 const char *section
,
1213 unsigned section_line
,
1220 ExecContext
*c
= data
;
1228 r
= safe_atoi(rvalue
, &i
);
1230 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1234 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1235 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1236 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1238 if (i
< min
|| i
> max
) {
1239 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1243 c
->cpu_sched_priority
= i
;
1244 c
->cpu_sched_set
= true;
1249 int config_parse_exec_cpu_affinity(const char *unit
,
1250 const char *filename
,
1252 const char *section
,
1253 unsigned section_line
,
1260 ExecContext
*c
= data
;
1261 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1269 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1274 /* An empty assignment resets the CPU list */
1275 c
->cpuset
= cpu_set_mfree(c
->cpuset
);
1276 c
->cpuset_ncpus
= 0;
1283 c
->cpuset_ncpus
= (unsigned) ncpus
;
1287 if (c
->cpuset_ncpus
< (unsigned) ncpus
) {
1288 CPU_OR_S(CPU_ALLOC_SIZE(c
->cpuset_ncpus
), cpuset
, c
->cpuset
, cpuset
);
1289 CPU_FREE(c
->cpuset
);
1292 c
->cpuset_ncpus
= (unsigned) ncpus
;
1296 CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus
), c
->cpuset
, c
->cpuset
, cpuset
);
1301 int config_parse_exec_secure_bits(const char *unit
,
1302 const char *filename
,
1304 const char *section
,
1305 unsigned section_line
,
1312 ExecContext
*c
= data
;
1320 if (isempty(rvalue
)) {
1321 /* An empty assignment resets the field */
1326 r
= secure_bits_from_string(rvalue
);
1330 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1331 "Invalid syntax, ignoring: %s", rvalue
);
1340 int config_parse_capability_set(
1342 const char *filename
,
1344 const char *section
,
1345 unsigned section_line
,
1352 uint64_t *capability_set
= data
;
1353 uint64_t sum
= 0, initial
= 0;
1354 bool invert
= false;
1362 if (rvalue
[0] == '~') {
1367 if (streq(lvalue
, "CapabilityBoundingSet"))
1368 initial
= CAP_ALL
; /* initialized to all bits on */
1369 /* else "AmbientCapabilities" initialized to all bits off */
1371 r
= capability_set_from_string(rvalue
, &sum
);
1375 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1379 if (sum
== 0 || *capability_set
== initial
)
1380 /* "", "~" or uninitialized data -> replace */
1381 *capability_set
= invert
? ~sum
: sum
;
1383 /* previous data -> merge */
1385 *capability_set
&= ~sum
;
1387 *capability_set
|= sum
;
1393 int config_parse_limit(
1395 const char *filename
,
1397 const char *section
,
1398 unsigned section_line
,
1405 struct rlimit
**rl
= data
, d
= {};
1413 r
= rlimit_parse(ltype
, rvalue
, &d
);
1415 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1419 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1426 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1434 #if HAVE_SYSV_COMPAT
1435 int config_parse_sysv_priority(const char *unit
,
1436 const char *filename
,
1438 const char *section
,
1439 unsigned section_line
,
1446 int *priority
= data
;
1454 r
= safe_atoi(rvalue
, &i
);
1455 if (r
< 0 || i
< 0) {
1456 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1460 *priority
= (int) i
;
1465 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1466 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1468 int config_parse_exec_mount_flags(
1470 const char *filename
,
1472 const char *section
,
1473 unsigned section_line
,
1481 ExecContext
*c
= data
;
1489 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1491 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1496 int config_parse_exec_selinux_context(
1498 const char *filename
,
1500 const char *section
,
1501 unsigned section_line
,
1508 ExecContext
*c
= data
;
1519 if (isempty(rvalue
)) {
1520 c
->selinux_context
= mfree(c
->selinux_context
);
1521 c
->selinux_context_ignore
= false;
1525 if (rvalue
[0] == '-') {
1531 r
= unit_full_printf(u
, rvalue
, &k
);
1533 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1534 "Failed to resolve specifiers%s: %m",
1535 ignore
? ", ignoring" : "");
1536 return ignore
? 0 : -ENOEXEC
;
1539 free(c
->selinux_context
);
1540 c
->selinux_context
= k
;
1541 c
->selinux_context_ignore
= ignore
;
1546 int config_parse_exec_apparmor_profile(
1548 const char *filename
,
1550 const char *section
,
1551 unsigned section_line
,
1558 ExecContext
*c
= data
;
1569 if (isempty(rvalue
)) {
1570 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1571 c
->apparmor_profile_ignore
= false;
1575 if (rvalue
[0] == '-') {
1581 r
= unit_full_printf(u
, rvalue
, &k
);
1583 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1584 "Failed to resolve specifiers%s: %m",
1585 ignore
? ", ignoring" : "");
1586 return ignore
? 0 : -ENOEXEC
;
1589 free(c
->apparmor_profile
);
1590 c
->apparmor_profile
= k
;
1591 c
->apparmor_profile_ignore
= ignore
;
1596 int config_parse_exec_smack_process_label(
1598 const char *filename
,
1600 const char *section
,
1601 unsigned section_line
,
1608 ExecContext
*c
= data
;
1619 if (isempty(rvalue
)) {
1620 c
->smack_process_label
= mfree(c
->smack_process_label
);
1621 c
->smack_process_label_ignore
= false;
1625 if (rvalue
[0] == '-') {
1631 r
= unit_full_printf(u
, rvalue
, &k
);
1633 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1634 "Failed to resolve specifiers%s: %m",
1635 ignore
? ", ignoring" : "");
1636 return ignore
? 0 : -ENOEXEC
;
1639 free(c
->smack_process_label
);
1640 c
->smack_process_label
= k
;
1641 c
->smack_process_label_ignore
= ignore
;
1646 int config_parse_timer(const char *unit
,
1647 const char *filename
,
1649 const char *section
,
1650 unsigned section_line
,
1661 CalendarSpec
*c
= NULL
;
1663 _cleanup_free_
char *k
= NULL
;
1671 if (isempty(rvalue
)) {
1672 /* Empty assignment resets list */
1673 timer_free_values(t
);
1677 b
= timer_base_from_string(lvalue
);
1679 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1683 r
= unit_full_printf(u
, rvalue
, &k
);
1685 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1689 if (b
== TIMER_CALENDAR
) {
1690 if (calendar_spec_from_string(k
, &c
) < 0) {
1691 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1695 if (parse_sec(k
, &usec
) < 0) {
1696 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1701 v
= new0(TimerValue
, 1);
1703 calendar_spec_free(c
);
1709 v
->calendar_spec
= c
;
1711 LIST_PREPEND(value
, t
->values
, v
);
1716 int config_parse_trigger_unit(
1718 const char *filename
,
1720 const char *section
,
1721 unsigned section_line
,
1728 _cleanup_free_
char *p
= NULL
;
1738 if (!hashmap_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1739 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1743 r
= unit_name_printf(u
, rvalue
, &p
);
1745 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1749 type
= unit_name_to_type(p
);
1751 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1755 if (type
== u
->type
) {
1756 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1760 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1762 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1769 int config_parse_path_spec(const char *unit
,
1770 const char *filename
,
1772 const char *section
,
1773 unsigned section_line
,
1783 _cleanup_free_
char *k
= NULL
;
1791 if (isempty(rvalue
)) {
1792 /* Empty assignment clears list */
1797 b
= path_type_from_string(lvalue
);
1799 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1803 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1805 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1809 if (!path_is_absolute(k
)) {
1810 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1814 s
= new0(PathSpec
, 1);
1819 s
->path
= path_kill_slashes(k
);
1824 LIST_PREPEND(spec
, p
->specs
, s
);
1829 int config_parse_socket_service(
1831 const char *filename
,
1833 const char *section
,
1834 unsigned section_line
,
1841 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1842 _cleanup_free_
char *p
= NULL
;
1852 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1854 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1858 if (!endswith(p
, ".service")) {
1859 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1863 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1865 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1869 unit_ref_set(&s
->service
, x
);
1874 int config_parse_fdname(
1876 const char *filename
,
1878 const char *section
,
1879 unsigned section_line
,
1886 _cleanup_free_
char *p
= NULL
;
1895 if (isempty(rvalue
)) {
1896 s
->fdname
= mfree(s
->fdname
);
1900 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1902 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1906 if (!fdname_is_valid(p
)) {
1907 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1911 return free_and_replace(s
->fdname
, p
);
1914 int config_parse_service_sockets(
1916 const char *filename
,
1918 const char *section
,
1919 unsigned section_line
,
1937 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1939 r
= extract_first_word(&p
, &word
, NULL
, 0);
1945 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1949 r
= unit_name_printf(UNIT(s
), word
, &k
);
1951 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1955 if (!endswith(k
, ".socket")) {
1956 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1960 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1962 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1964 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1966 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1972 int config_parse_bus_name(
1974 const char *filename
,
1976 const char *section
,
1977 unsigned section_line
,
1984 _cleanup_free_
char *k
= NULL
;
1993 r
= unit_full_printf(u
, rvalue
, &k
);
1995 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1999 if (!service_name_is_valid(k
)) {
2000 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
2004 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
2007 int config_parse_service_timeout(
2009 const char *filename
,
2011 const char *section
,
2012 unsigned section_line
,
2019 Service
*s
= userdata
;
2028 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
2030 r
= parse_sec(rvalue
, &usec
);
2032 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2036 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
2037 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
2038 * all other timeouts. */
2040 usec
= USEC_INFINITY
;
2042 if (!streq(lvalue
, "TimeoutStopSec")) {
2043 s
->start_timeout_defined
= true;
2044 s
->timeout_start_usec
= usec
;
2047 if (!streq(lvalue
, "TimeoutStartSec"))
2048 s
->timeout_stop_usec
= usec
;
2053 int config_parse_sec_fix_0(
2055 const char *filename
,
2057 const char *section
,
2058 unsigned section_line
,
2065 usec_t
*usec
= data
;
2073 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
2074 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
2077 r
= parse_sec_fix_0(rvalue
, usec
);
2079 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2086 int config_parse_user_group(
2088 const char *filename
,
2090 const char *section
,
2091 unsigned section_line
,
2098 char **user
= data
, *n
;
2107 if (isempty(rvalue
))
2110 _cleanup_free_
char *k
= NULL
;
2112 r
= unit_full_printf(u
, rvalue
, &k
);
2114 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
2118 if (!valid_user_group_name_or_id(k
)) {
2119 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2133 int config_parse_user_group_strv(
2135 const char *filename
,
2137 const char *section
,
2138 unsigned section_line
,
2145 char ***users
= data
;
2155 if (isempty(rvalue
)) {
2156 *users
= strv_free(*users
);
2162 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2164 r
= extract_first_word(&p
, &word
, NULL
, 0);
2170 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
2174 r
= unit_full_printf(u
, word
, &k
);
2176 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
2180 if (!valid_user_group_name_or_id(k
)) {
2181 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2185 r
= strv_push(users
, k
);
2195 int config_parse_working_directory(
2197 const char *filename
,
2199 const char *section
,
2200 unsigned section_line
,
2207 ExecContext
*c
= data
;
2218 if (rvalue
[0] == '-') {
2224 if (streq(rvalue
, "~")) {
2225 c
->working_directory_home
= true;
2226 c
->working_directory
= mfree(c
->working_directory
);
2228 _cleanup_free_
char *k
= NULL
;
2230 r
= unit_full_printf(u
, rvalue
, &k
);
2232 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2233 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2234 rvalue
, missing_ok
? ", ignoring" : "");
2235 return missing_ok
? 0 : -ENOEXEC
;
2238 path_kill_slashes(k
);
2240 if (!utf8_is_valid(k
)) {
2241 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2242 return missing_ok
? 0 : -ENOEXEC
;
2245 if (!path_is_absolute(k
)) {
2246 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2247 "Working directory path '%s' is not absolute%s.",
2248 rvalue
, missing_ok
? ", ignoring" : "");
2249 return missing_ok
? 0 : -ENOEXEC
;
2252 c
->working_directory_home
= false;
2253 free_and_replace(c
->working_directory
, k
);
2256 c
->working_directory_missing_ok
= missing_ok
;
2260 int config_parse_unit_env_file(const char *unit
,
2261 const char *filename
,
2263 const char *section
,
2264 unsigned section_line
,
2273 _cleanup_free_
char *n
= NULL
;
2281 if (isempty(rvalue
)) {
2282 /* Empty assignment frees the list */
2283 *env
= strv_free(*env
);
2287 r
= unit_full_printf(u
, rvalue
, &n
);
2289 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2293 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2294 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2298 r
= strv_extend(env
, n
);
2305 int config_parse_environ(
2307 const char *filename
,
2309 const char *section
,
2310 unsigned section_line
,
2327 if (isempty(rvalue
)) {
2328 /* Empty assignment resets the list */
2329 *env
= strv_free(*env
);
2333 for (p
= rvalue
;; ) {
2334 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2336 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2342 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2343 "Invalid syntax, ignoring: %s", rvalue
);
2348 r
= unit_full_printf(u
, word
, &k
);
2350 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2351 "Failed to resolve specifiers, ignoring: %s", word
);
2359 if (!env_assignment_is_valid(k
)) {
2360 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2361 "Invalid environment assignment, ignoring: %s", k
);
2365 r
= strv_env_replace(env
, k
);
2373 int config_parse_pass_environ(
2375 const char *filename
,
2377 const char *section
,
2378 unsigned section_line
,
2385 const char *whole_rvalue
= rvalue
;
2386 _cleanup_strv_free_
char **n
= NULL
;
2387 size_t nlen
= 0, nbufsize
= 0;
2388 char*** passenv
= data
;
2397 if (isempty(rvalue
)) {
2398 /* Empty assignment resets the list */
2399 *passenv
= strv_free(*passenv
);
2404 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2406 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2412 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2413 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2418 r
= unit_full_printf(u
, word
, &k
);
2420 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2421 "Failed to resolve specifiers, ignoring: %s", word
);
2429 if (!env_name_is_valid(k
)) {
2430 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2431 "Invalid environment name for %s, ignoring: %s", lvalue
, k
);
2435 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2444 r
= strv_extend_strv(passenv
, n
, true);
2452 int config_parse_unset_environ(
2454 const char *filename
,
2456 const char *section
,
2457 unsigned section_line
,
2464 _cleanup_strv_free_
char **n
= NULL
;
2465 const char *whole_rvalue
= rvalue
;
2466 size_t nlen
= 0, nbufsize
= 0;
2467 char*** unsetenv
= data
;
2476 if (isempty(rvalue
)) {
2477 /* Empty assignment resets the list */
2478 *unsetenv
= strv_free(*unsetenv
);
2483 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2485 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2491 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2492 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2497 r
= unit_full_printf(u
, word
, &k
);
2499 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2500 "Failed to resolve specifiers, ignoring: %s", word
);
2508 if (!env_assignment_is_valid(k
) && !env_name_is_valid(k
)) {
2509 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2510 "Invalid environment name or assignment %s, ignoring: %s", lvalue
, k
);
2514 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2523 r
= strv_extend_strv(unsetenv
, n
, true);
2531 int config_parse_log_extra_fields(
2533 const char *filename
,
2535 const char *section
,
2536 unsigned section_line
,
2543 ExecContext
*c
= data
;
2553 if (isempty(rvalue
)) {
2554 exec_context_free_log_extra_fields(c
);
2558 for (p
= rvalue
;; ) {
2559 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2563 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2569 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2573 r
= unit_full_printf(u
, word
, &k
);
2575 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring field: %m", word
);
2579 eq
= strchr(k
, '=');
2581 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field lacks '=' character, ignoring field: %s", k
);
2585 if (!journal_field_valid(k
, eq
-k
, false)) {
2586 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field name is invalid, ignoring field: %s", k
);
2590 t
= realloc_multiply(c
->log_extra_fields
, sizeof(struct iovec
), c
->n_log_extra_fields
+1);
2594 c
->log_extra_fields
= t
;
2595 c
->log_extra_fields
[c
->n_log_extra_fields
++] = IOVEC_MAKE_STRING(k
);
2603 int config_parse_ip_tos(const char *unit
,
2604 const char *filename
,
2606 const char *section
,
2607 unsigned section_line
,
2614 int *ip_tos
= data
, x
;
2621 x
= ip_tos_from_string(rvalue
);
2623 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2631 int config_parse_unit_condition_path(
2633 const char *filename
,
2635 const char *section
,
2636 unsigned section_line
,
2643 _cleanup_free_
char *p
= NULL
;
2644 Condition
**list
= data
, *c
;
2645 ConditionType t
= ltype
;
2646 bool trigger
, negate
;
2655 if (isempty(rvalue
)) {
2656 /* Empty assignment resets the list */
2657 *list
= condition_free_list(*list
);
2661 trigger
= rvalue
[0] == '|';
2665 negate
= rvalue
[0] == '!';
2669 r
= unit_full_printf(u
, rvalue
, &p
);
2671 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2675 if (!path_is_absolute(p
)) {
2676 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2680 c
= condition_new(t
, p
, trigger
, negate
);
2684 LIST_PREPEND(conditions
, *list
, c
);
2688 int config_parse_unit_condition_string(
2690 const char *filename
,
2692 const char *section
,
2693 unsigned section_line
,
2700 _cleanup_free_
char *s
= NULL
;
2701 Condition
**list
= data
, *c
;
2702 ConditionType t
= ltype
;
2703 bool trigger
, negate
;
2712 if (isempty(rvalue
)) {
2713 /* Empty assignment resets the list */
2714 *list
= condition_free_list(*list
);
2718 trigger
= rvalue
[0] == '|';
2722 negate
= rvalue
[0] == '!';
2726 r
= unit_full_printf(u
, rvalue
, &s
);
2728 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2732 c
= condition_new(t
, s
, trigger
, negate
);
2736 LIST_PREPEND(conditions
, *list
, c
);
2740 int config_parse_unit_condition_null(
2742 const char *filename
,
2744 const char *section
,
2745 unsigned section_line
,
2752 Condition
**list
= data
, *c
;
2753 bool trigger
, negate
;
2761 if (isempty(rvalue
)) {
2762 /* Empty assignment resets the list */
2763 *list
= condition_free_list(*list
);
2767 trigger
= rvalue
[0] == '|';
2771 negate
= rvalue
[0] == '!';
2775 b
= parse_boolean(rvalue
);
2777 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2784 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2788 LIST_PREPEND(conditions
, *list
, c
);
2792 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2793 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2795 int config_parse_unit_requires_mounts_for(
2797 const char *filename
,
2799 const char *section
,
2800 unsigned section_line
,
2816 for (p
= rvalue
;; ) {
2817 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2819 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2825 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2826 "Invalid syntax, ignoring: %s", rvalue
);
2830 if (!utf8_is_valid(word
)) {
2831 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2835 r
= unit_full_printf(u
, word
, &resolved
);
2837 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2841 r
= unit_require_mounts_for(u
, resolved
, UNIT_DEPENDENCY_FILE
);
2843 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2849 int config_parse_documentation(const char *unit
,
2850 const char *filename
,
2852 const char *section
,
2853 unsigned section_line
,
2869 if (isempty(rvalue
)) {
2870 /* Empty assignment resets the list */
2871 u
->documentation
= strv_free(u
->documentation
);
2875 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2876 rvalue
, data
, userdata
);
2880 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2882 if (documentation_url_is_valid(*a
))
2885 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2896 int config_parse_syscall_filter(
2898 const char *filename
,
2900 const char *section
,
2901 unsigned section_line
,
2908 ExecContext
*c
= data
;
2910 bool invert
= false;
2919 if (isempty(rvalue
)) {
2920 /* Empty assignment resets the list */
2921 c
->syscall_filter
= hashmap_free(c
->syscall_filter
);
2922 c
->syscall_whitelist
= false;
2926 if (rvalue
[0] == '~') {
2931 if (!c
->syscall_filter
) {
2932 c
->syscall_filter
= hashmap_new(NULL
);
2933 if (!c
->syscall_filter
)
2937 /* Allow everything but the ones listed */
2938 c
->syscall_whitelist
= false;
2940 /* Allow nothing but the ones listed */
2941 c
->syscall_whitelist
= true;
2943 /* Accept default syscalls if we are on a whitelist */
2944 r
= seccomp_parse_syscall_filter(false, "@default", -1, c
->syscall_filter
, true);
2952 _cleanup_free_
char *word
= NULL
, *name
= NULL
;
2955 r
= extract_first_word(&p
, &word
, NULL
, 0);
2961 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2965 r
= parse_syscall_and_errno(word
, &name
, &num
);
2967 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse syscall:errno, ignoring: %s", word
);
2971 r
= seccomp_parse_syscall_filter_and_warn(invert
, name
, num
, c
->syscall_filter
, c
->syscall_whitelist
, unit
, filename
, line
);
2979 int config_parse_syscall_archs(
2981 const char *filename
,
2983 const char *section
,
2984 unsigned section_line
,
2995 if (isempty(rvalue
)) {
2996 *archs
= set_free(*archs
);
3000 r
= set_ensure_allocated(archs
, NULL
);
3004 for (p
= rvalue
;;) {
3005 _cleanup_free_
char *word
= NULL
;
3008 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3014 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3015 "Invalid syntax, ignoring: %s", rvalue
);
3019 r
= seccomp_arch_from_string(word
, &a
);
3021 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3022 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
3026 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
3032 int config_parse_syscall_errno(
3034 const char *filename
,
3036 const char *section
,
3037 unsigned section_line
,
3044 ExecContext
*c
= data
;
3051 if (isempty(rvalue
)) {
3052 /* Empty assignment resets to KILL */
3053 c
->syscall_errno
= 0;
3057 e
= parse_errno(rvalue
);
3059 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
3063 c
->syscall_errno
= e
;
3067 int config_parse_address_families(
3069 const char *filename
,
3071 const char *section
,
3072 unsigned section_line
,
3079 ExecContext
*c
= data
;
3080 bool invert
= false;
3088 if (isempty(rvalue
)) {
3089 /* Empty assignment resets the list */
3090 c
->address_families
= set_free(c
->address_families
);
3091 c
->address_families_whitelist
= false;
3095 if (rvalue
[0] == '~') {
3100 if (!c
->address_families
) {
3101 c
->address_families
= set_new(NULL
);
3102 if (!c
->address_families
)
3105 c
->address_families_whitelist
= !invert
;
3108 for (p
= rvalue
;;) {
3109 _cleanup_free_
char *word
= NULL
;
3112 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3118 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3119 "Invalid syntax, ignoring: %s", rvalue
);
3123 af
= af_from_name(word
);
3125 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3126 "Failed to parse address family \"%s\", ignoring: %m", word
);
3130 /* If we previously wanted to forbid an address family and now
3131 * we want to allow it, then just remove it from the list.
3133 if (!invert
== c
->address_families_whitelist
) {
3134 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
3138 set_remove(c
->address_families
, INT_TO_PTR(af
));
3142 int config_parse_restrict_namespaces(
3144 const char *filename
,
3146 const char *section
,
3147 unsigned section_line
,
3154 ExecContext
*c
= data
;
3155 bool invert
= false;
3158 if (isempty(rvalue
)) {
3159 /* Reset to the default. */
3160 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3164 if (rvalue
[0] == '~') {
3169 r
= parse_boolean(rvalue
);
3171 c
->restrict_namespaces
= 0;
3173 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3175 /* Not a boolean argument, in this case it's a list of namespace types. */
3177 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
3179 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
3185 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
3191 int config_parse_unit_slice(
3193 const char *filename
,
3195 const char *section
,
3196 unsigned section_line
,
3203 _cleanup_free_
char *k
= NULL
;
3204 Unit
*u
= userdata
, *slice
= NULL
;
3212 r
= unit_name_printf(u
, rvalue
, &k
);
3214 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3218 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3220 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3224 r
= unit_set_slice(u
, slice
);
3226 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3233 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3235 int config_parse_cpu_weight(
3237 const char *filename
,
3239 const char *section
,
3240 unsigned section_line
,
3247 uint64_t *weight
= data
;
3254 r
= cg_weight_parse(rvalue
, weight
);
3256 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3263 int config_parse_cpu_shares(
3265 const char *filename
,
3267 const char *section
,
3268 unsigned section_line
,
3275 uint64_t *shares
= data
;
3282 r
= cg_cpu_shares_parse(rvalue
, shares
);
3284 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3291 int config_parse_cpu_quota(
3293 const char *filename
,
3295 const char *section
,
3296 unsigned section_line
,
3303 CGroupContext
*c
= data
;
3310 if (isempty(rvalue
)) {
3311 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3315 r
= parse_percent_unbounded(rvalue
);
3317 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3321 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3325 int config_parse_memory_limit(
3327 const char *filename
,
3329 const char *section
,
3330 unsigned section_line
,
3337 CGroupContext
*c
= data
;
3338 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3341 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3343 r
= parse_percent(rvalue
);
3345 r
= parse_size(rvalue
, 1024, &bytes
);
3347 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3351 bytes
= physical_memory_scale(r
, 100U);
3353 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3354 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3359 if (streq(lvalue
, "MemoryLow"))
3360 c
->memory_low
= bytes
;
3361 else if (streq(lvalue
, "MemoryHigh"))
3362 c
->memory_high
= bytes
;
3363 else if (streq(lvalue
, "MemoryMax"))
3364 c
->memory_max
= bytes
;
3365 else if (streq(lvalue
, "MemorySwapMax"))
3366 c
->memory_swap_max
= bytes
;
3367 else if (streq(lvalue
, "MemoryLimit"))
3368 c
->memory_limit
= bytes
;
3375 int config_parse_tasks_max(
3377 const char *filename
,
3379 const char *section
,
3380 unsigned section_line
,
3387 uint64_t *tasks_max
= data
, v
;
3391 if (isempty(rvalue
)) {
3392 *tasks_max
= u
->manager
->default_tasks_max
;
3396 if (streq(rvalue
, "infinity")) {
3397 *tasks_max
= CGROUP_LIMIT_MAX
;
3401 r
= parse_percent(rvalue
);
3403 r
= safe_atou64(rvalue
, &v
);
3405 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3409 v
= system_tasks_max_scale(r
, 100U);
3411 if (v
<= 0 || v
>= UINT64_MAX
) {
3412 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3420 int config_parse_delegate(
3422 const char *filename
,
3424 const char *section
,
3425 unsigned section_line
,
3432 CGroupContext
*c
= data
;
3435 /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
3436 * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
3437 * mask to delegate. */
3439 if (isempty(rvalue
)) {
3441 c
->delegate_controllers
= 0;
3445 r
= parse_boolean(rvalue
);
3447 const char *p
= rvalue
;
3448 CGroupMask mask
= 0;
3451 _cleanup_free_
char *word
= NULL
;
3452 CGroupController cc
;
3454 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3460 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
3464 cc
= cgroup_controller_from_string(word
);
3466 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid controller name '%s', ignoring", rvalue
);
3470 mask
|= CGROUP_CONTROLLER_TO_MASK(cc
);
3474 c
->delegate_controllers
|= mask
;
3478 c
->delegate_controllers
= _CGROUP_MASK_ALL
;
3480 c
->delegate
= false;
3481 c
->delegate_controllers
= 0;
3487 int config_parse_device_allow(
3489 const char *filename
,
3491 const char *section
,
3492 unsigned section_line
,
3499 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3500 CGroupContext
*c
= data
;
3501 CGroupDeviceAllow
*a
;
3502 const char *m
= NULL
;
3506 if (isempty(rvalue
)) {
3507 while (c
->device_allow
)
3508 cgroup_context_free_device_allow(c
, c
->device_allow
);
3513 r
= unit_full_printf(userdata
, rvalue
, &t
);
3515 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3516 "Failed to resolve specifiers in %s, ignoring: %m",
3520 n
= strcspn(t
, WHITESPACE
);
3522 path
= strndup(t
, n
);
3526 if (!is_deviceallow_pattern(path
) &&
3527 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3528 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3532 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3536 if (!in_charset(m
, "rwm")) {
3537 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3541 a
= new0(CGroupDeviceAllow
, 1);
3547 a
->r
= !!strchr(m
, 'r');
3548 a
->w
= !!strchr(m
, 'w');
3549 a
->m
= !!strchr(m
, 'm');
3551 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3555 int config_parse_io_weight(
3557 const char *filename
,
3559 const char *section
,
3560 unsigned section_line
,
3567 uint64_t *weight
= data
;
3574 r
= cg_weight_parse(rvalue
, weight
);
3576 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3583 int config_parse_io_device_weight(
3585 const char *filename
,
3587 const char *section
,
3588 unsigned section_line
,
3595 _cleanup_free_
char *path
= NULL
;
3596 CGroupIODeviceWeight
*w
;
3597 CGroupContext
*c
= data
;
3607 if (isempty(rvalue
)) {
3608 while (c
->io_device_weights
)
3609 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3614 n
= strcspn(rvalue
, WHITESPACE
);
3615 weight
= rvalue
+ n
;
3616 weight
+= strspn(weight
, WHITESPACE
);
3618 if (isempty(weight
)) {
3619 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3623 path
= strndup(rvalue
, n
);
3627 if (!path_startswith(path
, "/dev") &&
3628 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3629 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3633 r
= cg_weight_parse(weight
, &u
);
3635 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3639 assert(u
!= CGROUP_WEIGHT_INVALID
);
3641 w
= new0(CGroupIODeviceWeight
, 1);
3650 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3654 int config_parse_io_limit(
3656 const char *filename
,
3658 const char *section
,
3659 unsigned section_line
,
3666 _cleanup_free_
char *path
= NULL
;
3667 CGroupIODeviceLimit
*l
= NULL
, *t
;
3668 CGroupContext
*c
= data
;
3669 CGroupIOLimitType type
;
3679 type
= cgroup_io_limit_type_from_string(lvalue
);
3682 if (isempty(rvalue
)) {
3683 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3684 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3688 n
= strcspn(rvalue
, WHITESPACE
);
3690 limit
+= strspn(limit
, WHITESPACE
);
3693 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3697 path
= strndup(rvalue
, n
);
3701 if (!path_startswith(path
, "/dev") &&
3702 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3703 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3707 if (streq("infinity", limit
)) {
3708 num
= CGROUP_LIMIT_MAX
;
3710 r
= parse_size(limit
, 1000, &num
);
3711 if (r
< 0 || num
<= 0) {
3712 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3717 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3718 if (path_equal(path
, t
->path
)) {
3725 CGroupIOLimitType ttype
;
3727 l
= new0(CGroupIODeviceLimit
, 1);
3733 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3734 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3736 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3739 l
->limits
[type
] = num
;
3744 int config_parse_blockio_weight(
3746 const char *filename
,
3748 const char *section
,
3749 unsigned section_line
,
3756 uint64_t *weight
= data
;
3763 r
= cg_blkio_weight_parse(rvalue
, weight
);
3765 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3772 int config_parse_blockio_device_weight(
3774 const char *filename
,
3776 const char *section
,
3777 unsigned section_line
,
3784 _cleanup_free_
char *path
= NULL
;
3785 CGroupBlockIODeviceWeight
*w
;
3786 CGroupContext
*c
= data
;
3796 if (isempty(rvalue
)) {
3797 while (c
->blockio_device_weights
)
3798 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3803 n
= strcspn(rvalue
, WHITESPACE
);
3804 weight
= rvalue
+ n
;
3805 weight
+= strspn(weight
, WHITESPACE
);
3807 if (isempty(weight
)) {
3808 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3812 path
= strndup(rvalue
, n
);
3816 if (!path_startswith(path
, "/dev") &&
3817 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3818 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3822 r
= cg_blkio_weight_parse(weight
, &u
);
3824 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3828 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3830 w
= new0(CGroupBlockIODeviceWeight
, 1);
3839 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3843 int config_parse_blockio_bandwidth(
3845 const char *filename
,
3847 const char *section
,
3848 unsigned section_line
,
3855 _cleanup_free_
char *path
= NULL
;
3856 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3857 CGroupContext
*c
= data
;
3858 const char *bandwidth
;
3868 read
= streq("BlockIOReadBandwidth", lvalue
);
3870 if (isempty(rvalue
)) {
3871 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3872 b
->rbps
= CGROUP_LIMIT_MAX
;
3873 b
->wbps
= CGROUP_LIMIT_MAX
;
3878 n
= strcspn(rvalue
, WHITESPACE
);
3879 bandwidth
= rvalue
+ n
;
3880 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3883 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3887 path
= strndup(rvalue
, n
);
3891 if (!path_startswith(path
, "/dev") &&
3892 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3893 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3897 r
= parse_size(bandwidth
, 1000, &bytes
);
3898 if (r
< 0 || bytes
<= 0) {
3899 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3903 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3904 if (path_equal(path
, t
->path
)) {
3911 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3917 b
->rbps
= CGROUP_LIMIT_MAX
;
3918 b
->wbps
= CGROUP_LIMIT_MAX
;
3920 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3931 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3933 int config_parse_job_mode_isolate(
3935 const char *filename
,
3937 const char *section
,
3938 unsigned section_line
,
3952 r
= parse_boolean(rvalue
);
3954 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3958 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3962 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3964 int config_parse_exec_directories(
3966 const char *filename
,
3968 const char *section
,
3969 unsigned section_line
,
3986 if (isempty(rvalue
)) {
3987 /* Empty assignment resets the list */
3988 *rt
= strv_free(*rt
);
3992 for (p
= rvalue
;;) {
3993 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3995 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3999 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
4000 "Invalid syntax, ignoring: %s", rvalue
);
4006 r
= unit_full_printf(u
, word
, &k
);
4008 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4009 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
4013 if (!path_is_normalized(k
) || path_is_absolute(k
)) {
4014 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
4015 "%s= path is not valid, ignoring assignment: %s", lvalue
, rvalue
);
4019 r
= strv_push(rt
, k
);
4026 int config_parse_set_status(
4028 const char *filename
,
4030 const char *section
,
4031 unsigned section_line
,
4039 const char *word
, *state
;
4041 ExitStatusSet
*status_set
= data
;
4048 /* Empty assignment resets the list */
4049 if (isempty(rvalue
)) {
4050 exit_status_set_free(status_set
);
4054 FOREACH_WORD(word
, l
, rvalue
, state
) {
4055 _cleanup_free_
char *temp
;
4059 temp
= strndup(word
, l
);
4063 r
= safe_atoi(temp
, &val
);
4065 val
= signal_from_string_try_harder(temp
);
4068 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
4071 set
= &status_set
->signal
;
4073 if (val
< 0 || val
> 255) {
4074 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
4077 set
= &status_set
->status
;
4080 r
= set_ensure_allocated(set
, NULL
);
4084 r
= set_put(*set
, INT_TO_PTR(val
));
4086 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
4090 if (!isempty(state
))
4091 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
4096 int config_parse_namespace_path_strv(
4098 const char *filename
,
4100 const char *section
,
4101 unsigned section_line
,
4118 if (isempty(rvalue
)) {
4119 /* Empty assignment resets the list */
4120 *sv
= strv_free(*sv
);
4126 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
4128 bool ignore_enoent
= false, shall_prefix
= false;
4130 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
4136 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
4140 if (!utf8_is_valid(word
)) {
4141 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
4146 if (startswith(w
, "-")) {
4147 ignore_enoent
= true;
4150 if (startswith(w
, "+")) {
4151 shall_prefix
= true;
4155 r
= unit_full_printf(u
, w
, &resolved
);
4157 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
4161 if (!path_is_absolute(resolved
)) {
4162 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
4166 path_kill_slashes(resolved
);
4168 joined
= strjoin(ignore_enoent
? "-" : "",
4169 shall_prefix
? "+" : "",
4172 r
= strv_push(sv
, joined
);
4182 int config_parse_bind_paths(
4184 const char *filename
,
4186 const char *section
,
4187 unsigned section_line
,
4194 ExecContext
*c
= data
;
4204 if (isempty(rvalue
)) {
4205 /* Empty assignment resets the list */
4206 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
4207 c
->bind_mounts
= NULL
;
4208 c
->n_bind_mounts
= 0;
4214 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
4215 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
4216 char *s
= NULL
, *d
= NULL
;
4217 bool rbind
= true, ignore_enoent
= false;
4219 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4225 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4229 r
= unit_full_printf(u
, source
, &sresolved
);
4231 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4232 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
4238 ignore_enoent
= true;
4242 if (!utf8_is_valid(s
)) {
4243 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
4246 if (!path_is_absolute(s
)) {
4247 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
4251 path_kill_slashes(s
);
4253 /* Optionally, the destination is specified. */
4254 if (p
&& p
[-1] == ':') {
4255 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4259 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4263 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
4267 r
= unit_full_printf(u
, destination
, &dresolved
);
4269 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4270 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
4274 if (!utf8_is_valid(dresolved
)) {
4275 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
4278 if (!path_is_absolute(dresolved
)) {
4279 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
4283 d
= path_kill_slashes(dresolved
);
4285 /* Optionally, there's also a short option string specified */
4286 if (p
&& p
[-1] == ':') {
4287 _cleanup_free_
char *options
= NULL
;
4289 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
4293 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4297 if (isempty(options
) || streq(options
, "rbind"))
4299 else if (streq(options
, "norbind"))
4302 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4309 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4313 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4315 .ignore_enoent
= ignore_enoent
,
4324 int config_parse_no_new_privileges(
4326 const char *filename
,
4328 const char *section
,
4329 unsigned section_line
,
4336 ExecContext
*c
= data
;
4344 k
= parse_boolean(rvalue
);
4346 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4350 c
->no_new_privileges
= k
;
4355 int config_parse_protect_home(
4357 const char *filename
,
4359 const char *section
,
4360 unsigned section_line
,
4367 ExecContext
*c
= data
;
4375 /* Our enum shall be a superset of booleans, hence first try
4376 * to parse as boolean, and then as enum */
4378 k
= parse_boolean(rvalue
);
4380 c
->protect_home
= PROTECT_HOME_YES
;
4382 c
->protect_home
= PROTECT_HOME_NO
;
4386 h
= protect_home_from_string(rvalue
);
4388 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4392 c
->protect_home
= h
;
4398 int config_parse_protect_system(
4400 const char *filename
,
4402 const char *section
,
4403 unsigned section_line
,
4410 ExecContext
*c
= data
;
4418 /* Our enum shall be a superset of booleans, hence first try
4419 * to parse as boolean, and then as enum */
4421 k
= parse_boolean(rvalue
);
4423 c
->protect_system
= PROTECT_SYSTEM_YES
;
4425 c
->protect_system
= PROTECT_SYSTEM_NO
;
4429 s
= protect_system_from_string(rvalue
);
4431 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4435 c
->protect_system
= s
;
4441 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode
, exec_keyring_mode
, ExecKeyringMode
, "Failed to parse keyring mode");
4443 int config_parse_job_timeout_sec(
4445 const char *filename
,
4447 const char *section
,
4448 unsigned section_line
,
4464 r
= parse_sec_fix_0(rvalue
, &usec
);
4466 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue
);
4470 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4471 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4474 if (!u
->job_running_timeout_set
)
4475 u
->job_running_timeout
= usec
;
4477 u
->job_timeout
= usec
;
4482 int config_parse_job_running_timeout_sec(
4484 const char *filename
,
4486 const char *section
,
4487 unsigned section_line
,
4503 r
= parse_sec_fix_0(rvalue
, &usec
);
4505 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue
);
4509 u
->job_running_timeout
= usec
;
4510 u
->job_running_timeout_set
= true;
4515 #define FOLLOW_MAX 8
4517 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4528 /* This will update the filename pointer if the loaded file is
4529 * reached by a symlink. The old string will be freed. */
4532 char *target
, *name
;
4534 if (c
++ >= FOLLOW_MAX
)
4537 path_kill_slashes(*filename
);
4539 /* Add the file name we are currently looking at to
4540 * the names of this unit, but only if it is a valid
4542 name
= basename(*filename
);
4543 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4545 id
= set_get(names
, name
);
4551 r
= set_consume(names
, id
);
4557 /* Try to open the file name, but don't if its a symlink */
4558 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4565 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4566 r
= readlink_and_make_absolute(*filename
, &target
);
4574 f
= fdopen(fd
, "re");
4586 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4594 /* Let's try to add in all symlink names we found */
4595 while ((k
= set_steal_first(names
))) {
4597 /* First try to merge in the other name into our
4599 r
= unit_merge_by_name(*u
, k
);
4603 /* Hmm, we couldn't merge the other unit into
4604 * ours? Then let's try it the other way
4607 /* If the symlink name we are looking at is unit template, then
4608 we must search for instance of this template */
4609 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4610 _cleanup_free_
char *instance
= NULL
;
4612 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4616 other
= manager_get_unit((*u
)->manager
, instance
);
4618 other
= manager_get_unit((*u
)->manager
, k
);
4623 r
= unit_merge(other
, *u
);
4626 return merge_by_names(u
, names
, NULL
);
4634 unit_choose_id(*u
, id
);
4642 static int load_from_path(Unit
*u
, const char *path
) {
4643 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4644 _cleanup_fclose_
FILE *f
= NULL
;
4645 _cleanup_free_
char *filename
= NULL
;
4654 symlink_names
= set_new(&string_hash_ops
);
4658 if (path_is_absolute(path
)) {
4660 filename
= strdup(path
);
4664 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4666 filename
= mfree(filename
);
4674 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4676 /* Instead of opening the path right away, we manually
4677 * follow all symlinks and add their name to our unit
4678 * name set while doing so */
4679 filename
= path_make_absolute(path
, *p
);
4683 if (u
->manager
->unit_path_cache
&&
4684 !set_get(u
->manager
->unit_path_cache
, filename
))
4687 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4690 filename
= mfree(filename
);
4692 /* ENOENT means that the file is missing or is a dangling symlink.
4693 * ENOTDIR means that one of paths we expect to be is a directory
4694 * is not a directory, we should just ignore that.
4695 * EACCES means that the directory or file permissions are wrong.
4698 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4699 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4702 /* Empty the symlink names for the next run */
4703 set_clear_free(symlink_names
);
4708 /* Hmm, no suitable file found? */
4711 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4712 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4717 r
= merge_by_names(&merged
, symlink_names
, id
);
4722 u
->load_state
= UNIT_MERGED
;
4726 if (fstat(fileno(f
), &st
) < 0)
4729 if (null_or_empty(&st
)) {
4730 u
->load_state
= UNIT_MASKED
;
4731 u
->fragment_mtime
= 0;
4733 u
->load_state
= UNIT_LOADED
;
4734 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4736 /* Now, parse the file contents */
4737 r
= config_parse(u
->id
, filename
, f
,
4738 UNIT_VTABLE(u
)->sections
,
4739 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4740 CONFIG_PARSE_ALLOW_INCLUDE
, u
);
4745 free(u
->fragment_path
);
4746 u
->fragment_path
= filename
;
4749 if (u
->source_path
) {
4750 if (stat(u
->source_path
, &st
) >= 0)
4751 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4753 u
->source_mtime
= 0;
4759 int unit_load_fragment(Unit
*u
) {
4765 assert(u
->load_state
== UNIT_STUB
);
4769 u
->load_state
= UNIT_LOADED
;
4773 /* First, try to find the unit under its id. We always look
4774 * for unit files in the default directories, to make it easy
4775 * to override things by placing things in /etc/systemd/system */
4776 r
= load_from_path(u
, u
->id
);
4780 /* Try to find an alias we can load this with */
4781 if (u
->load_state
== UNIT_STUB
) {
4782 SET_FOREACH(t
, u
->names
, i
) {
4787 r
= load_from_path(u
, t
);
4791 if (u
->load_state
!= UNIT_STUB
)
4796 /* And now, try looking for it under the suggested (originally linked) path */
4797 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4799 r
= load_from_path(u
, u
->fragment_path
);
4803 if (u
->load_state
== UNIT_STUB
)
4804 /* Hmm, this didn't work? Then let's get rid
4805 * of the fragment path stored for us, so that
4806 * we don't point to an invalid location. */
4807 u
->fragment_path
= mfree(u
->fragment_path
);
4810 /* Look for a template */
4811 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4812 _cleanup_free_
char *k
= NULL
;
4814 r
= unit_name_template(u
->id
, &k
);
4818 r
= load_from_path(u
, k
);
4821 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4825 if (u
->load_state
== UNIT_STUB
) {
4826 SET_FOREACH(t
, u
->names
, i
) {
4827 _cleanup_free_
char *z
= NULL
;
4832 r
= unit_name_template(t
, &z
);
4836 r
= load_from_path(u
, z
);
4840 if (u
->load_state
!= UNIT_STUB
)
4849 void unit_dump_config_items(FILE *f
) {
4850 static const struct {
4851 const ConfigParserCallback callback
;
4854 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4855 { config_parse_warn_compat
, "NOTSUPPORTED" },
4857 { config_parse_int
, "INTEGER" },
4858 { config_parse_unsigned
, "UNSIGNED" },
4859 { config_parse_iec_size
, "SIZE" },
4860 { config_parse_iec_uint64
, "SIZE" },
4861 { config_parse_si_size
, "SIZE" },
4862 { config_parse_bool
, "BOOLEAN" },
4863 { config_parse_string
, "STRING" },
4864 { config_parse_path
, "PATH" },
4865 { config_parse_unit_path_printf
, "PATH" },
4866 { config_parse_strv
, "STRING [...]" },
4867 { config_parse_exec_nice
, "NICE" },
4868 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4869 { config_parse_exec_io_class
, "IOCLASS" },
4870 { config_parse_exec_io_priority
, "IOPRIORITY" },
4871 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4872 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4873 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4874 { config_parse_mode
, "MODE" },
4875 { config_parse_unit_env_file
, "FILE" },
4876 { config_parse_exec_output
, "OUTPUT" },
4877 { config_parse_exec_input
, "INPUT" },
4878 { config_parse_log_facility
, "FACILITY" },
4879 { config_parse_log_level
, "LEVEL" },
4880 { config_parse_exec_secure_bits
, "SECUREBITS" },
4881 { config_parse_capability_set
, "BOUNDINGSET" },
4882 { config_parse_limit
, "LIMIT" },
4883 { config_parse_unit_deps
, "UNIT [...]" },
4884 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4885 { config_parse_service_type
, "SERVICETYPE" },
4886 { config_parse_service_restart
, "SERVICERESTART" },
4887 #if HAVE_SYSV_COMPAT
4888 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4890 { config_parse_kill_mode
, "KILLMODE" },
4891 { config_parse_signal
, "SIGNAL" },
4892 { config_parse_socket_listen
, "SOCKET [...]" },
4893 { config_parse_socket_bind
, "SOCKETBIND" },
4894 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4895 { config_parse_sec
, "SECONDS" },
4896 { config_parse_nsec
, "NANOSECONDS" },
4897 { config_parse_namespace_path_strv
, "PATH [...]" },
4898 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4899 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4900 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4901 { config_parse_unit_string_printf
, "STRING" },
4902 { config_parse_trigger_unit
, "UNIT" },
4903 { config_parse_timer
, "TIMER" },
4904 { config_parse_path_spec
, "PATH" },
4905 { config_parse_notify_access
, "ACCESS" },
4906 { config_parse_ip_tos
, "TOS" },
4907 { config_parse_unit_condition_path
, "CONDITION" },
4908 { config_parse_unit_condition_string
, "CONDITION" },
4909 { config_parse_unit_condition_null
, "CONDITION" },
4910 { config_parse_unit_slice
, "SLICE" },
4911 { config_parse_documentation
, "URL" },
4912 { config_parse_service_timeout
, "SECONDS" },
4913 { config_parse_emergency_action
, "ACTION" },
4914 { config_parse_set_status
, "STATUS" },
4915 { config_parse_service_sockets
, "SOCKETS" },
4916 { config_parse_environ
, "ENVIRON" },
4918 { config_parse_syscall_filter
, "SYSCALLS" },
4919 { config_parse_syscall_archs
, "ARCHS" },
4920 { config_parse_syscall_errno
, "ERRNO" },
4921 { config_parse_address_families
, "FAMILIES" },
4922 { config_parse_restrict_namespaces
, "NAMESPACES" },
4924 { config_parse_cpu_shares
, "SHARES" },
4925 { config_parse_cpu_weight
, "WEIGHT" },
4926 { config_parse_memory_limit
, "LIMIT" },
4927 { config_parse_device_allow
, "DEVICE" },
4928 { config_parse_device_policy
, "POLICY" },
4929 { config_parse_io_limit
, "LIMIT" },
4930 { config_parse_io_weight
, "WEIGHT" },
4931 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4932 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4933 { config_parse_blockio_weight
, "WEIGHT" },
4934 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4935 { config_parse_long
, "LONG" },
4936 { config_parse_socket_service
, "SERVICE" },
4938 { config_parse_exec_selinux_context
, "LABEL" },
4940 { config_parse_job_mode
, "MODE" },
4941 { config_parse_job_mode_isolate
, "BOOLEAN" },
4942 { config_parse_personality
, "PERSONALITY" },
4945 const char *prev
= NULL
;
4950 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4951 const char *rvalue
= "OTHER", *lvalue
;
4955 const ConfigPerfItem
*p
;
4957 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4959 dot
= strchr(i
, '.');
4960 lvalue
= dot
? dot
+ 1 : i
;
4964 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4968 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4971 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4972 if (p
->parse
== table
[j
].callback
) {
4973 rvalue
= table
[j
].rvalue
;
4977 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);