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
= parse_socket_address_bind_ipv6_only_or_bool(rvalue
);
502 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
506 s
->bind_ipv6_only
= b
;
511 int config_parse_exec_nice(
513 const char *filename
,
516 unsigned section_line
,
523 ExecContext
*c
= data
;
531 r
= parse_nice(rvalue
, &priority
);
534 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
536 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
547 int config_parse_exec_oom_score_adjust(const char* unit
,
548 const char *filename
,
551 unsigned section_line
,
558 ExecContext
*c
= data
;
566 r
= safe_atoi(rvalue
, &oa
);
568 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
572 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
573 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
577 c
->oom_score_adjust
= oa
;
578 c
->oom_score_adjust_set
= true;
583 int config_parse_exec(
585 const char *filename
,
588 unsigned section_line
,
595 ExecCommand
**e
= data
;
607 rvalue
+= strspn(rvalue
, WHITESPACE
);
609 if (isempty(rvalue
)) {
610 /* An empty assignment resets the list */
611 *e
= exec_command_free_list(*e
);
617 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
618 ExecCommandFlags flags
= 0;
619 bool ignore
= false, separate_argv0
= false;
620 _cleanup_free_ ExecCommand
*nce
= NULL
;
621 _cleanup_strv_free_
char **n
= NULL
;
622 size_t nlen
= 0, nbufsize
= 0;
627 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
633 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
634 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
635 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
636 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
637 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
638 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
639 * other sandboxing, with some special exceptions for changing UID.
641 * The idea is that '!!' may be used to write services that can take benefit of systemd's
642 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
643 * privilege dropping within the daemon if the kernel does not offer that. */
645 if (*f
== '-' && !(flags
& EXEC_COMMAND_IGNORE_FAILURE
)) {
646 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
648 } else if (*f
== '@' && !separate_argv0
)
649 separate_argv0
= true;
650 else if (*f
== '+' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
651 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
652 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
653 flags
|= EXEC_COMMAND_NO_SETUID
;
654 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
655 flags
&= ~EXEC_COMMAND_NO_SETUID
;
656 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
662 r
= unit_full_printf(u
, f
, &path
);
664 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
665 "Failed to resolve unit specifiers on %s%s: %m",
666 f
, ignore
? ", ignoring" : "");
667 return ignore
? 0 : -ENOEXEC
;
671 /* First word is either "-" or "@" with no command. */
672 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
673 "Empty path in command line%s: \"%s\"",
674 ignore
? ", ignoring" : "", rvalue
);
675 return ignore
? 0 : -ENOEXEC
;
677 if (!string_is_safe(path
)) {
678 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
679 "Executable path contains special characters%s: %s",
680 ignore
? ", ignoring" : "", rvalue
);
681 return ignore
? 0 : -ENOEXEC
;
683 if (!path_is_absolute(path
)) {
684 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
685 "Executable path is not absolute%s: %s",
686 ignore
? ", ignoring" : "", rvalue
);
687 return ignore
? 0 : -ENOEXEC
;
689 if (endswith(path
, "/")) {
690 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
691 "Executable path specifies a directory%s: %s",
692 ignore
? ", ignoring" : "", rvalue
);
693 return ignore
? 0 : -ENOEXEC
;
696 if (!separate_argv0
) {
699 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
709 path_kill_slashes(path
);
711 while (!isempty(p
)) {
712 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
714 /* Check explicitly for an unquoted semicolon as
715 * command separator token. */
716 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
718 p
+= strspn(p
, WHITESPACE
);
723 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
724 * extract_first_word() would return the same for all of those. */
725 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
729 p
+= strspn(p
, WHITESPACE
);
731 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
742 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
746 return ignore
? 0 : -ENOEXEC
;
748 r
= unit_full_printf(u
, word
, &resolved
);
750 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
751 "Failed to resolve unit specifiers on %s%s: %m",
752 word
, ignore
? ", ignoring" : "");
753 return ignore
? 0 : -ENOEXEC
;
756 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
758 n
[nlen
++] = resolved
;
764 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
765 "Empty executable name or zeroeth argument%s: %s",
766 ignore
? ", ignoring" : "", rvalue
);
767 return ignore
? 0 : -ENOEXEC
;
770 nce
= new0(ExecCommand
, 1);
778 exec_command_append_list(e
, nce
);
780 /* Do not _cleanup_free_ these. */
791 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
792 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
794 int config_parse_socket_bindtodevice(
796 const char *filename
,
799 unsigned section_line
,
814 if (rvalue
[0] && !streq(rvalue
, "*")) {
815 if (!ifname_valid(rvalue
)) {
816 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
826 free(s
->bind_to_device
);
827 s
->bind_to_device
= n
;
832 int config_parse_exec_input(
834 const char *filename
,
837 unsigned section_line
,
844 ExecContext
*c
= data
;
855 n
= startswith(rvalue
, "fd:");
857 _cleanup_free_
char *resolved
= NULL
;
859 r
= unit_full_printf(u
, n
, &resolved
);
861 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
863 if (isempty(resolved
))
864 resolved
= mfree(resolved
);
865 else if (!fdname_is_valid(resolved
)) {
866 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name: %s", resolved
);
870 free_and_replace(c
->stdio_fdname
[STDIN_FILENO
], resolved
);
872 ei
= EXEC_INPUT_NAMED_FD
;
874 } else if ((n
= startswith(rvalue
, "file:"))) {
875 _cleanup_free_
char *resolved
= NULL
;
877 r
= unit_full_printf(u
, n
, &resolved
);
879 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
881 if (!path_is_absolute(resolved
)) {
882 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
886 if (!path_is_normalized(resolved
)) {
887 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name: %s", resolved
);
891 free_and_replace(c
->stdio_file
[STDIN_FILENO
], resolved
);
893 ei
= EXEC_INPUT_FILE
;
896 ei
= exec_input_from_string(rvalue
);
898 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
907 int config_parse_exec_input_text(
909 const char *filename
,
912 unsigned section_line
,
919 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
920 ExecContext
*c
= data
;
931 if (isempty(rvalue
)) {
932 /* Reset if the empty string is assigned */
933 c
->stdin_data
= mfree(c
->stdin_data
);
934 c
->stdin_data_size
= 0;
938 r
= cunescape(rvalue
, 0, &unescaped
);
940 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode C escaped text: %s", rvalue
);
942 r
= unit_full_printf(u
, unescaped
, &resolved
);
944 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", unescaped
);
946 sz
= strlen(resolved
);
947 if (c
->stdin_data_size
+ sz
+ 1 < c
->stdin_data_size
|| /* check for overflow */
948 c
->stdin_data_size
+ sz
+ 1 > EXEC_STDIN_DATA_MAX
) {
949 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c
->stdin_data_size
+ sz
, (size_t) EXEC_STDIN_DATA_MAX
);
953 p
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
+ 1);
957 *((char*) mempcpy((char*) p
+ c
->stdin_data_size
, resolved
, sz
)) = '\n';
960 c
->stdin_data_size
+= sz
+ 1;
965 int config_parse_exec_input_data(
967 const char *filename
,
970 unsigned section_line
,
977 _cleanup_free_
void *p
= NULL
;
978 ExecContext
*c
= data
;
988 if (isempty(rvalue
)) {
989 /* Reset if the empty string is assigned */
990 c
->stdin_data
= mfree(c
->stdin_data
);
991 c
->stdin_data_size
= 0;
995 r
= unbase64mem(rvalue
, (size_t) -1, &p
, &sz
);
997 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode base64 data, ignoring: %s", rvalue
);
1001 if (c
->stdin_data_size
+ sz
< c
->stdin_data_size
|| /* check for overflow */
1002 c
->stdin_data_size
+ sz
> EXEC_STDIN_DATA_MAX
) {
1003 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c
->stdin_data_size
+ sz
, (size_t) EXEC_STDIN_DATA_MAX
);
1007 q
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
);
1011 memcpy((uint8_t*) q
+ c
->stdin_data_size
, p
, sz
);
1014 c
->stdin_data_size
+= sz
;
1019 int config_parse_exec_output(
1021 const char *filename
,
1023 const char *section
,
1024 unsigned section_line
,
1031 _cleanup_free_
char *resolved
= NULL
;
1033 ExecContext
*c
= data
;
1044 n
= startswith(rvalue
, "fd:");
1046 r
= unit_full_printf(u
, n
, &resolved
);
1048 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1050 if (isempty(resolved
))
1051 resolved
= mfree(resolved
);
1052 else if (!fdname_is_valid(resolved
)) {
1053 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name: %s", resolved
);
1057 eo
= EXEC_OUTPUT_NAMED_FD
;
1059 } else if ((n
= startswith(rvalue
, "file:"))) {
1061 r
= unit_full_printf(u
, n
, &resolved
);
1063 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1065 if (!path_is_absolute(resolved
)) {
1066 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
1070 if (!path_is_normalized(resolved
)) {
1071 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name, ignoring: %s", resolved
);
1075 eo
= EXEC_OUTPUT_FILE
;
1078 eo
= exec_output_from_string(rvalue
);
1080 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
1085 if (streq(lvalue
, "StandardOutput")) {
1086 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1087 free_and_replace(c
->stdio_fdname
[STDOUT_FILENO
], resolved
);
1089 free_and_replace(c
->stdio_file
[STDOUT_FILENO
], resolved
);
1094 assert(streq(lvalue
, "StandardError"));
1096 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1097 free_and_replace(c
->stdio_fdname
[STDERR_FILENO
], resolved
);
1099 free_and_replace(c
->stdio_file
[STDERR_FILENO
], resolved
);
1107 int config_parse_exec_io_class(const char *unit
,
1108 const char *filename
,
1110 const char *section
,
1111 unsigned section_line
,
1118 ExecContext
*c
= data
;
1126 x
= ioprio_class_from_string(rvalue
);
1128 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
1132 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
1133 c
->ioprio_set
= true;
1138 int config_parse_exec_io_priority(const char *unit
,
1139 const char *filename
,
1141 const char *section
,
1142 unsigned section_line
,
1149 ExecContext
*c
= data
;
1157 r
= ioprio_parse_priority(rvalue
, &i
);
1159 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
1163 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
1164 c
->ioprio_set
= true;
1169 int config_parse_exec_cpu_sched_policy(const char *unit
,
1170 const char *filename
,
1172 const char *section
,
1173 unsigned section_line
,
1181 ExecContext
*c
= data
;
1189 x
= sched_policy_from_string(rvalue
);
1191 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1195 c
->cpu_sched_policy
= x
;
1196 /* Moving to or from real-time policy? We need to adjust the priority */
1197 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1198 c
->cpu_sched_set
= true;
1203 int config_parse_exec_cpu_sched_prio(const char *unit
,
1204 const char *filename
,
1206 const char *section
,
1207 unsigned section_line
,
1214 ExecContext
*c
= data
;
1222 r
= safe_atoi(rvalue
, &i
);
1224 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1228 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1229 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1230 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1232 if (i
< min
|| i
> max
) {
1233 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1237 c
->cpu_sched_priority
= i
;
1238 c
->cpu_sched_set
= true;
1243 int config_parse_exec_cpu_affinity(const char *unit
,
1244 const char *filename
,
1246 const char *section
,
1247 unsigned section_line
,
1254 ExecContext
*c
= data
;
1255 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1263 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1268 /* An empty assignment resets the CPU list */
1269 c
->cpuset
= cpu_set_mfree(c
->cpuset
);
1270 c
->cpuset_ncpus
= 0;
1277 c
->cpuset_ncpus
= (unsigned) ncpus
;
1281 if (c
->cpuset_ncpus
< (unsigned) ncpus
) {
1282 CPU_OR_S(CPU_ALLOC_SIZE(c
->cpuset_ncpus
), cpuset
, c
->cpuset
, cpuset
);
1283 CPU_FREE(c
->cpuset
);
1286 c
->cpuset_ncpus
= (unsigned) ncpus
;
1290 CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus
), c
->cpuset
, c
->cpuset
, cpuset
);
1295 int config_parse_exec_secure_bits(const char *unit
,
1296 const char *filename
,
1298 const char *section
,
1299 unsigned section_line
,
1306 ExecContext
*c
= data
;
1314 if (isempty(rvalue
)) {
1315 /* An empty assignment resets the field */
1320 r
= secure_bits_from_string(rvalue
);
1324 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1325 "Invalid syntax, ignoring: %s", rvalue
);
1334 int config_parse_capability_set(
1336 const char *filename
,
1338 const char *section
,
1339 unsigned section_line
,
1346 uint64_t *capability_set
= data
;
1347 uint64_t sum
= 0, initial
= 0;
1348 bool invert
= false;
1356 if (rvalue
[0] == '~') {
1361 if (streq(lvalue
, "CapabilityBoundingSet"))
1362 initial
= CAP_ALL
; /* initialized to all bits on */
1363 /* else "AmbientCapabilities" initialized to all bits off */
1365 r
= capability_set_from_string(rvalue
, &sum
);
1369 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1373 if (sum
== 0 || *capability_set
== initial
)
1374 /* "", "~" or uninitialized data -> replace */
1375 *capability_set
= invert
? ~sum
: sum
;
1377 /* previous data -> merge */
1379 *capability_set
&= ~sum
;
1381 *capability_set
|= sum
;
1387 int config_parse_limit(
1389 const char *filename
,
1391 const char *section
,
1392 unsigned section_line
,
1399 struct rlimit
**rl
= data
, d
= {};
1407 r
= rlimit_parse(ltype
, rvalue
, &d
);
1409 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1413 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1420 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1428 #if HAVE_SYSV_COMPAT
1429 int config_parse_sysv_priority(const char *unit
,
1430 const char *filename
,
1432 const char *section
,
1433 unsigned section_line
,
1440 int *priority
= data
;
1448 r
= safe_atoi(rvalue
, &i
);
1449 if (r
< 0 || i
< 0) {
1450 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1454 *priority
= (int) i
;
1459 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1460 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1462 int config_parse_exec_mount_flags(
1464 const char *filename
,
1466 const char *section
,
1467 unsigned section_line
,
1475 ExecContext
*c
= data
;
1483 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1485 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1490 int config_parse_exec_selinux_context(
1492 const char *filename
,
1494 const char *section
,
1495 unsigned section_line
,
1502 ExecContext
*c
= data
;
1513 if (isempty(rvalue
)) {
1514 c
->selinux_context
= mfree(c
->selinux_context
);
1515 c
->selinux_context_ignore
= false;
1519 if (rvalue
[0] == '-') {
1525 r
= unit_full_printf(u
, rvalue
, &k
);
1527 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1528 "Failed to resolve specifiers%s: %m",
1529 ignore
? ", ignoring" : "");
1530 return ignore
? 0 : -ENOEXEC
;
1533 free(c
->selinux_context
);
1534 c
->selinux_context
= k
;
1535 c
->selinux_context_ignore
= ignore
;
1540 int config_parse_exec_apparmor_profile(
1542 const char *filename
,
1544 const char *section
,
1545 unsigned section_line
,
1552 ExecContext
*c
= data
;
1563 if (isempty(rvalue
)) {
1564 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1565 c
->apparmor_profile_ignore
= false;
1569 if (rvalue
[0] == '-') {
1575 r
= unit_full_printf(u
, rvalue
, &k
);
1577 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1578 "Failed to resolve specifiers%s: %m",
1579 ignore
? ", ignoring" : "");
1580 return ignore
? 0 : -ENOEXEC
;
1583 free(c
->apparmor_profile
);
1584 c
->apparmor_profile
= k
;
1585 c
->apparmor_profile_ignore
= ignore
;
1590 int config_parse_exec_smack_process_label(
1592 const char *filename
,
1594 const char *section
,
1595 unsigned section_line
,
1602 ExecContext
*c
= data
;
1613 if (isempty(rvalue
)) {
1614 c
->smack_process_label
= mfree(c
->smack_process_label
);
1615 c
->smack_process_label_ignore
= false;
1619 if (rvalue
[0] == '-') {
1625 r
= unit_full_printf(u
, rvalue
, &k
);
1627 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1628 "Failed to resolve specifiers%s: %m",
1629 ignore
? ", ignoring" : "");
1630 return ignore
? 0 : -ENOEXEC
;
1633 free(c
->smack_process_label
);
1634 c
->smack_process_label
= k
;
1635 c
->smack_process_label_ignore
= ignore
;
1640 int config_parse_timer(const char *unit
,
1641 const char *filename
,
1643 const char *section
,
1644 unsigned section_line
,
1655 CalendarSpec
*c
= NULL
;
1657 _cleanup_free_
char *k
= NULL
;
1665 if (isempty(rvalue
)) {
1666 /* Empty assignment resets list */
1667 timer_free_values(t
);
1671 b
= timer_base_from_string(lvalue
);
1673 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1677 r
= unit_full_printf(u
, rvalue
, &k
);
1679 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1683 if (b
== TIMER_CALENDAR
) {
1684 if (calendar_spec_from_string(k
, &c
) < 0) {
1685 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1689 if (parse_sec(k
, &usec
) < 0) {
1690 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1695 v
= new0(TimerValue
, 1);
1697 calendar_spec_free(c
);
1703 v
->calendar_spec
= c
;
1705 LIST_PREPEND(value
, t
->values
, v
);
1710 int config_parse_trigger_unit(
1712 const char *filename
,
1714 const char *section
,
1715 unsigned section_line
,
1722 _cleanup_free_
char *p
= NULL
;
1732 if (!hashmap_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1733 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1737 r
= unit_name_printf(u
, rvalue
, &p
);
1739 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1743 type
= unit_name_to_type(p
);
1745 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1749 if (type
== u
->type
) {
1750 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1754 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1756 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1763 int config_parse_path_spec(const char *unit
,
1764 const char *filename
,
1766 const char *section
,
1767 unsigned section_line
,
1777 _cleanup_free_
char *k
= NULL
;
1785 if (isempty(rvalue
)) {
1786 /* Empty assignment clears list */
1791 b
= path_type_from_string(lvalue
);
1793 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1797 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1799 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1803 if (!path_is_absolute(k
)) {
1804 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1808 s
= new0(PathSpec
, 1);
1813 s
->path
= path_kill_slashes(k
);
1818 LIST_PREPEND(spec
, p
->specs
, s
);
1823 int config_parse_socket_service(
1825 const char *filename
,
1827 const char *section
,
1828 unsigned section_line
,
1835 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1836 _cleanup_free_
char *p
= NULL
;
1846 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1848 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1852 if (!endswith(p
, ".service")) {
1853 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1857 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1859 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1863 unit_ref_set(&s
->service
, x
);
1868 int config_parse_fdname(
1870 const char *filename
,
1872 const char *section
,
1873 unsigned section_line
,
1880 _cleanup_free_
char *p
= NULL
;
1889 if (isempty(rvalue
)) {
1890 s
->fdname
= mfree(s
->fdname
);
1894 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1896 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1900 if (!fdname_is_valid(p
)) {
1901 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1905 return free_and_replace(s
->fdname
, p
);
1908 int config_parse_service_sockets(
1910 const char *filename
,
1912 const char *section
,
1913 unsigned section_line
,
1931 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1933 r
= extract_first_word(&p
, &word
, NULL
, 0);
1939 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1943 r
= unit_name_printf(UNIT(s
), word
, &k
);
1945 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1949 if (!endswith(k
, ".socket")) {
1950 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1954 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1956 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1958 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1960 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1966 int config_parse_bus_name(
1968 const char *filename
,
1970 const char *section
,
1971 unsigned section_line
,
1978 _cleanup_free_
char *k
= NULL
;
1987 r
= unit_full_printf(u
, rvalue
, &k
);
1989 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1993 if (!service_name_is_valid(k
)) {
1994 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1998 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
2001 int config_parse_service_timeout(
2003 const char *filename
,
2005 const char *section
,
2006 unsigned section_line
,
2013 Service
*s
= userdata
;
2022 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
2024 r
= parse_sec(rvalue
, &usec
);
2026 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2030 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
2031 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
2032 * all other timeouts. */
2034 usec
= USEC_INFINITY
;
2036 if (!streq(lvalue
, "TimeoutStopSec")) {
2037 s
->start_timeout_defined
= true;
2038 s
->timeout_start_usec
= usec
;
2041 if (!streq(lvalue
, "TimeoutStartSec"))
2042 s
->timeout_stop_usec
= usec
;
2047 int config_parse_sec_fix_0(
2049 const char *filename
,
2051 const char *section
,
2052 unsigned section_line
,
2059 usec_t
*usec
= data
;
2067 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
2068 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
2071 r
= parse_sec_fix_0(rvalue
, usec
);
2073 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2080 int config_parse_user_group(
2082 const char *filename
,
2084 const char *section
,
2085 unsigned section_line
,
2092 char **user
= data
, *n
;
2101 if (isempty(rvalue
))
2104 _cleanup_free_
char *k
= NULL
;
2106 r
= unit_full_printf(u
, rvalue
, &k
);
2108 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
2112 if (!valid_user_group_name_or_id(k
)) {
2113 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2127 int config_parse_user_group_strv(
2129 const char *filename
,
2131 const char *section
,
2132 unsigned section_line
,
2139 char ***users
= data
;
2149 if (isempty(rvalue
)) {
2150 *users
= strv_free(*users
);
2156 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2158 r
= extract_first_word(&p
, &word
, NULL
, 0);
2164 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
2168 r
= unit_full_printf(u
, word
, &k
);
2170 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
2174 if (!valid_user_group_name_or_id(k
)) {
2175 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2179 r
= strv_push(users
, k
);
2189 int config_parse_working_directory(
2191 const char *filename
,
2193 const char *section
,
2194 unsigned section_line
,
2201 ExecContext
*c
= data
;
2212 if (rvalue
[0] == '-') {
2218 if (streq(rvalue
, "~")) {
2219 c
->working_directory_home
= true;
2220 c
->working_directory
= mfree(c
->working_directory
);
2222 _cleanup_free_
char *k
= NULL
;
2224 r
= unit_full_printf(u
, rvalue
, &k
);
2226 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2227 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2228 rvalue
, missing_ok
? ", ignoring" : "");
2229 return missing_ok
? 0 : -ENOEXEC
;
2232 path_kill_slashes(k
);
2234 if (!utf8_is_valid(k
)) {
2235 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2236 return missing_ok
? 0 : -ENOEXEC
;
2239 if (!path_is_absolute(k
)) {
2240 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2241 "Working directory path '%s' is not absolute%s.",
2242 rvalue
, missing_ok
? ", ignoring" : "");
2243 return missing_ok
? 0 : -ENOEXEC
;
2246 c
->working_directory_home
= false;
2247 free_and_replace(c
->working_directory
, k
);
2250 c
->working_directory_missing_ok
= missing_ok
;
2254 int config_parse_unit_env_file(const char *unit
,
2255 const char *filename
,
2257 const char *section
,
2258 unsigned section_line
,
2267 _cleanup_free_
char *n
= NULL
;
2275 if (isempty(rvalue
)) {
2276 /* Empty assignment frees the list */
2277 *env
= strv_free(*env
);
2281 r
= unit_full_printf(u
, rvalue
, &n
);
2283 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2287 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2288 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2292 r
= strv_extend(env
, n
);
2299 int config_parse_environ(
2301 const char *filename
,
2303 const char *section
,
2304 unsigned section_line
,
2321 if (isempty(rvalue
)) {
2322 /* Empty assignment resets the list */
2323 *env
= strv_free(*env
);
2327 for (p
= rvalue
;; ) {
2328 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2330 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2336 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2337 "Invalid syntax, ignoring: %s", rvalue
);
2342 r
= unit_full_printf(u
, word
, &k
);
2344 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2345 "Failed to resolve specifiers, ignoring: %s", word
);
2353 if (!env_assignment_is_valid(k
)) {
2354 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2355 "Invalid environment assignment, ignoring: %s", k
);
2359 r
= strv_env_replace(env
, k
);
2367 int config_parse_pass_environ(
2369 const char *filename
,
2371 const char *section
,
2372 unsigned section_line
,
2379 const char *whole_rvalue
= rvalue
;
2380 _cleanup_strv_free_
char **n
= NULL
;
2381 size_t nlen
= 0, nbufsize
= 0;
2382 char*** passenv
= data
;
2391 if (isempty(rvalue
)) {
2392 /* Empty assignment resets the list */
2393 *passenv
= strv_free(*passenv
);
2398 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2400 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2406 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2407 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2412 r
= unit_full_printf(u
, word
, &k
);
2414 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2415 "Failed to resolve specifiers, ignoring: %s", word
);
2423 if (!env_name_is_valid(k
)) {
2424 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2425 "Invalid environment name for %s, ignoring: %s", lvalue
, k
);
2429 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2438 r
= strv_extend_strv(passenv
, n
, true);
2446 int config_parse_unset_environ(
2448 const char *filename
,
2450 const char *section
,
2451 unsigned section_line
,
2458 _cleanup_strv_free_
char **n
= NULL
;
2459 const char *whole_rvalue
= rvalue
;
2460 size_t nlen
= 0, nbufsize
= 0;
2461 char*** unsetenv
= data
;
2470 if (isempty(rvalue
)) {
2471 /* Empty assignment resets the list */
2472 *unsetenv
= strv_free(*unsetenv
);
2477 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2479 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2485 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2486 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2491 r
= unit_full_printf(u
, word
, &k
);
2493 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2494 "Failed to resolve specifiers, ignoring: %s", word
);
2502 if (!env_assignment_is_valid(k
) && !env_name_is_valid(k
)) {
2503 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2504 "Invalid environment name or assignment %s, ignoring: %s", lvalue
, k
);
2508 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2517 r
= strv_extend_strv(unsetenv
, n
, true);
2525 int config_parse_log_extra_fields(
2527 const char *filename
,
2529 const char *section
,
2530 unsigned section_line
,
2537 ExecContext
*c
= data
;
2547 if (isempty(rvalue
)) {
2548 exec_context_free_log_extra_fields(c
);
2552 for (p
= rvalue
;; ) {
2553 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2557 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2563 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2567 r
= unit_full_printf(u
, word
, &k
);
2569 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring field: %m", word
);
2573 eq
= strchr(k
, '=');
2575 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field lacks '=' character, ignoring field: %s", k
);
2579 if (!journal_field_valid(k
, eq
-k
, false)) {
2580 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field name is invalid, ignoring field: %s", k
);
2584 t
= realloc_multiply(c
->log_extra_fields
, sizeof(struct iovec
), c
->n_log_extra_fields
+1);
2588 c
->log_extra_fields
= t
;
2589 c
->log_extra_fields
[c
->n_log_extra_fields
++] = IOVEC_MAKE_STRING(k
);
2597 int config_parse_ip_tos(const char *unit
,
2598 const char *filename
,
2600 const char *section
,
2601 unsigned section_line
,
2608 int *ip_tos
= data
, x
;
2615 x
= ip_tos_from_string(rvalue
);
2617 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2625 int config_parse_unit_condition_path(
2627 const char *filename
,
2629 const char *section
,
2630 unsigned section_line
,
2637 _cleanup_free_
char *p
= NULL
;
2638 Condition
**list
= data
, *c
;
2639 ConditionType t
= ltype
;
2640 bool trigger
, negate
;
2649 if (isempty(rvalue
)) {
2650 /* Empty assignment resets the list */
2651 *list
= condition_free_list(*list
);
2655 trigger
= rvalue
[0] == '|';
2659 negate
= rvalue
[0] == '!';
2663 r
= unit_full_printf(u
, rvalue
, &p
);
2665 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2669 if (!path_is_absolute(p
)) {
2670 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2674 c
= condition_new(t
, p
, trigger
, negate
);
2678 LIST_PREPEND(conditions
, *list
, c
);
2682 int config_parse_unit_condition_string(
2684 const char *filename
,
2686 const char *section
,
2687 unsigned section_line
,
2694 _cleanup_free_
char *s
= NULL
;
2695 Condition
**list
= data
, *c
;
2696 ConditionType t
= ltype
;
2697 bool trigger
, negate
;
2706 if (isempty(rvalue
)) {
2707 /* Empty assignment resets the list */
2708 *list
= condition_free_list(*list
);
2712 trigger
= rvalue
[0] == '|';
2716 negate
= rvalue
[0] == '!';
2720 r
= unit_full_printf(u
, rvalue
, &s
);
2722 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2726 c
= condition_new(t
, s
, trigger
, negate
);
2730 LIST_PREPEND(conditions
, *list
, c
);
2734 int config_parse_unit_condition_null(
2736 const char *filename
,
2738 const char *section
,
2739 unsigned section_line
,
2746 Condition
**list
= data
, *c
;
2747 bool trigger
, negate
;
2755 if (isempty(rvalue
)) {
2756 /* Empty assignment resets the list */
2757 *list
= condition_free_list(*list
);
2761 trigger
= rvalue
[0] == '|';
2765 negate
= rvalue
[0] == '!';
2769 b
= parse_boolean(rvalue
);
2771 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2778 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2782 LIST_PREPEND(conditions
, *list
, c
);
2786 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2787 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2789 int config_parse_unit_requires_mounts_for(
2791 const char *filename
,
2793 const char *section
,
2794 unsigned section_line
,
2810 for (p
= rvalue
;; ) {
2811 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2813 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2819 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2820 "Invalid syntax, ignoring: %s", rvalue
);
2824 if (!utf8_is_valid(word
)) {
2825 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2829 r
= unit_full_printf(u
, word
, &resolved
);
2831 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2835 r
= unit_require_mounts_for(u
, resolved
, UNIT_DEPENDENCY_FILE
);
2837 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2843 int config_parse_documentation(const char *unit
,
2844 const char *filename
,
2846 const char *section
,
2847 unsigned section_line
,
2863 if (isempty(rvalue
)) {
2864 /* Empty assignment resets the list */
2865 u
->documentation
= strv_free(u
->documentation
);
2869 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2870 rvalue
, data
, userdata
);
2874 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2876 if (documentation_url_is_valid(*a
))
2879 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2890 int config_parse_syscall_filter(
2892 const char *filename
,
2894 const char *section
,
2895 unsigned section_line
,
2902 ExecContext
*c
= data
;
2904 bool invert
= false;
2913 if (isempty(rvalue
)) {
2914 /* Empty assignment resets the list */
2915 c
->syscall_filter
= hashmap_free(c
->syscall_filter
);
2916 c
->syscall_whitelist
= false;
2920 if (rvalue
[0] == '~') {
2925 if (!c
->syscall_filter
) {
2926 c
->syscall_filter
= hashmap_new(NULL
);
2927 if (!c
->syscall_filter
)
2931 /* Allow everything but the ones listed */
2932 c
->syscall_whitelist
= false;
2934 /* Allow nothing but the ones listed */
2935 c
->syscall_whitelist
= true;
2937 /* Accept default syscalls if we are on a whitelist */
2938 r
= seccomp_parse_syscall_filter(false, "@default", -1, c
->syscall_filter
, true);
2946 _cleanup_free_
char *word
= NULL
, *name
= NULL
;
2949 r
= extract_first_word(&p
, &word
, NULL
, 0);
2955 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2959 r
= parse_syscall_and_errno(word
, &name
, &num
);
2961 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse syscall:errno, ignoring: %s", word
);
2965 r
= seccomp_parse_syscall_filter_and_warn(invert
, name
, num
, c
->syscall_filter
, c
->syscall_whitelist
, unit
, filename
, line
);
2973 int config_parse_syscall_archs(
2975 const char *filename
,
2977 const char *section
,
2978 unsigned section_line
,
2989 if (isempty(rvalue
)) {
2990 *archs
= set_free(*archs
);
2994 r
= set_ensure_allocated(archs
, NULL
);
2998 for (p
= rvalue
;;) {
2999 _cleanup_free_
char *word
= NULL
;
3002 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3008 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3009 "Invalid syntax, ignoring: %s", rvalue
);
3013 r
= seccomp_arch_from_string(word
, &a
);
3015 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3016 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
3020 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
3026 int config_parse_syscall_errno(
3028 const char *filename
,
3030 const char *section
,
3031 unsigned section_line
,
3038 ExecContext
*c
= data
;
3045 if (isempty(rvalue
)) {
3046 /* Empty assignment resets to KILL */
3047 c
->syscall_errno
= 0;
3051 e
= parse_errno(rvalue
);
3053 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
3057 c
->syscall_errno
= e
;
3061 int config_parse_address_families(
3063 const char *filename
,
3065 const char *section
,
3066 unsigned section_line
,
3073 ExecContext
*c
= data
;
3074 bool invert
= false;
3082 if (isempty(rvalue
)) {
3083 /* Empty assignment resets the list */
3084 c
->address_families
= set_free(c
->address_families
);
3085 c
->address_families_whitelist
= false;
3089 if (rvalue
[0] == '~') {
3094 if (!c
->address_families
) {
3095 c
->address_families
= set_new(NULL
);
3096 if (!c
->address_families
)
3099 c
->address_families_whitelist
= !invert
;
3102 for (p
= rvalue
;;) {
3103 _cleanup_free_
char *word
= NULL
;
3106 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3112 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3113 "Invalid syntax, ignoring: %s", rvalue
);
3117 af
= af_from_name(word
);
3119 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3120 "Failed to parse address family \"%s\", ignoring: %m", word
);
3124 /* If we previously wanted to forbid an address family and now
3125 * we want to allow it, then just remove it from the list.
3127 if (!invert
== c
->address_families_whitelist
) {
3128 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
3132 set_remove(c
->address_families
, INT_TO_PTR(af
));
3136 int config_parse_restrict_namespaces(
3138 const char *filename
,
3140 const char *section
,
3141 unsigned section_line
,
3148 ExecContext
*c
= data
;
3149 bool invert
= false;
3152 if (isempty(rvalue
)) {
3153 /* Reset to the default. */
3154 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3158 if (rvalue
[0] == '~') {
3163 r
= parse_boolean(rvalue
);
3165 c
->restrict_namespaces
= 0;
3167 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3169 /* Not a boolean argument, in this case it's a list of namespace types. */
3171 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
3173 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
3179 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
3185 int config_parse_unit_slice(
3187 const char *filename
,
3189 const char *section
,
3190 unsigned section_line
,
3197 _cleanup_free_
char *k
= NULL
;
3198 Unit
*u
= userdata
, *slice
= NULL
;
3206 r
= unit_name_printf(u
, rvalue
, &k
);
3208 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3212 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3214 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3218 r
= unit_set_slice(u
, slice
);
3220 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3227 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3229 int config_parse_cpu_weight(
3231 const char *filename
,
3233 const char *section
,
3234 unsigned section_line
,
3241 uint64_t *weight
= data
;
3248 r
= cg_weight_parse(rvalue
, weight
);
3250 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3257 int config_parse_cpu_shares(
3259 const char *filename
,
3261 const char *section
,
3262 unsigned section_line
,
3269 uint64_t *shares
= data
;
3276 r
= cg_cpu_shares_parse(rvalue
, shares
);
3278 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3285 int config_parse_cpu_quota(
3287 const char *filename
,
3289 const char *section
,
3290 unsigned section_line
,
3297 CGroupContext
*c
= data
;
3304 if (isempty(rvalue
)) {
3305 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3309 r
= parse_percent_unbounded(rvalue
);
3311 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3315 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3319 int config_parse_memory_limit(
3321 const char *filename
,
3323 const char *section
,
3324 unsigned section_line
,
3331 CGroupContext
*c
= data
;
3332 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3335 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3337 r
= parse_percent(rvalue
);
3339 r
= parse_size(rvalue
, 1024, &bytes
);
3341 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3345 bytes
= physical_memory_scale(r
, 100U);
3347 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3348 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3353 if (streq(lvalue
, "MemoryLow"))
3354 c
->memory_low
= bytes
;
3355 else if (streq(lvalue
, "MemoryHigh"))
3356 c
->memory_high
= bytes
;
3357 else if (streq(lvalue
, "MemoryMax"))
3358 c
->memory_max
= bytes
;
3359 else if (streq(lvalue
, "MemorySwapMax"))
3360 c
->memory_swap_max
= bytes
;
3361 else if (streq(lvalue
, "MemoryLimit"))
3362 c
->memory_limit
= bytes
;
3369 int config_parse_tasks_max(
3371 const char *filename
,
3373 const char *section
,
3374 unsigned section_line
,
3381 uint64_t *tasks_max
= data
, v
;
3385 if (isempty(rvalue
)) {
3386 *tasks_max
= u
->manager
->default_tasks_max
;
3390 if (streq(rvalue
, "infinity")) {
3391 *tasks_max
= CGROUP_LIMIT_MAX
;
3395 r
= parse_percent(rvalue
);
3397 r
= safe_atou64(rvalue
, &v
);
3399 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3403 v
= system_tasks_max_scale(r
, 100U);
3405 if (v
<= 0 || v
>= UINT64_MAX
) {
3406 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3414 int config_parse_delegate(
3416 const char *filename
,
3418 const char *section
,
3419 unsigned section_line
,
3426 CGroupContext
*c
= data
;
3429 /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
3430 * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
3431 * mask to delegate. */
3433 if (isempty(rvalue
)) {
3435 c
->delegate_controllers
= 0;
3439 r
= parse_boolean(rvalue
);
3441 const char *p
= rvalue
;
3442 CGroupMask mask
= 0;
3445 _cleanup_free_
char *word
= NULL
;
3446 CGroupController cc
;
3448 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3454 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
3458 cc
= cgroup_controller_from_string(word
);
3460 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid controller name '%s', ignoring", rvalue
);
3464 mask
|= CGROUP_CONTROLLER_TO_MASK(cc
);
3468 c
->delegate_controllers
|= mask
;
3472 c
->delegate_controllers
= _CGROUP_MASK_ALL
;
3474 c
->delegate
= false;
3475 c
->delegate_controllers
= 0;
3481 int config_parse_device_allow(
3483 const char *filename
,
3485 const char *section
,
3486 unsigned section_line
,
3493 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3494 CGroupContext
*c
= data
;
3495 CGroupDeviceAllow
*a
;
3496 const char *m
= NULL
;
3500 if (isempty(rvalue
)) {
3501 while (c
->device_allow
)
3502 cgroup_context_free_device_allow(c
, c
->device_allow
);
3507 r
= unit_full_printf(userdata
, rvalue
, &t
);
3509 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3510 "Failed to resolve specifiers in %s, ignoring: %m",
3514 n
= strcspn(t
, WHITESPACE
);
3516 path
= strndup(t
, n
);
3520 if (!is_deviceallow_pattern(path
) &&
3521 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3522 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3526 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3530 if (!in_charset(m
, "rwm")) {
3531 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3535 a
= new0(CGroupDeviceAllow
, 1);
3541 a
->r
= !!strchr(m
, 'r');
3542 a
->w
= !!strchr(m
, 'w');
3543 a
->m
= !!strchr(m
, 'm');
3545 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3549 int config_parse_io_weight(
3551 const char *filename
,
3553 const char *section
,
3554 unsigned section_line
,
3561 uint64_t *weight
= data
;
3568 r
= cg_weight_parse(rvalue
, weight
);
3570 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3577 int config_parse_io_device_weight(
3579 const char *filename
,
3581 const char *section
,
3582 unsigned section_line
,
3589 _cleanup_free_
char *path
= NULL
;
3590 CGroupIODeviceWeight
*w
;
3591 CGroupContext
*c
= data
;
3601 if (isempty(rvalue
)) {
3602 while (c
->io_device_weights
)
3603 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3608 n
= strcspn(rvalue
, WHITESPACE
);
3609 weight
= rvalue
+ n
;
3610 weight
+= strspn(weight
, WHITESPACE
);
3612 if (isempty(weight
)) {
3613 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3617 path
= strndup(rvalue
, n
);
3621 if (!path_startswith(path
, "/dev") &&
3622 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3623 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3627 r
= cg_weight_parse(weight
, &u
);
3629 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3633 assert(u
!= CGROUP_WEIGHT_INVALID
);
3635 w
= new0(CGroupIODeviceWeight
, 1);
3644 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3648 int config_parse_io_limit(
3650 const char *filename
,
3652 const char *section
,
3653 unsigned section_line
,
3660 _cleanup_free_
char *path
= NULL
;
3661 CGroupIODeviceLimit
*l
= NULL
, *t
;
3662 CGroupContext
*c
= data
;
3663 CGroupIOLimitType type
;
3673 type
= cgroup_io_limit_type_from_string(lvalue
);
3676 if (isempty(rvalue
)) {
3677 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3678 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3682 n
= strcspn(rvalue
, WHITESPACE
);
3684 limit
+= strspn(limit
, WHITESPACE
);
3687 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3691 path
= strndup(rvalue
, n
);
3695 if (!path_startswith(path
, "/dev") &&
3696 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3697 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3701 if (streq("infinity", limit
)) {
3702 num
= CGROUP_LIMIT_MAX
;
3704 r
= parse_size(limit
, 1000, &num
);
3705 if (r
< 0 || num
<= 0) {
3706 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3711 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3712 if (path_equal(path
, t
->path
)) {
3719 CGroupIOLimitType ttype
;
3721 l
= new0(CGroupIODeviceLimit
, 1);
3727 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3728 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3730 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3733 l
->limits
[type
] = num
;
3738 int config_parse_blockio_weight(
3740 const char *filename
,
3742 const char *section
,
3743 unsigned section_line
,
3750 uint64_t *weight
= data
;
3757 r
= cg_blkio_weight_parse(rvalue
, weight
);
3759 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3766 int config_parse_blockio_device_weight(
3768 const char *filename
,
3770 const char *section
,
3771 unsigned section_line
,
3778 _cleanup_free_
char *path
= NULL
;
3779 CGroupBlockIODeviceWeight
*w
;
3780 CGroupContext
*c
= data
;
3790 if (isempty(rvalue
)) {
3791 while (c
->blockio_device_weights
)
3792 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3797 n
= strcspn(rvalue
, WHITESPACE
);
3798 weight
= rvalue
+ n
;
3799 weight
+= strspn(weight
, WHITESPACE
);
3801 if (isempty(weight
)) {
3802 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3806 path
= strndup(rvalue
, n
);
3810 if (!path_startswith(path
, "/dev") &&
3811 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3812 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3816 r
= cg_blkio_weight_parse(weight
, &u
);
3818 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3822 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3824 w
= new0(CGroupBlockIODeviceWeight
, 1);
3833 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3837 int config_parse_blockio_bandwidth(
3839 const char *filename
,
3841 const char *section
,
3842 unsigned section_line
,
3849 _cleanup_free_
char *path
= NULL
;
3850 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3851 CGroupContext
*c
= data
;
3852 const char *bandwidth
;
3862 read
= streq("BlockIOReadBandwidth", lvalue
);
3864 if (isempty(rvalue
)) {
3865 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3866 b
->rbps
= CGROUP_LIMIT_MAX
;
3867 b
->wbps
= CGROUP_LIMIT_MAX
;
3872 n
= strcspn(rvalue
, WHITESPACE
);
3873 bandwidth
= rvalue
+ n
;
3874 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3877 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3881 path
= strndup(rvalue
, n
);
3885 if (!path_startswith(path
, "/dev") &&
3886 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3887 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3891 r
= parse_size(bandwidth
, 1000, &bytes
);
3892 if (r
< 0 || bytes
<= 0) {
3893 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3897 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3898 if (path_equal(path
, t
->path
)) {
3905 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3911 b
->rbps
= CGROUP_LIMIT_MAX
;
3912 b
->wbps
= CGROUP_LIMIT_MAX
;
3914 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3925 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3927 int config_parse_job_mode_isolate(
3929 const char *filename
,
3931 const char *section
,
3932 unsigned section_line
,
3946 r
= parse_boolean(rvalue
);
3948 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3952 log_notice("%s is deprecated. Please use OnFailureJobMode= instead", lvalue
);
3954 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3958 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3960 int config_parse_exec_directories(
3962 const char *filename
,
3964 const char *section
,
3965 unsigned section_line
,
3982 if (isempty(rvalue
)) {
3983 /* Empty assignment resets the list */
3984 *rt
= strv_free(*rt
);
3988 for (p
= rvalue
;;) {
3989 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3991 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3995 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3996 "Invalid syntax, ignoring: %s", rvalue
);
4002 r
= unit_full_printf(u
, word
, &k
);
4004 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4005 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
4009 if (!path_is_normalized(k
) || path_is_absolute(k
)) {
4010 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
4011 "%s= path is not valid, ignoring assignment: %s", lvalue
, rvalue
);
4015 r
= strv_push(rt
, k
);
4022 int config_parse_set_status(
4024 const char *filename
,
4026 const char *section
,
4027 unsigned section_line
,
4035 const char *word
, *state
;
4037 ExitStatusSet
*status_set
= data
;
4044 /* Empty assignment resets the list */
4045 if (isempty(rvalue
)) {
4046 exit_status_set_free(status_set
);
4050 FOREACH_WORD(word
, l
, rvalue
, state
) {
4051 _cleanup_free_
char *temp
;
4055 temp
= strndup(word
, l
);
4059 r
= safe_atoi(temp
, &val
);
4061 val
= signal_from_string_try_harder(temp
);
4064 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
4067 set
= &status_set
->signal
;
4069 if (val
< 0 || val
> 255) {
4070 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
4073 set
= &status_set
->status
;
4076 r
= set_ensure_allocated(set
, NULL
);
4080 r
= set_put(*set
, INT_TO_PTR(val
));
4082 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
4086 if (!isempty(state
))
4087 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
4092 int config_parse_namespace_path_strv(
4094 const char *filename
,
4096 const char *section
,
4097 unsigned section_line
,
4114 if (isempty(rvalue
)) {
4115 /* Empty assignment resets the list */
4116 *sv
= strv_free(*sv
);
4122 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
4124 bool ignore_enoent
= false, shall_prefix
= false;
4126 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
4132 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
4136 if (!utf8_is_valid(word
)) {
4137 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
4142 if (startswith(w
, "-")) {
4143 ignore_enoent
= true;
4146 if (startswith(w
, "+")) {
4147 shall_prefix
= true;
4151 r
= unit_full_printf(u
, w
, &resolved
);
4153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
4157 if (!path_is_absolute(resolved
)) {
4158 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
4162 path_kill_slashes(resolved
);
4164 joined
= strjoin(ignore_enoent
? "-" : "",
4165 shall_prefix
? "+" : "",
4168 r
= strv_push(sv
, joined
);
4178 int config_parse_bind_paths(
4180 const char *filename
,
4182 const char *section
,
4183 unsigned section_line
,
4190 ExecContext
*c
= data
;
4200 if (isempty(rvalue
)) {
4201 /* Empty assignment resets the list */
4202 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
4203 c
->bind_mounts
= NULL
;
4204 c
->n_bind_mounts
= 0;
4210 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
4211 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
4212 char *s
= NULL
, *d
= NULL
;
4213 bool rbind
= true, ignore_enoent
= false;
4215 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4221 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4225 r
= unit_full_printf(u
, source
, &sresolved
);
4227 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4228 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
4234 ignore_enoent
= true;
4238 if (!utf8_is_valid(s
)) {
4239 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
4242 if (!path_is_absolute(s
)) {
4243 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
4247 path_kill_slashes(s
);
4249 /* Optionally, the destination is specified. */
4250 if (p
&& p
[-1] == ':') {
4251 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4255 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4259 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
4263 r
= unit_full_printf(u
, destination
, &dresolved
);
4265 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4266 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
4270 if (!utf8_is_valid(dresolved
)) {
4271 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
4274 if (!path_is_absolute(dresolved
)) {
4275 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
4279 d
= path_kill_slashes(dresolved
);
4281 /* Optionally, there's also a short option string specified */
4282 if (p
&& p
[-1] == ':') {
4283 _cleanup_free_
char *options
= NULL
;
4285 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
4289 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4293 if (isempty(options
) || streq(options
, "rbind"))
4295 else if (streq(options
, "norbind"))
4298 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4305 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4309 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4311 .ignore_enoent
= ignore_enoent
,
4320 int config_parse_no_new_privileges(
4322 const char *filename
,
4324 const char *section
,
4325 unsigned section_line
,
4332 ExecContext
*c
= data
;
4340 k
= parse_boolean(rvalue
);
4342 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4346 c
->no_new_privileges
= k
;
4351 int config_parse_protect_home(
4353 const char *filename
,
4355 const char *section
,
4356 unsigned section_line
,
4363 ExecContext
*c
= data
;
4371 /* Our enum shall be a superset of booleans, hence first try
4372 * to parse as boolean, and then as enum */
4374 h
= parse_protect_home_or_bool(rvalue
);
4376 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4380 c
->protect_home
= h
;
4385 int config_parse_protect_system(
4387 const char *filename
,
4389 const char *section
,
4390 unsigned section_line
,
4397 ExecContext
*c
= data
;
4405 /* Our enum shall be a superset of booleans, hence first try
4406 * to parse as boolean, and then as enum */
4408 s
= parse_protect_system_or_bool(rvalue
);
4410 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4414 c
->protect_system
= s
;
4419 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode
, exec_keyring_mode
, ExecKeyringMode
, "Failed to parse keyring mode");
4421 int config_parse_job_timeout_sec(
4423 const char *filename
,
4425 const char *section
,
4426 unsigned section_line
,
4442 r
= parse_sec_fix_0(rvalue
, &usec
);
4444 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue
);
4448 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4449 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4452 if (!u
->job_running_timeout_set
)
4453 u
->job_running_timeout
= usec
;
4455 u
->job_timeout
= usec
;
4460 int config_parse_job_running_timeout_sec(
4462 const char *filename
,
4464 const char *section
,
4465 unsigned section_line
,
4481 r
= parse_sec_fix_0(rvalue
, &usec
);
4483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue
);
4487 u
->job_running_timeout
= usec
;
4488 u
->job_running_timeout_set
= true;
4493 #define FOLLOW_MAX 8
4495 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4506 /* This will update the filename pointer if the loaded file is
4507 * reached by a symlink. The old string will be freed. */
4510 char *target
, *name
;
4512 if (c
++ >= FOLLOW_MAX
)
4515 path_kill_slashes(*filename
);
4517 /* Add the file name we are currently looking at to
4518 * the names of this unit, but only if it is a valid
4520 name
= basename(*filename
);
4521 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4523 id
= set_get(names
, name
);
4529 r
= set_consume(names
, id
);
4535 /* Try to open the file name, but don't if its a symlink */
4536 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4543 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4544 r
= readlink_and_make_absolute(*filename
, &target
);
4552 f
= fdopen(fd
, "re");
4564 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4572 /* Let's try to add in all symlink names we found */
4573 while ((k
= set_steal_first(names
))) {
4575 /* First try to merge in the other name into our
4577 r
= unit_merge_by_name(*u
, k
);
4581 /* Hmm, we couldn't merge the other unit into
4582 * ours? Then let's try it the other way
4585 /* If the symlink name we are looking at is unit template, then
4586 we must search for instance of this template */
4587 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4588 _cleanup_free_
char *instance
= NULL
;
4590 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4594 other
= manager_get_unit((*u
)->manager
, instance
);
4596 other
= manager_get_unit((*u
)->manager
, k
);
4601 r
= unit_merge(other
, *u
);
4604 return merge_by_names(u
, names
, NULL
);
4612 unit_choose_id(*u
, id
);
4620 static int load_from_path(Unit
*u
, const char *path
) {
4621 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4622 _cleanup_fclose_
FILE *f
= NULL
;
4623 _cleanup_free_
char *filename
= NULL
;
4632 symlink_names
= set_new(&string_hash_ops
);
4636 if (path_is_absolute(path
)) {
4638 filename
= strdup(path
);
4642 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4644 filename
= mfree(filename
);
4652 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4654 /* Instead of opening the path right away, we manually
4655 * follow all symlinks and add their name to our unit
4656 * name set while doing so */
4657 filename
= path_make_absolute(path
, *p
);
4661 if (u
->manager
->unit_path_cache
&&
4662 !set_get(u
->manager
->unit_path_cache
, filename
))
4665 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4668 filename
= mfree(filename
);
4670 /* ENOENT means that the file is missing or is a dangling symlink.
4671 * ENOTDIR means that one of paths we expect to be is a directory
4672 * is not a directory, we should just ignore that.
4673 * EACCES means that the directory or file permissions are wrong.
4676 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4677 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4680 /* Empty the symlink names for the next run */
4681 set_clear_free(symlink_names
);
4686 /* Hmm, no suitable file found? */
4689 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4690 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4695 r
= merge_by_names(&merged
, symlink_names
, id
);
4700 u
->load_state
= UNIT_MERGED
;
4704 if (fstat(fileno(f
), &st
) < 0)
4707 if (null_or_empty(&st
)) {
4708 u
->load_state
= UNIT_MASKED
;
4709 u
->fragment_mtime
= 0;
4711 u
->load_state
= UNIT_LOADED
;
4712 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4714 /* Now, parse the file contents */
4715 r
= config_parse(u
->id
, filename
, f
,
4716 UNIT_VTABLE(u
)->sections
,
4717 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4718 CONFIG_PARSE_ALLOW_INCLUDE
, u
);
4723 free(u
->fragment_path
);
4724 u
->fragment_path
= filename
;
4727 if (u
->source_path
) {
4728 if (stat(u
->source_path
, &st
) >= 0)
4729 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4731 u
->source_mtime
= 0;
4737 int unit_load_fragment(Unit
*u
) {
4743 assert(u
->load_state
== UNIT_STUB
);
4747 u
->load_state
= UNIT_LOADED
;
4751 /* First, try to find the unit under its id. We always look
4752 * for unit files in the default directories, to make it easy
4753 * to override things by placing things in /etc/systemd/system */
4754 r
= load_from_path(u
, u
->id
);
4758 /* Try to find an alias we can load this with */
4759 if (u
->load_state
== UNIT_STUB
) {
4760 SET_FOREACH(t
, u
->names
, i
) {
4765 r
= load_from_path(u
, t
);
4769 if (u
->load_state
!= UNIT_STUB
)
4774 /* And now, try looking for it under the suggested (originally linked) path */
4775 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4777 r
= load_from_path(u
, u
->fragment_path
);
4781 if (u
->load_state
== UNIT_STUB
)
4782 /* Hmm, this didn't work? Then let's get rid
4783 * of the fragment path stored for us, so that
4784 * we don't point to an invalid location. */
4785 u
->fragment_path
= mfree(u
->fragment_path
);
4788 /* Look for a template */
4789 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4790 _cleanup_free_
char *k
= NULL
;
4792 r
= unit_name_template(u
->id
, &k
);
4796 r
= load_from_path(u
, k
);
4799 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4803 if (u
->load_state
== UNIT_STUB
) {
4804 SET_FOREACH(t
, u
->names
, i
) {
4805 _cleanup_free_
char *z
= NULL
;
4810 r
= unit_name_template(t
, &z
);
4814 r
= load_from_path(u
, z
);
4818 if (u
->load_state
!= UNIT_STUB
)
4827 void unit_dump_config_items(FILE *f
) {
4828 static const struct {
4829 const ConfigParserCallback callback
;
4832 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4833 { config_parse_warn_compat
, "NOTSUPPORTED" },
4835 { config_parse_int
, "INTEGER" },
4836 { config_parse_unsigned
, "UNSIGNED" },
4837 { config_parse_iec_size
, "SIZE" },
4838 { config_parse_iec_uint64
, "SIZE" },
4839 { config_parse_si_size
, "SIZE" },
4840 { config_parse_bool
, "BOOLEAN" },
4841 { config_parse_string
, "STRING" },
4842 { config_parse_path
, "PATH" },
4843 { config_parse_unit_path_printf
, "PATH" },
4844 { config_parse_strv
, "STRING [...]" },
4845 { config_parse_exec_nice
, "NICE" },
4846 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4847 { config_parse_exec_io_class
, "IOCLASS" },
4848 { config_parse_exec_io_priority
, "IOPRIORITY" },
4849 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4850 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4851 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4852 { config_parse_mode
, "MODE" },
4853 { config_parse_unit_env_file
, "FILE" },
4854 { config_parse_exec_output
, "OUTPUT" },
4855 { config_parse_exec_input
, "INPUT" },
4856 { config_parse_log_facility
, "FACILITY" },
4857 { config_parse_log_level
, "LEVEL" },
4858 { config_parse_exec_secure_bits
, "SECUREBITS" },
4859 { config_parse_capability_set
, "BOUNDINGSET" },
4860 { config_parse_limit
, "LIMIT" },
4861 { config_parse_unit_deps
, "UNIT [...]" },
4862 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4863 { config_parse_service_type
, "SERVICETYPE" },
4864 { config_parse_service_restart
, "SERVICERESTART" },
4865 #if HAVE_SYSV_COMPAT
4866 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4868 { config_parse_kill_mode
, "KILLMODE" },
4869 { config_parse_signal
, "SIGNAL" },
4870 { config_parse_socket_listen
, "SOCKET [...]" },
4871 { config_parse_socket_bind
, "SOCKETBIND" },
4872 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4873 { config_parse_sec
, "SECONDS" },
4874 { config_parse_nsec
, "NANOSECONDS" },
4875 { config_parse_namespace_path_strv
, "PATH [...]" },
4876 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4877 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4878 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4879 { config_parse_unit_string_printf
, "STRING" },
4880 { config_parse_trigger_unit
, "UNIT" },
4881 { config_parse_timer
, "TIMER" },
4882 { config_parse_path_spec
, "PATH" },
4883 { config_parse_notify_access
, "ACCESS" },
4884 { config_parse_ip_tos
, "TOS" },
4885 { config_parse_unit_condition_path
, "CONDITION" },
4886 { config_parse_unit_condition_string
, "CONDITION" },
4887 { config_parse_unit_condition_null
, "CONDITION" },
4888 { config_parse_unit_slice
, "SLICE" },
4889 { config_parse_documentation
, "URL" },
4890 { config_parse_service_timeout
, "SECONDS" },
4891 { config_parse_emergency_action
, "ACTION" },
4892 { config_parse_set_status
, "STATUS" },
4893 { config_parse_service_sockets
, "SOCKETS" },
4894 { config_parse_environ
, "ENVIRON" },
4896 { config_parse_syscall_filter
, "SYSCALLS" },
4897 { config_parse_syscall_archs
, "ARCHS" },
4898 { config_parse_syscall_errno
, "ERRNO" },
4899 { config_parse_address_families
, "FAMILIES" },
4900 { config_parse_restrict_namespaces
, "NAMESPACES" },
4902 { config_parse_cpu_shares
, "SHARES" },
4903 { config_parse_cpu_weight
, "WEIGHT" },
4904 { config_parse_memory_limit
, "LIMIT" },
4905 { config_parse_device_allow
, "DEVICE" },
4906 { config_parse_device_policy
, "POLICY" },
4907 { config_parse_io_limit
, "LIMIT" },
4908 { config_parse_io_weight
, "WEIGHT" },
4909 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4910 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4911 { config_parse_blockio_weight
, "WEIGHT" },
4912 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4913 { config_parse_long
, "LONG" },
4914 { config_parse_socket_service
, "SERVICE" },
4916 { config_parse_exec_selinux_context
, "LABEL" },
4918 { config_parse_job_mode
, "MODE" },
4919 { config_parse_job_mode_isolate
, "BOOLEAN" },
4920 { config_parse_personality
, "PERSONALITY" },
4923 const char *prev
= NULL
;
4928 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4929 const char *rvalue
= "OTHER", *lvalue
;
4933 const ConfigPerfItem
*p
;
4935 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4937 dot
= strchr(i
, '.');
4938 lvalue
= dot
? dot
+ 1 : i
;
4942 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4946 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4949 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4950 if (p
->parse
== table
[j
].callback
) {
4951 rvalue
= table
[j
].rvalue
;
4955 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);