2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
5 Copyright 2012 Holger Hans Peter Freyther
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/oom.h>
30 #include <sys/resource.h>
34 #include "alloc-util.h"
35 #include "bus-error.h"
36 #include "bus-internal.h"
39 #include "capability-util.h"
41 #include "conf-parser.h"
42 #include "cpu-set-util.h"
44 #include "errno-list.h"
49 #include "load-fragment.h"
52 #include "mount-util.h"
53 #include "parse-util.h"
54 #include "path-util.h"
55 #include "process-util.h"
56 #include "rlimit-util.h"
58 #include "seccomp-util.h"
60 #include "securebits.h"
61 #include "securebits-util.h"
62 #include "signal-util.h"
63 #include "stat-util.h"
64 #include "string-util.h"
66 #include "unit-name.h"
67 #include "unit-printf.h"
69 #include "user-util.h"
73 int config_parse_warn_compat(
78 unsigned section_line
,
84 Disabled reason
= ltype
;
87 case DISABLED_CONFIGURATION
:
88 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
89 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
92 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
93 "Support for option %s= has been removed and it is ignored", lvalue
);
95 case DISABLED_EXPERIMENTAL
:
96 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
97 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
104 int config_parse_unit_deps(
106 const char *filename
,
109 unsigned section_line
,
116 UnitDependency d
= ltype
;
126 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
129 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
135 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
139 r
= unit_name_printf(u
, word
, &k
);
141 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
145 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
147 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
153 int config_parse_obsolete_unit_deps(
155 const char *filename
,
158 unsigned section_line
,
165 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
166 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
168 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
171 int config_parse_unit_string_printf(
173 const char *filename
,
176 unsigned section_line
,
183 _cleanup_free_
char *k
= NULL
;
192 r
= unit_full_printf(u
, rvalue
, &k
);
194 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
198 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
201 int config_parse_unit_strv_printf(
203 const char *filename
,
206 unsigned section_line
,
214 _cleanup_free_
char *k
= NULL
;
222 r
= unit_full_printf(u
, rvalue
, &k
);
224 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
228 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
231 int config_parse_unit_path_printf(
233 const char *filename
,
236 unsigned section_line
,
243 _cleanup_free_
char *k
= NULL
;
253 r
= unit_full_printf(u
, rvalue
, &k
);
255 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
256 "Failed to resolve unit specifiers on %s%s: %m",
257 fatal
? "" : ", ignoring", rvalue
);
258 return fatal
? -ENOEXEC
: 0;
261 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
264 int config_parse_unit_path_strv_printf(
266 const char *filename
,
269 unsigned section_line
,
286 if (isempty(rvalue
)) {
292 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
294 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
300 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
301 "Invalid syntax, ignoring: %s", rvalue
);
305 r
= unit_full_printf(u
, word
, &k
);
307 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
308 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
312 if (!utf8_is_valid(k
)) {
313 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
317 if (!path_is_absolute(k
)) {
318 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
319 "Symlink path is not absolute: %s", k
);
323 path_kill_slashes(k
);
332 int config_parse_socket_listen(const char *unit
,
333 const char *filename
,
336 unsigned section_line
,
343 _cleanup_free_ SocketPort
*p
= NULL
;
355 if (isempty(rvalue
)) {
356 /* An empty assignment removes all ports */
357 socket_free_ports(s
);
361 p
= new0(SocketPort
, 1);
365 if (ltype
!= SOCKET_SOCKET
) {
368 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
370 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
374 path_kill_slashes(p
->path
);
376 } else if (streq(lvalue
, "ListenNetlink")) {
377 _cleanup_free_
char *k
= NULL
;
379 p
->type
= SOCKET_SOCKET
;
380 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
382 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
386 r
= socket_address_parse_netlink(&p
->address
, k
);
388 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
393 _cleanup_free_
char *k
= NULL
;
395 p
->type
= SOCKET_SOCKET
;
396 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
398 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
402 r
= socket_address_parse_and_warn(&p
->address
, k
);
404 if (r
!= -EAFNOSUPPORT
)
405 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
410 if (streq(lvalue
, "ListenStream"))
411 p
->address
.type
= SOCK_STREAM
;
412 else if (streq(lvalue
, "ListenDatagram"))
413 p
->address
.type
= SOCK_DGRAM
;
415 assert(streq(lvalue
, "ListenSequentialPacket"));
416 p
->address
.type
= SOCK_SEQPACKET
;
419 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
420 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
426 p
->auxiliary_fds
= NULL
;
427 p
->n_auxiliary_fds
= 0;
431 LIST_FIND_TAIL(port
, s
->ports
, tail
);
432 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
434 LIST_PREPEND(port
, s
->ports
, p
);
440 int config_parse_socket_protocol(const char *unit
,
441 const char *filename
,
444 unsigned section_line
,
459 if (streq(rvalue
, "udplite"))
460 s
->socket_protocol
= IPPROTO_UDPLITE
;
461 else if (streq(rvalue
, "sctp"))
462 s
->socket_protocol
= IPPROTO_SCTP
;
464 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
471 int config_parse_socket_bind(const char *unit
,
472 const char *filename
,
475 unsigned section_line
,
483 SocketAddressBindIPv6Only b
;
492 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
496 r
= parse_boolean(rvalue
);
498 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
502 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
504 s
->bind_ipv6_only
= b
;
509 int config_parse_exec_nice(
511 const char *filename
,
514 unsigned section_line
,
521 ExecContext
*c
= data
;
529 r
= parse_nice(rvalue
, &priority
);
532 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
534 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
545 int config_parse_exec_oom_score_adjust(const char* unit
,
546 const char *filename
,
549 unsigned section_line
,
556 ExecContext
*c
= data
;
564 r
= safe_atoi(rvalue
, &oa
);
566 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
570 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
571 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
575 c
->oom_score_adjust
= oa
;
576 c
->oom_score_adjust_set
= true;
581 int config_parse_exec(
583 const char *filename
,
586 unsigned section_line
,
593 ExecCommand
**e
= data
;
605 rvalue
+= strspn(rvalue
, WHITESPACE
);
607 if (isempty(rvalue
)) {
608 /* An empty assignment resets the list */
609 *e
= exec_command_free_list(*e
);
615 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
616 ExecCommandFlags flags
= 0;
617 bool ignore
= false, separate_argv0
= false;
618 _cleanup_free_ ExecCommand
*nce
= NULL
;
619 _cleanup_strv_free_
char **n
= NULL
;
620 size_t nlen
= 0, nbufsize
= 0;
625 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
631 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
632 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
633 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
634 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
635 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
636 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
637 * other sandboxing, with some special exceptions for changing UID.
639 * The idea is that '!!' may be used to write services that can take benefit of systemd's
640 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
641 * privilege dropping within the daemon if the kernel does not offer that. */
643 if (*f
== '-' && !(flags
& EXEC_COMMAND_IGNORE_FAILURE
)) {
644 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
646 } else if (*f
== '@' && !separate_argv0
)
647 separate_argv0
= true;
648 else if (*f
== '+' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
649 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
650 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
651 flags
|= EXEC_COMMAND_NO_SETUID
;
652 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
653 flags
&= ~EXEC_COMMAND_NO_SETUID
;
654 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
660 r
= unit_full_printf(u
, f
, &path
);
662 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
663 "Failed to resolve unit specifiers on %s%s: %m",
664 f
, ignore
? ", ignoring" : "");
665 return ignore
? 0 : -ENOEXEC
;
669 /* First word is either "-" or "@" with no command. */
670 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
671 "Empty path in command line%s: \"%s\"",
672 ignore
? ", ignoring" : "", rvalue
);
673 return ignore
? 0 : -ENOEXEC
;
675 if (!string_is_safe(path
)) {
676 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
677 "Executable path contains special characters%s: %s",
678 ignore
? ", ignoring" : "", rvalue
);
679 return ignore
? 0 : -ENOEXEC
;
681 if (!path_is_absolute(path
)) {
682 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
683 "Executable path is not absolute%s: %s",
684 ignore
? ", ignoring" : "", rvalue
);
685 return ignore
? 0 : -ENOEXEC
;
687 if (endswith(path
, "/")) {
688 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
689 "Executable path specifies a directory%s: %s",
690 ignore
? ", ignoring" : "", rvalue
);
691 return ignore
? 0 : -ENOEXEC
;
694 if (!separate_argv0
) {
697 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
707 path_kill_slashes(path
);
709 while (!isempty(p
)) {
710 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
712 /* Check explicitly for an unquoted semicolon as
713 * command separator token. */
714 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
716 p
+= strspn(p
, WHITESPACE
);
721 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
722 * extract_first_word() would return the same for all of those. */
723 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
727 p
+= strspn(p
, WHITESPACE
);
729 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
740 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
744 return ignore
? 0 : -ENOEXEC
;
746 r
= unit_full_printf(u
, word
, &resolved
);
748 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
749 "Failed to resolve unit specifiers on %s%s: %m",
750 word
, ignore
? ", ignoring" : "");
751 return ignore
? 0 : -ENOEXEC
;
754 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
756 n
[nlen
++] = resolved
;
762 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
763 "Empty executable name or zeroeth argument%s: %s",
764 ignore
? ", ignoring" : "", rvalue
);
765 return ignore
? 0 : -ENOEXEC
;
768 nce
= new0(ExecCommand
, 1);
776 exec_command_append_list(e
, nce
);
778 /* Do not _cleanup_free_ these. */
789 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
790 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
792 int config_parse_socket_bindtodevice(
794 const char *filename
,
797 unsigned section_line
,
812 if (rvalue
[0] && !streq(rvalue
, "*")) {
813 if (!ifname_valid(rvalue
)) {
814 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
824 free(s
->bind_to_device
);
825 s
->bind_to_device
= n
;
830 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
831 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
833 int config_parse_exec_input(const char *unit
,
834 const char *filename
,
837 unsigned section_line
,
843 ExecContext
*c
= data
;
852 name
= startswith(rvalue
, "fd:");
854 /* Strip prefix and validate fd name */
855 if (!fdname_is_valid(name
)) {
856 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
859 c
->std_input
= EXEC_INPUT_NAMED_FD
;
860 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
865 ExecInput ei
= exec_input_from_string(rvalue
);
866 if (ei
== _EXEC_INPUT_INVALID
)
867 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
874 int config_parse_exec_output(const char *unit
,
875 const char *filename
,
878 unsigned section_line
,
884 ExecContext
*c
= data
;
895 name
= startswith(rvalue
, "fd:");
897 /* Strip prefix and validate fd name */
898 if (!fdname_is_valid(name
)) {
899 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
902 eo
= EXEC_OUTPUT_NAMED_FD
;
904 eo
= exec_output_from_string(rvalue
);
905 if (eo
== _EXEC_OUTPUT_INVALID
) {
906 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
911 if (streq(lvalue
, "StandardOutput")) {
913 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
917 } else if (streq(lvalue
, "StandardError")) {
919 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
924 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
929 int config_parse_exec_io_class(const char *unit
,
930 const char *filename
,
933 unsigned section_line
,
940 ExecContext
*c
= data
;
948 x
= ioprio_class_from_string(rvalue
);
950 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
954 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
955 c
->ioprio_set
= true;
960 int config_parse_exec_io_priority(const char *unit
,
961 const char *filename
,
964 unsigned section_line
,
971 ExecContext
*c
= data
;
979 r
= ioprio_parse_priority(rvalue
, &i
);
981 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
985 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
986 c
->ioprio_set
= true;
991 int config_parse_exec_cpu_sched_policy(const char *unit
,
992 const char *filename
,
995 unsigned section_line
,
1003 ExecContext
*c
= data
;
1011 x
= sched_policy_from_string(rvalue
);
1013 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1017 c
->cpu_sched_policy
= x
;
1018 /* Moving to or from real-time policy? We need to adjust the priority */
1019 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1020 c
->cpu_sched_set
= true;
1025 int config_parse_exec_cpu_sched_prio(const char *unit
,
1026 const char *filename
,
1028 const char *section
,
1029 unsigned section_line
,
1036 ExecContext
*c
= data
;
1044 r
= safe_atoi(rvalue
, &i
);
1046 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1050 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1051 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1052 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1054 if (i
< min
|| i
> max
) {
1055 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1059 c
->cpu_sched_priority
= i
;
1060 c
->cpu_sched_set
= true;
1065 int config_parse_exec_cpu_affinity(const char *unit
,
1066 const char *filename
,
1068 const char *section
,
1069 unsigned section_line
,
1076 ExecContext
*c
= data
;
1077 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1085 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1090 CPU_FREE(c
->cpuset
);
1093 /* An empty assignment resets the CPU list */
1099 c
->cpuset_ncpus
= ncpus
;
1104 int config_parse_exec_secure_bits(const char *unit
,
1105 const char *filename
,
1107 const char *section
,
1108 unsigned section_line
,
1115 ExecContext
*c
= data
;
1123 if (isempty(rvalue
)) {
1124 /* An empty assignment resets the field */
1129 r
= secure_bits_from_string(rvalue
);
1133 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1134 "Invalid syntax, ignoring: %s", rvalue
);
1143 int config_parse_capability_set(
1145 const char *filename
,
1147 const char *section
,
1148 unsigned section_line
,
1155 uint64_t *capability_set
= data
;
1156 uint64_t sum
= 0, initial
= 0;
1157 bool invert
= false;
1165 if (rvalue
[0] == '~') {
1170 if (streq(lvalue
, "CapabilityBoundingSet"))
1171 initial
= CAP_ALL
; /* initialized to all bits on */
1172 /* else "AmbientCapabilities" initialized to all bits off */
1174 r
= capability_set_from_string(rvalue
, &sum
);
1178 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1182 if (sum
== 0 || *capability_set
== initial
)
1183 /* "", "~" or uninitialized data -> replace */
1184 *capability_set
= invert
? ~sum
: sum
;
1186 /* previous data -> merge */
1188 *capability_set
&= ~sum
;
1190 *capability_set
|= sum
;
1196 int config_parse_limit(
1198 const char *filename
,
1200 const char *section
,
1201 unsigned section_line
,
1208 struct rlimit
**rl
= data
, d
= {};
1216 r
= rlimit_parse(ltype
, rvalue
, &d
);
1218 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1222 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1229 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1237 #if HAVE_SYSV_COMPAT
1238 int config_parse_sysv_priority(const char *unit
,
1239 const char *filename
,
1241 const char *section
,
1242 unsigned section_line
,
1249 int *priority
= data
;
1257 r
= safe_atoi(rvalue
, &i
);
1258 if (r
< 0 || i
< 0) {
1259 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1263 *priority
= (int) i
;
1268 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1269 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1271 int config_parse_exec_mount_flags(
1273 const char *filename
,
1275 const char *section
,
1276 unsigned section_line
,
1284 ExecContext
*c
= data
;
1292 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1294 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1299 int config_parse_exec_selinux_context(
1301 const char *filename
,
1303 const char *section
,
1304 unsigned section_line
,
1311 ExecContext
*c
= data
;
1322 if (isempty(rvalue
)) {
1323 c
->selinux_context
= mfree(c
->selinux_context
);
1324 c
->selinux_context_ignore
= false;
1328 if (rvalue
[0] == '-') {
1334 r
= unit_full_printf(u
, rvalue
, &k
);
1336 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1337 "Failed to resolve specifiers%s: %m",
1338 ignore
? ", ignoring" : "");
1339 return ignore
? 0 : -ENOEXEC
;
1342 free(c
->selinux_context
);
1343 c
->selinux_context
= k
;
1344 c
->selinux_context_ignore
= ignore
;
1349 int config_parse_exec_apparmor_profile(
1351 const char *filename
,
1353 const char *section
,
1354 unsigned section_line
,
1361 ExecContext
*c
= data
;
1372 if (isempty(rvalue
)) {
1373 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1374 c
->apparmor_profile_ignore
= false;
1378 if (rvalue
[0] == '-') {
1384 r
= unit_full_printf(u
, rvalue
, &k
);
1386 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1387 "Failed to resolve specifiers%s: %m",
1388 ignore
? ", ignoring" : "");
1389 return ignore
? 0 : -ENOEXEC
;
1392 free(c
->apparmor_profile
);
1393 c
->apparmor_profile
= k
;
1394 c
->apparmor_profile_ignore
= ignore
;
1399 int config_parse_exec_smack_process_label(
1401 const char *filename
,
1403 const char *section
,
1404 unsigned section_line
,
1411 ExecContext
*c
= data
;
1422 if (isempty(rvalue
)) {
1423 c
->smack_process_label
= mfree(c
->smack_process_label
);
1424 c
->smack_process_label_ignore
= false;
1428 if (rvalue
[0] == '-') {
1434 r
= unit_full_printf(u
, rvalue
, &k
);
1436 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1437 "Failed to resolve specifiers%s: %m",
1438 ignore
? ", ignoring" : "");
1439 return ignore
? 0 : -ENOEXEC
;
1442 free(c
->smack_process_label
);
1443 c
->smack_process_label
= k
;
1444 c
->smack_process_label_ignore
= ignore
;
1449 int config_parse_timer(const char *unit
,
1450 const char *filename
,
1452 const char *section
,
1453 unsigned section_line
,
1464 CalendarSpec
*c
= NULL
;
1466 _cleanup_free_
char *k
= NULL
;
1474 if (isempty(rvalue
)) {
1475 /* Empty assignment resets list */
1476 timer_free_values(t
);
1480 b
= timer_base_from_string(lvalue
);
1482 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1486 r
= unit_full_printf(u
, rvalue
, &k
);
1488 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1492 if (b
== TIMER_CALENDAR
) {
1493 if (calendar_spec_from_string(k
, &c
) < 0) {
1494 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1498 if (parse_sec(k
, &usec
) < 0) {
1499 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1504 v
= new0(TimerValue
, 1);
1506 calendar_spec_free(c
);
1512 v
->calendar_spec
= c
;
1514 LIST_PREPEND(value
, t
->values
, v
);
1519 int config_parse_trigger_unit(
1521 const char *filename
,
1523 const char *section
,
1524 unsigned section_line
,
1531 _cleanup_free_
char *p
= NULL
;
1541 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1542 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1546 r
= unit_name_printf(u
, rvalue
, &p
);
1548 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1552 type
= unit_name_to_type(p
);
1554 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1558 if (type
== u
->type
) {
1559 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1563 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1565 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1572 int config_parse_path_spec(const char *unit
,
1573 const char *filename
,
1575 const char *section
,
1576 unsigned section_line
,
1586 _cleanup_free_
char *k
= NULL
;
1594 if (isempty(rvalue
)) {
1595 /* Empty assignment clears list */
1600 b
= path_type_from_string(lvalue
);
1602 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1606 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1608 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1612 if (!path_is_absolute(k
)) {
1613 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1617 s
= new0(PathSpec
, 1);
1622 s
->path
= path_kill_slashes(k
);
1627 LIST_PREPEND(spec
, p
->specs
, s
);
1632 int config_parse_socket_service(
1634 const char *filename
,
1636 const char *section
,
1637 unsigned section_line
,
1644 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1645 _cleanup_free_
char *p
= NULL
;
1655 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1657 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1661 if (!endswith(p
, ".service")) {
1662 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1666 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1668 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1672 unit_ref_set(&s
->service
, x
);
1677 int config_parse_fdname(
1679 const char *filename
,
1681 const char *section
,
1682 unsigned section_line
,
1689 _cleanup_free_
char *p
= NULL
;
1698 if (isempty(rvalue
)) {
1699 s
->fdname
= mfree(s
->fdname
);
1703 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1705 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1709 if (!fdname_is_valid(p
)) {
1710 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1714 return free_and_replace(s
->fdname
, p
);
1717 int config_parse_service_sockets(
1719 const char *filename
,
1721 const char *section
,
1722 unsigned section_line
,
1740 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1742 r
= extract_first_word(&p
, &word
, NULL
, 0);
1748 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1752 r
= unit_name_printf(UNIT(s
), word
, &k
);
1754 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1758 if (!endswith(k
, ".socket")) {
1759 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1763 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1765 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1767 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1769 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1775 int config_parse_bus_name(
1777 const char *filename
,
1779 const char *section
,
1780 unsigned section_line
,
1787 _cleanup_free_
char *k
= NULL
;
1796 r
= unit_full_printf(u
, rvalue
, &k
);
1798 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1802 if (!service_name_is_valid(k
)) {
1803 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1807 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1810 int config_parse_service_timeout(
1812 const char *filename
,
1814 const char *section
,
1815 unsigned section_line
,
1822 Service
*s
= userdata
;
1831 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1833 r
= parse_sec(rvalue
, &usec
);
1835 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1839 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1840 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1841 * all other timeouts. */
1843 usec
= USEC_INFINITY
;
1845 if (!streq(lvalue
, "TimeoutStopSec")) {
1846 s
->start_timeout_defined
= true;
1847 s
->timeout_start_usec
= usec
;
1850 if (!streq(lvalue
, "TimeoutStartSec"))
1851 s
->timeout_stop_usec
= usec
;
1856 int config_parse_sec_fix_0(
1858 const char *filename
,
1860 const char *section
,
1861 unsigned section_line
,
1868 usec_t
*usec
= data
;
1876 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1877 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1880 r
= parse_sec_fix_0(rvalue
, usec
);
1882 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1889 int config_parse_user_group(
1891 const char *filename
,
1893 const char *section
,
1894 unsigned section_line
,
1901 char **user
= data
, *n
;
1910 if (isempty(rvalue
))
1913 _cleanup_free_
char *k
= NULL
;
1915 r
= unit_full_printf(u
, rvalue
, &k
);
1917 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
1921 if (!valid_user_group_name_or_id(k
)) {
1922 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1936 int config_parse_user_group_strv(
1938 const char *filename
,
1940 const char *section
,
1941 unsigned section_line
,
1948 char ***users
= data
;
1958 if (isempty(rvalue
)) {
1959 *users
= strv_free(*users
);
1965 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1967 r
= extract_first_word(&p
, &word
, NULL
, 0);
1973 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
1977 r
= unit_full_printf(u
, word
, &k
);
1979 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
1983 if (!valid_user_group_name_or_id(k
)) {
1984 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1988 r
= strv_push(users
, k
);
1998 int config_parse_working_directory(
2000 const char *filename
,
2002 const char *section
,
2003 unsigned section_line
,
2010 ExecContext
*c
= data
;
2021 if (rvalue
[0] == '-') {
2027 if (streq(rvalue
, "~")) {
2028 c
->working_directory_home
= true;
2029 c
->working_directory
= mfree(c
->working_directory
);
2031 _cleanup_free_
char *k
= NULL
;
2033 r
= unit_full_printf(u
, rvalue
, &k
);
2035 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2036 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2037 rvalue
, missing_ok
? ", ignoring" : "");
2038 return missing_ok
? 0 : -ENOEXEC
;
2041 path_kill_slashes(k
);
2043 if (!utf8_is_valid(k
)) {
2044 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2045 return missing_ok
? 0 : -ENOEXEC
;
2048 if (!path_is_absolute(k
)) {
2049 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2050 "Working directory path '%s' is not absolute%s.",
2051 rvalue
, missing_ok
? ", ignoring" : "");
2052 return missing_ok
? 0 : -ENOEXEC
;
2055 c
->working_directory_home
= false;
2056 free_and_replace(c
->working_directory
, k
);
2059 c
->working_directory_missing_ok
= missing_ok
;
2063 int config_parse_unit_env_file(const char *unit
,
2064 const char *filename
,
2066 const char *section
,
2067 unsigned section_line
,
2076 _cleanup_free_
char *n
= NULL
;
2084 if (isempty(rvalue
)) {
2085 /* Empty assignment frees the list */
2086 *env
= strv_free(*env
);
2090 r
= unit_full_printf(u
, rvalue
, &n
);
2092 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2096 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2097 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2101 r
= strv_extend(env
, n
);
2108 int config_parse_environ(
2110 const char *filename
,
2112 const char *section
,
2113 unsigned section_line
,
2130 if (isempty(rvalue
)) {
2131 /* Empty assignment resets the list */
2132 *env
= strv_free(*env
);
2136 for (p
= rvalue
;; ) {
2137 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2139 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2145 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2146 "Invalid syntax, ignoring: %s", rvalue
);
2151 r
= unit_full_printf(u
, word
, &k
);
2153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2154 "Failed to resolve specifiers, ignoring: %s", word
);
2162 if (!env_assignment_is_valid(k
)) {
2163 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2164 "Invalid environment assignment, ignoring: %s", k
);
2168 r
= strv_env_replace(env
, k
);
2176 int config_parse_pass_environ(
2178 const char *filename
,
2180 const char *section
,
2181 unsigned section_line
,
2188 const char *whole_rvalue
= rvalue
;
2189 _cleanup_strv_free_
char **n
= NULL
;
2190 size_t nlen
= 0, nbufsize
= 0;
2191 char*** passenv
= data
;
2200 if (isempty(rvalue
)) {
2201 /* Empty assignment resets the list */
2202 *passenv
= strv_free(*passenv
);
2207 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2209 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2215 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2216 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2221 r
= unit_full_printf(u
, word
, &k
);
2223 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2224 "Failed to resolve specifiers, ignoring: %s", word
);
2232 if (!env_name_is_valid(k
)) {
2233 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2234 "Invalid environment name for %s, ignoring: %s", lvalue
, k
);
2238 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2247 r
= strv_extend_strv(passenv
, n
, true);
2255 int config_parse_unset_environ(
2257 const char *filename
,
2259 const char *section
,
2260 unsigned section_line
,
2267 _cleanup_strv_free_
char **n
= NULL
;
2268 const char *whole_rvalue
= rvalue
;
2269 size_t nlen
= 0, nbufsize
= 0;
2270 char*** unsetenv
= data
;
2279 if (isempty(rvalue
)) {
2280 /* Empty assignment resets the list */
2281 *unsetenv
= strv_free(*unsetenv
);
2286 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2288 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2294 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2295 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2300 r
= unit_full_printf(u
, word
, &k
);
2302 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2303 "Failed to resolve specifiers, ignoring: %s", word
);
2311 if (!env_assignment_is_valid(k
) && !env_name_is_valid(k
)) {
2312 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2313 "Invalid environment name or assignment %s, ignoring: %s", lvalue
, k
);
2317 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2326 r
= strv_extend_strv(unsetenv
, n
, true);
2334 int config_parse_ip_tos(const char *unit
,
2335 const char *filename
,
2337 const char *section
,
2338 unsigned section_line
,
2345 int *ip_tos
= data
, x
;
2352 x
= ip_tos_from_string(rvalue
);
2354 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2362 int config_parse_unit_condition_path(
2364 const char *filename
,
2366 const char *section
,
2367 unsigned section_line
,
2374 _cleanup_free_
char *p
= NULL
;
2375 Condition
**list
= data
, *c
;
2376 ConditionType t
= ltype
;
2377 bool trigger
, negate
;
2386 if (isempty(rvalue
)) {
2387 /* Empty assignment resets the list */
2388 *list
= condition_free_list(*list
);
2392 trigger
= rvalue
[0] == '|';
2396 negate
= rvalue
[0] == '!';
2400 r
= unit_full_printf(u
, rvalue
, &p
);
2402 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2406 if (!path_is_absolute(p
)) {
2407 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2411 c
= condition_new(t
, p
, trigger
, negate
);
2415 LIST_PREPEND(conditions
, *list
, c
);
2419 int config_parse_unit_condition_string(
2421 const char *filename
,
2423 const char *section
,
2424 unsigned section_line
,
2431 _cleanup_free_
char *s
= NULL
;
2432 Condition
**list
= data
, *c
;
2433 ConditionType t
= ltype
;
2434 bool trigger
, negate
;
2443 if (isempty(rvalue
)) {
2444 /* Empty assignment resets the list */
2445 *list
= condition_free_list(*list
);
2449 trigger
= rvalue
[0] == '|';
2453 negate
= rvalue
[0] == '!';
2457 r
= unit_full_printf(u
, rvalue
, &s
);
2459 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2463 c
= condition_new(t
, s
, trigger
, negate
);
2467 LIST_PREPEND(conditions
, *list
, c
);
2471 int config_parse_unit_condition_null(
2473 const char *filename
,
2475 const char *section
,
2476 unsigned section_line
,
2483 Condition
**list
= data
, *c
;
2484 bool trigger
, negate
;
2492 if (isempty(rvalue
)) {
2493 /* Empty assignment resets the list */
2494 *list
= condition_free_list(*list
);
2498 trigger
= rvalue
[0] == '|';
2502 negate
= rvalue
[0] == '!';
2506 b
= parse_boolean(rvalue
);
2508 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2515 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2519 LIST_PREPEND(conditions
, *list
, c
);
2523 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2524 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2526 int config_parse_unit_requires_mounts_for(
2528 const char *filename
,
2530 const char *section
,
2531 unsigned section_line
,
2547 for (p
= rvalue
;; ) {
2548 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2550 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2556 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2557 "Invalid syntax, ignoring: %s", rvalue
);
2561 if (!utf8_is_valid(word
)) {
2562 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2566 r
= unit_full_printf(u
, word
, &resolved
);
2568 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2572 r
= unit_require_mounts_for(u
, resolved
);
2574 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2580 int config_parse_documentation(const char *unit
,
2581 const char *filename
,
2583 const char *section
,
2584 unsigned section_line
,
2600 if (isempty(rvalue
)) {
2601 /* Empty assignment resets the list */
2602 u
->documentation
= strv_free(u
->documentation
);
2606 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2607 rvalue
, data
, userdata
);
2611 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2613 if (documentation_url_is_valid(*a
))
2616 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2628 static int syscall_filter_parse_one(
2630 const char *filename
,
2639 const SyscallFilterSet
*set
;
2642 set
= syscall_filter_set_find(t
);
2645 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2649 NULSTR_FOREACH(i
, set
->value
) {
2650 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2657 id
= seccomp_syscall_resolve_name(t
);
2658 if (id
== __NR_SCMP_ERROR
) {
2660 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2664 /* If we previously wanted to forbid a syscall and now
2665 * we want to allow it, then remove it from the list
2667 if (!invert
== c
->syscall_whitelist
) {
2668 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2674 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2680 int config_parse_syscall_filter(
2682 const char *filename
,
2684 const char *section
,
2685 unsigned section_line
,
2692 ExecContext
*c
= data
;
2694 bool invert
= false;
2703 if (isempty(rvalue
)) {
2704 /* Empty assignment resets the list */
2705 c
->syscall_filter
= set_free(c
->syscall_filter
);
2706 c
->syscall_whitelist
= false;
2710 if (rvalue
[0] == '~') {
2715 if (!c
->syscall_filter
) {
2716 c
->syscall_filter
= set_new(NULL
);
2717 if (!c
->syscall_filter
)
2721 /* Allow everything but the ones listed */
2722 c
->syscall_whitelist
= false;
2724 /* Allow nothing but the ones listed */
2725 c
->syscall_whitelist
= true;
2727 /* Accept default syscalls if we are on a whitelist */
2728 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2736 _cleanup_free_
char *word
= NULL
;
2738 r
= extract_first_word(&p
, &word
, NULL
, 0);
2744 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2748 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2756 int config_parse_syscall_archs(
2758 const char *filename
,
2760 const char *section
,
2761 unsigned section_line
,
2772 if (isempty(rvalue
)) {
2773 *archs
= set_free(*archs
);
2777 r
= set_ensure_allocated(archs
, NULL
);
2781 for (p
= rvalue
;;) {
2782 _cleanup_free_
char *word
= NULL
;
2785 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2791 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2792 "Invalid syntax, ignoring: %s", rvalue
);
2796 r
= seccomp_arch_from_string(word
, &a
);
2798 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2799 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2803 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2809 int config_parse_syscall_errno(
2811 const char *filename
,
2813 const char *section
,
2814 unsigned section_line
,
2821 ExecContext
*c
= data
;
2828 if (isempty(rvalue
)) {
2829 /* Empty assignment resets to KILL */
2830 c
->syscall_errno
= 0;
2834 e
= errno_from_name(rvalue
);
2836 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2840 c
->syscall_errno
= e
;
2844 int config_parse_address_families(
2846 const char *filename
,
2848 const char *section
,
2849 unsigned section_line
,
2856 ExecContext
*c
= data
;
2857 bool invert
= false;
2865 if (isempty(rvalue
)) {
2866 /* Empty assignment resets the list */
2867 c
->address_families
= set_free(c
->address_families
);
2868 c
->address_families_whitelist
= false;
2872 if (rvalue
[0] == '~') {
2877 if (!c
->address_families
) {
2878 c
->address_families
= set_new(NULL
);
2879 if (!c
->address_families
)
2882 c
->address_families_whitelist
= !invert
;
2885 for (p
= rvalue
;;) {
2886 _cleanup_free_
char *word
= NULL
;
2889 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2895 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2896 "Invalid syntax, ignoring: %s", rvalue
);
2900 af
= af_from_name(word
);
2902 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2903 "Failed to parse address family \"%s\", ignoring: %m", word
);
2907 /* If we previously wanted to forbid an address family and now
2908 * we want to allow it, then just remove it from the list.
2910 if (!invert
== c
->address_families_whitelist
) {
2911 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2915 set_remove(c
->address_families
, INT_TO_PTR(af
));
2919 int config_parse_restrict_namespaces(
2921 const char *filename
,
2923 const char *section
,
2924 unsigned section_line
,
2931 ExecContext
*c
= data
;
2932 bool invert
= false;
2935 if (isempty(rvalue
)) {
2936 /* Reset to the default. */
2937 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2941 if (rvalue
[0] == '~') {
2946 r
= parse_boolean(rvalue
);
2948 c
->restrict_namespaces
= 0;
2950 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2952 /* Not a boolean argument, in this case it's a list of namespace types. */
2954 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2956 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2962 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2968 int config_parse_unit_slice(
2970 const char *filename
,
2972 const char *section
,
2973 unsigned section_line
,
2980 _cleanup_free_
char *k
= NULL
;
2981 Unit
*u
= userdata
, *slice
= NULL
;
2989 r
= unit_name_printf(u
, rvalue
, &k
);
2991 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2995 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2997 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3001 r
= unit_set_slice(u
, slice
);
3003 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3010 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3012 int config_parse_cpu_weight(
3014 const char *filename
,
3016 const char *section
,
3017 unsigned section_line
,
3024 uint64_t *weight
= data
;
3031 r
= cg_weight_parse(rvalue
, weight
);
3033 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3040 int config_parse_cpu_shares(
3042 const char *filename
,
3044 const char *section
,
3045 unsigned section_line
,
3052 uint64_t *shares
= data
;
3059 r
= cg_cpu_shares_parse(rvalue
, shares
);
3061 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3068 int config_parse_cpu_quota(
3070 const char *filename
,
3072 const char *section
,
3073 unsigned section_line
,
3080 CGroupContext
*c
= data
;
3087 if (isempty(rvalue
)) {
3088 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3092 r
= parse_percent_unbounded(rvalue
);
3094 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3098 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3102 int config_parse_memory_limit(
3104 const char *filename
,
3106 const char *section
,
3107 unsigned section_line
,
3114 CGroupContext
*c
= data
;
3115 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3118 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3120 r
= parse_percent(rvalue
);
3122 r
= parse_size(rvalue
, 1024, &bytes
);
3124 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3128 bytes
= physical_memory_scale(r
, 100U);
3130 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3131 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3136 if (streq(lvalue
, "MemoryLow"))
3137 c
->memory_low
= bytes
;
3138 else if (streq(lvalue
, "MemoryHigh"))
3139 c
->memory_high
= bytes
;
3140 else if (streq(lvalue
, "MemoryMax"))
3141 c
->memory_max
= bytes
;
3142 else if (streq(lvalue
, "MemorySwapMax"))
3143 c
->memory_swap_max
= bytes
;
3144 else if (streq(lvalue
, "MemoryLimit"))
3145 c
->memory_limit
= bytes
;
3152 int config_parse_tasks_max(
3154 const char *filename
,
3156 const char *section
,
3157 unsigned section_line
,
3164 uint64_t *tasks_max
= data
, v
;
3168 if (isempty(rvalue
)) {
3169 *tasks_max
= u
->manager
->default_tasks_max
;
3173 if (streq(rvalue
, "infinity")) {
3174 *tasks_max
= CGROUP_LIMIT_MAX
;
3178 r
= parse_percent(rvalue
);
3180 r
= safe_atou64(rvalue
, &v
);
3182 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3186 v
= system_tasks_max_scale(r
, 100U);
3188 if (v
<= 0 || v
>= UINT64_MAX
) {
3189 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3197 int config_parse_device_allow(
3199 const char *filename
,
3201 const char *section
,
3202 unsigned section_line
,
3209 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3210 CGroupContext
*c
= data
;
3211 CGroupDeviceAllow
*a
;
3212 const char *m
= NULL
;
3216 if (isempty(rvalue
)) {
3217 while (c
->device_allow
)
3218 cgroup_context_free_device_allow(c
, c
->device_allow
);
3223 r
= unit_full_printf(userdata
, rvalue
, &t
);
3225 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3226 "Failed to resolve specifiers in %s, ignoring: %m",
3230 n
= strcspn(t
, WHITESPACE
);
3232 path
= strndup(t
, n
);
3236 if (!is_deviceallow_pattern(path
)) {
3237 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3241 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3245 if (!in_charset(m
, "rwm")) {
3246 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3250 a
= new0(CGroupDeviceAllow
, 1);
3256 a
->r
= !!strchr(m
, 'r');
3257 a
->w
= !!strchr(m
, 'w');
3258 a
->m
= !!strchr(m
, 'm');
3260 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3264 int config_parse_io_weight(
3266 const char *filename
,
3268 const char *section
,
3269 unsigned section_line
,
3276 uint64_t *weight
= data
;
3283 r
= cg_weight_parse(rvalue
, weight
);
3285 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3292 int config_parse_io_device_weight(
3294 const char *filename
,
3296 const char *section
,
3297 unsigned section_line
,
3304 _cleanup_free_
char *path
= NULL
;
3305 CGroupIODeviceWeight
*w
;
3306 CGroupContext
*c
= data
;
3316 if (isempty(rvalue
)) {
3317 while (c
->io_device_weights
)
3318 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3323 n
= strcspn(rvalue
, WHITESPACE
);
3324 weight
= rvalue
+ n
;
3325 weight
+= strspn(weight
, WHITESPACE
);
3327 if (isempty(weight
)) {
3328 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3332 path
= strndup(rvalue
, n
);
3336 if (!path_startswith(path
, "/dev")) {
3337 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3341 r
= cg_weight_parse(weight
, &u
);
3343 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3347 assert(u
!= CGROUP_WEIGHT_INVALID
);
3349 w
= new0(CGroupIODeviceWeight
, 1);
3358 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3362 int config_parse_io_limit(
3364 const char *filename
,
3366 const char *section
,
3367 unsigned section_line
,
3374 _cleanup_free_
char *path
= NULL
;
3375 CGroupIODeviceLimit
*l
= NULL
, *t
;
3376 CGroupContext
*c
= data
;
3377 CGroupIOLimitType type
;
3387 type
= cgroup_io_limit_type_from_string(lvalue
);
3390 if (isempty(rvalue
)) {
3391 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3392 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3396 n
= strcspn(rvalue
, WHITESPACE
);
3398 limit
+= strspn(limit
, WHITESPACE
);
3401 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3405 path
= strndup(rvalue
, n
);
3409 if (!path_startswith(path
, "/dev")) {
3410 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3414 if (streq("infinity", limit
)) {
3415 num
= CGROUP_LIMIT_MAX
;
3417 r
= parse_size(limit
, 1000, &num
);
3418 if (r
< 0 || num
<= 0) {
3419 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3424 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3425 if (path_equal(path
, t
->path
)) {
3432 CGroupIOLimitType ttype
;
3434 l
= new0(CGroupIODeviceLimit
, 1);
3440 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3441 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3443 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3446 l
->limits
[type
] = num
;
3451 int config_parse_blockio_weight(
3453 const char *filename
,
3455 const char *section
,
3456 unsigned section_line
,
3463 uint64_t *weight
= data
;
3470 r
= cg_blkio_weight_parse(rvalue
, weight
);
3472 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3479 int config_parse_blockio_device_weight(
3481 const char *filename
,
3483 const char *section
,
3484 unsigned section_line
,
3491 _cleanup_free_
char *path
= NULL
;
3492 CGroupBlockIODeviceWeight
*w
;
3493 CGroupContext
*c
= data
;
3503 if (isempty(rvalue
)) {
3504 while (c
->blockio_device_weights
)
3505 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3510 n
= strcspn(rvalue
, WHITESPACE
);
3511 weight
= rvalue
+ n
;
3512 weight
+= strspn(weight
, WHITESPACE
);
3514 if (isempty(weight
)) {
3515 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3519 path
= strndup(rvalue
, n
);
3523 if (!path_startswith(path
, "/dev")) {
3524 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3528 r
= cg_blkio_weight_parse(weight
, &u
);
3530 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3534 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3536 w
= new0(CGroupBlockIODeviceWeight
, 1);
3545 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3549 int config_parse_blockio_bandwidth(
3551 const char *filename
,
3553 const char *section
,
3554 unsigned section_line
,
3561 _cleanup_free_
char *path
= NULL
;
3562 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3563 CGroupContext
*c
= data
;
3564 const char *bandwidth
;
3574 read
= streq("BlockIOReadBandwidth", lvalue
);
3576 if (isempty(rvalue
)) {
3577 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3578 b
->rbps
= CGROUP_LIMIT_MAX
;
3579 b
->wbps
= CGROUP_LIMIT_MAX
;
3584 n
= strcspn(rvalue
, WHITESPACE
);
3585 bandwidth
= rvalue
+ n
;
3586 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3589 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3593 path
= strndup(rvalue
, n
);
3597 if (!path_startswith(path
, "/dev")) {
3598 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3602 r
= parse_size(bandwidth
, 1000, &bytes
);
3603 if (r
< 0 || bytes
<= 0) {
3604 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3608 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3609 if (path_equal(path
, t
->path
)) {
3616 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3622 b
->rbps
= CGROUP_LIMIT_MAX
;
3623 b
->wbps
= CGROUP_LIMIT_MAX
;
3625 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3636 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3638 int config_parse_job_mode_isolate(
3640 const char *filename
,
3642 const char *section
,
3643 unsigned section_line
,
3657 r
= parse_boolean(rvalue
);
3659 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3663 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3667 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3669 int config_parse_exec_directories(
3671 const char *filename
,
3673 const char *section
,
3674 unsigned section_line
,
3691 if (isempty(rvalue
)) {
3692 /* Empty assignment resets the list */
3693 *rt
= strv_free(*rt
);
3697 for (p
= rvalue
;;) {
3698 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3700 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3704 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3705 "Invalid syntax, ignoring: %s", rvalue
);
3711 r
= unit_full_printf(u
, word
, &k
);
3713 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3714 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3718 if (!path_is_safe(k
) || path_is_absolute(k
)) {
3719 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3720 "%s= path is not valid, ignoring assignment: %s", lvalue
, rvalue
);
3724 r
= strv_push(rt
, k
);
3731 int config_parse_set_status(
3733 const char *filename
,
3735 const char *section
,
3736 unsigned section_line
,
3744 const char *word
, *state
;
3746 ExitStatusSet
*status_set
= data
;
3753 /* Empty assignment resets the list */
3754 if (isempty(rvalue
)) {
3755 exit_status_set_free(status_set
);
3759 FOREACH_WORD(word
, l
, rvalue
, state
) {
3760 _cleanup_free_
char *temp
;
3764 temp
= strndup(word
, l
);
3768 r
= safe_atoi(temp
, &val
);
3770 val
= signal_from_string_try_harder(temp
);
3773 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3776 set
= &status_set
->signal
;
3778 if (val
< 0 || val
> 255) {
3779 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3782 set
= &status_set
->status
;
3785 r
= set_ensure_allocated(set
, NULL
);
3789 r
= set_put(*set
, INT_TO_PTR(val
));
3791 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3795 if (!isempty(state
))
3796 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3801 int config_parse_namespace_path_strv(
3803 const char *filename
,
3805 const char *section
,
3806 unsigned section_line
,
3823 if (isempty(rvalue
)) {
3824 /* Empty assignment resets the list */
3825 *sv
= strv_free(*sv
);
3831 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3833 bool ignore_enoent
= false, shall_prefix
= false;
3835 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3841 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3845 if (!utf8_is_valid(word
)) {
3846 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3851 if (startswith(w
, "-")) {
3852 ignore_enoent
= true;
3855 if (startswith(w
, "+")) {
3856 shall_prefix
= true;
3860 r
= unit_full_printf(u
, w
, &resolved
);
3862 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3866 if (!path_is_absolute(resolved
)) {
3867 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3871 path_kill_slashes(resolved
);
3873 joined
= strjoin(ignore_enoent
? "-" : "",
3874 shall_prefix
? "+" : "",
3877 r
= strv_push(sv
, joined
);
3887 int config_parse_bind_paths(
3889 const char *filename
,
3891 const char *section
,
3892 unsigned section_line
,
3899 ExecContext
*c
= data
;
3909 if (isempty(rvalue
)) {
3910 /* Empty assignment resets the list */
3911 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3912 c
->bind_mounts
= NULL
;
3913 c
->n_bind_mounts
= 0;
3919 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3920 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3921 char *s
= NULL
, *d
= NULL
;
3922 bool rbind
= true, ignore_enoent
= false;
3924 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3930 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3934 r
= unit_full_printf(u
, source
, &sresolved
);
3936 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3937 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3943 ignore_enoent
= true;
3947 if (!utf8_is_valid(s
)) {
3948 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3951 if (!path_is_absolute(s
)) {
3952 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3956 path_kill_slashes(s
);
3958 /* Optionally, the destination is specified. */
3959 if (p
&& p
[-1] == ':') {
3960 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3964 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3968 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3972 r
= unit_full_printf(u
, destination
, &dresolved
);
3974 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3975 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3979 if (!utf8_is_valid(dresolved
)) {
3980 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
3983 if (!path_is_absolute(dresolved
)) {
3984 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
3988 d
= path_kill_slashes(dresolved
);
3990 /* Optionally, there's also a short option string specified */
3991 if (p
&& p
[-1] == ':') {
3992 _cleanup_free_
char *options
= NULL
;
3994 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
3998 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4002 if (isempty(options
) || streq(options
, "rbind"))
4004 else if (streq(options
, "norbind"))
4007 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4014 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4018 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4020 .ignore_enoent
= ignore_enoent
,
4029 int config_parse_no_new_privileges(
4031 const char *filename
,
4033 const char *section
,
4034 unsigned section_line
,
4041 ExecContext
*c
= data
;
4049 k
= parse_boolean(rvalue
);
4051 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4055 c
->no_new_privileges
= k
;
4060 int config_parse_protect_home(
4062 const char *filename
,
4064 const char *section
,
4065 unsigned section_line
,
4072 ExecContext
*c
= data
;
4080 /* Our enum shall be a superset of booleans, hence first try
4081 * to parse as boolean, and then as enum */
4083 k
= parse_boolean(rvalue
);
4085 c
->protect_home
= PROTECT_HOME_YES
;
4087 c
->protect_home
= PROTECT_HOME_NO
;
4091 h
= protect_home_from_string(rvalue
);
4093 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4097 c
->protect_home
= h
;
4103 int config_parse_protect_system(
4105 const char *filename
,
4107 const char *section
,
4108 unsigned section_line
,
4115 ExecContext
*c
= data
;
4123 /* Our enum shall be a superset of booleans, hence first try
4124 * to parse as boolean, and then as enum */
4126 k
= parse_boolean(rvalue
);
4128 c
->protect_system
= PROTECT_SYSTEM_YES
;
4130 c
->protect_system
= PROTECT_SYSTEM_NO
;
4134 s
= protect_system_from_string(rvalue
);
4136 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4140 c
->protect_system
= s
;
4146 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode
, exec_keyring_mode
, ExecKeyringMode
, "Failed to parse keyring mode");
4148 #define FOLLOW_MAX 8
4150 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4161 /* This will update the filename pointer if the loaded file is
4162 * reached by a symlink. The old string will be freed. */
4165 char *target
, *name
;
4167 if (c
++ >= FOLLOW_MAX
)
4170 path_kill_slashes(*filename
);
4172 /* Add the file name we are currently looking at to
4173 * the names of this unit, but only if it is a valid
4175 name
= basename(*filename
);
4176 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4178 id
= set_get(names
, name
);
4184 r
= set_consume(names
, id
);
4190 /* Try to open the file name, but don't if its a symlink */
4191 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4198 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4199 r
= readlink_and_make_absolute(*filename
, &target
);
4207 f
= fdopen(fd
, "re");
4219 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4227 /* Let's try to add in all symlink names we found */
4228 while ((k
= set_steal_first(names
))) {
4230 /* First try to merge in the other name into our
4232 r
= unit_merge_by_name(*u
, k
);
4236 /* Hmm, we couldn't merge the other unit into
4237 * ours? Then let's try it the other way
4240 /* If the symlink name we are looking at is unit template, then
4241 we must search for instance of this template */
4242 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4243 _cleanup_free_
char *instance
= NULL
;
4245 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4249 other
= manager_get_unit((*u
)->manager
, instance
);
4251 other
= manager_get_unit((*u
)->manager
, k
);
4256 r
= unit_merge(other
, *u
);
4259 return merge_by_names(u
, names
, NULL
);
4267 unit_choose_id(*u
, id
);
4275 static int load_from_path(Unit
*u
, const char *path
) {
4276 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4277 _cleanup_fclose_
FILE *f
= NULL
;
4278 _cleanup_free_
char *filename
= NULL
;
4287 symlink_names
= set_new(&string_hash_ops
);
4291 if (path_is_absolute(path
)) {
4293 filename
= strdup(path
);
4297 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4299 filename
= mfree(filename
);
4307 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4309 /* Instead of opening the path right away, we manually
4310 * follow all symlinks and add their name to our unit
4311 * name set while doing so */
4312 filename
= path_make_absolute(path
, *p
);
4316 if (u
->manager
->unit_path_cache
&&
4317 !set_get(u
->manager
->unit_path_cache
, filename
))
4320 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4323 filename
= mfree(filename
);
4325 /* ENOENT means that the file is missing or is a dangling symlink.
4326 * ENOTDIR means that one of paths we expect to be is a directory
4327 * is not a directory, we should just ignore that.
4328 * EACCES means that the directory or file permissions are wrong.
4331 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4332 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4335 /* Empty the symlink names for the next run */
4336 set_clear_free(symlink_names
);
4341 /* Hmm, no suitable file found? */
4344 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4345 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4350 r
= merge_by_names(&merged
, symlink_names
, id
);
4355 u
->load_state
= UNIT_MERGED
;
4359 if (fstat(fileno(f
), &st
) < 0)
4362 if (null_or_empty(&st
)) {
4363 u
->load_state
= UNIT_MASKED
;
4364 u
->fragment_mtime
= 0;
4366 u
->load_state
= UNIT_LOADED
;
4367 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4369 /* Now, parse the file contents */
4370 r
= config_parse(u
->id
, filename
, f
,
4371 UNIT_VTABLE(u
)->sections
,
4372 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4373 false, true, false, u
);
4378 free(u
->fragment_path
);
4379 u
->fragment_path
= filename
;
4382 if (u
->source_path
) {
4383 if (stat(u
->source_path
, &st
) >= 0)
4384 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4386 u
->source_mtime
= 0;
4392 int unit_load_fragment(Unit
*u
) {
4398 assert(u
->load_state
== UNIT_STUB
);
4402 u
->load_state
= UNIT_LOADED
;
4406 /* First, try to find the unit under its id. We always look
4407 * for unit files in the default directories, to make it easy
4408 * to override things by placing things in /etc/systemd/system */
4409 r
= load_from_path(u
, u
->id
);
4413 /* Try to find an alias we can load this with */
4414 if (u
->load_state
== UNIT_STUB
) {
4415 SET_FOREACH(t
, u
->names
, i
) {
4420 r
= load_from_path(u
, t
);
4424 if (u
->load_state
!= UNIT_STUB
)
4429 /* And now, try looking for it under the suggested (originally linked) path */
4430 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4432 r
= load_from_path(u
, u
->fragment_path
);
4436 if (u
->load_state
== UNIT_STUB
)
4437 /* Hmm, this didn't work? Then let's get rid
4438 * of the fragment path stored for us, so that
4439 * we don't point to an invalid location. */
4440 u
->fragment_path
= mfree(u
->fragment_path
);
4443 /* Look for a template */
4444 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4445 _cleanup_free_
char *k
= NULL
;
4447 r
= unit_name_template(u
->id
, &k
);
4451 r
= load_from_path(u
, k
);
4454 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4458 if (u
->load_state
== UNIT_STUB
) {
4459 SET_FOREACH(t
, u
->names
, i
) {
4460 _cleanup_free_
char *z
= NULL
;
4465 r
= unit_name_template(t
, &z
);
4469 r
= load_from_path(u
, z
);
4473 if (u
->load_state
!= UNIT_STUB
)
4482 void unit_dump_config_items(FILE *f
) {
4483 static const struct {
4484 const ConfigParserCallback callback
;
4487 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4488 { config_parse_warn_compat
, "NOTSUPPORTED" },
4490 { config_parse_int
, "INTEGER" },
4491 { config_parse_unsigned
, "UNSIGNED" },
4492 { config_parse_iec_size
, "SIZE" },
4493 { config_parse_iec_uint64
, "SIZE" },
4494 { config_parse_si_size
, "SIZE" },
4495 { config_parse_bool
, "BOOLEAN" },
4496 { config_parse_string
, "STRING" },
4497 { config_parse_path
, "PATH" },
4498 { config_parse_unit_path_printf
, "PATH" },
4499 { config_parse_strv
, "STRING [...]" },
4500 { config_parse_exec_nice
, "NICE" },
4501 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4502 { config_parse_exec_io_class
, "IOCLASS" },
4503 { config_parse_exec_io_priority
, "IOPRIORITY" },
4504 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4505 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4506 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4507 { config_parse_mode
, "MODE" },
4508 { config_parse_unit_env_file
, "FILE" },
4509 { config_parse_exec_output
, "OUTPUT" },
4510 { config_parse_exec_input
, "INPUT" },
4511 { config_parse_log_facility
, "FACILITY" },
4512 { config_parse_log_level
, "LEVEL" },
4513 { config_parse_exec_secure_bits
, "SECUREBITS" },
4514 { config_parse_capability_set
, "BOUNDINGSET" },
4515 { config_parse_limit
, "LIMIT" },
4516 { config_parse_unit_deps
, "UNIT [...]" },
4517 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4518 { config_parse_service_type
, "SERVICETYPE" },
4519 { config_parse_service_restart
, "SERVICERESTART" },
4520 #if HAVE_SYSV_COMPAT
4521 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4523 { config_parse_kill_mode
, "KILLMODE" },
4524 { config_parse_signal
, "SIGNAL" },
4525 { config_parse_socket_listen
, "SOCKET [...]" },
4526 { config_parse_socket_bind
, "SOCKETBIND" },
4527 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4528 { config_parse_sec
, "SECONDS" },
4529 { config_parse_nsec
, "NANOSECONDS" },
4530 { config_parse_namespace_path_strv
, "PATH [...]" },
4531 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4532 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4533 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4534 { config_parse_unit_string_printf
, "STRING" },
4535 { config_parse_trigger_unit
, "UNIT" },
4536 { config_parse_timer
, "TIMER" },
4537 { config_parse_path_spec
, "PATH" },
4538 { config_parse_notify_access
, "ACCESS" },
4539 { config_parse_ip_tos
, "TOS" },
4540 { config_parse_unit_condition_path
, "CONDITION" },
4541 { config_parse_unit_condition_string
, "CONDITION" },
4542 { config_parse_unit_condition_null
, "CONDITION" },
4543 { config_parse_unit_slice
, "SLICE" },
4544 { config_parse_documentation
, "URL" },
4545 { config_parse_service_timeout
, "SECONDS" },
4546 { config_parse_emergency_action
, "ACTION" },
4547 { config_parse_set_status
, "STATUS" },
4548 { config_parse_service_sockets
, "SOCKETS" },
4549 { config_parse_environ
, "ENVIRON" },
4551 { config_parse_syscall_filter
, "SYSCALLS" },
4552 { config_parse_syscall_archs
, "ARCHS" },
4553 { config_parse_syscall_errno
, "ERRNO" },
4554 { config_parse_address_families
, "FAMILIES" },
4555 { config_parse_restrict_namespaces
, "NAMESPACES" },
4557 { config_parse_cpu_shares
, "SHARES" },
4558 { config_parse_cpu_weight
, "WEIGHT" },
4559 { config_parse_memory_limit
, "LIMIT" },
4560 { config_parse_device_allow
, "DEVICE" },
4561 { config_parse_device_policy
, "POLICY" },
4562 { config_parse_io_limit
, "LIMIT" },
4563 { config_parse_io_weight
, "WEIGHT" },
4564 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4565 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4566 { config_parse_blockio_weight
, "WEIGHT" },
4567 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4568 { config_parse_long
, "LONG" },
4569 { config_parse_socket_service
, "SERVICE" },
4571 { config_parse_exec_selinux_context
, "LABEL" },
4573 { config_parse_job_mode
, "MODE" },
4574 { config_parse_job_mode_isolate
, "BOOLEAN" },
4575 { config_parse_personality
, "PERSONALITY" },
4578 const char *prev
= NULL
;
4583 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4584 const char *rvalue
= "OTHER", *lvalue
;
4588 const ConfigPerfItem
*p
;
4590 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4592 dot
= strchr(i
, '.');
4593 lvalue
= dot
? dot
+ 1 : i
;
4597 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4601 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4604 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4605 if (p
->parse
== table
[j
].callback
) {
4606 rvalue
= table
[j
].rvalue
;
4610 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);