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
)) {
289 /* Empty assignment resets the list. As a special rule
290 * we actually fill in a real empty array here rather
291 * than NULL, since some code wants to know if
292 * something was set at all... */
293 empty
= new0(char*, 1);
304 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
306 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
312 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
313 "Invalid syntax, ignoring: %s", rvalue
);
317 r
= unit_full_printf(u
, word
, &k
);
319 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
320 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
324 if (!utf8_is_valid(k
)) {
325 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
329 if (!path_is_absolute(k
)) {
330 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
331 "Symlink path is not absolute: %s", k
);
335 path_kill_slashes(k
);
344 int config_parse_socket_listen(const char *unit
,
345 const char *filename
,
348 unsigned section_line
,
355 _cleanup_free_ SocketPort
*p
= NULL
;
367 if (isempty(rvalue
)) {
368 /* An empty assignment removes all ports */
369 socket_free_ports(s
);
373 p
= new0(SocketPort
, 1);
377 if (ltype
!= SOCKET_SOCKET
) {
380 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
382 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
386 path_kill_slashes(p
->path
);
388 } else if (streq(lvalue
, "ListenNetlink")) {
389 _cleanup_free_
char *k
= NULL
;
391 p
->type
= SOCKET_SOCKET
;
392 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
394 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
398 r
= socket_address_parse_netlink(&p
->address
, k
);
400 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
405 _cleanup_free_
char *k
= NULL
;
407 p
->type
= SOCKET_SOCKET
;
408 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
410 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
414 r
= socket_address_parse_and_warn(&p
->address
, k
);
416 if (r
!= -EAFNOSUPPORT
)
417 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
422 if (streq(lvalue
, "ListenStream"))
423 p
->address
.type
= SOCK_STREAM
;
424 else if (streq(lvalue
, "ListenDatagram"))
425 p
->address
.type
= SOCK_DGRAM
;
427 assert(streq(lvalue
, "ListenSequentialPacket"));
428 p
->address
.type
= SOCK_SEQPACKET
;
431 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
432 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
438 p
->auxiliary_fds
= NULL
;
439 p
->n_auxiliary_fds
= 0;
443 LIST_FIND_TAIL(port
, s
->ports
, tail
);
444 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
446 LIST_PREPEND(port
, s
->ports
, p
);
452 int config_parse_socket_protocol(const char *unit
,
453 const char *filename
,
456 unsigned section_line
,
471 if (streq(rvalue
, "udplite"))
472 s
->socket_protocol
= IPPROTO_UDPLITE
;
473 else if (streq(rvalue
, "sctp"))
474 s
->socket_protocol
= IPPROTO_SCTP
;
476 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
483 int config_parse_socket_bind(const char *unit
,
484 const char *filename
,
487 unsigned section_line
,
495 SocketAddressBindIPv6Only b
;
504 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
508 r
= parse_boolean(rvalue
);
510 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
514 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
516 s
->bind_ipv6_only
= b
;
521 int config_parse_exec_nice(
523 const char *filename
,
526 unsigned section_line
,
533 ExecContext
*c
= data
;
541 r
= parse_nice(rvalue
, &priority
);
544 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
546 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
557 int config_parse_exec_oom_score_adjust(const char* unit
,
558 const char *filename
,
561 unsigned section_line
,
568 ExecContext
*c
= data
;
576 r
= safe_atoi(rvalue
, &oa
);
578 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
582 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
583 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
587 c
->oom_score_adjust
= oa
;
588 c
->oom_score_adjust_set
= true;
593 int config_parse_exec(
595 const char *filename
,
598 unsigned section_line
,
605 ExecCommand
**e
= data
;
617 rvalue
+= strspn(rvalue
, WHITESPACE
);
619 if (isempty(rvalue
)) {
620 /* An empty assignment resets the list */
621 *e
= exec_command_free_list(*e
);
627 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
628 ExecCommandFlags flags
= 0;
629 bool ignore
= false, separate_argv0
= false;
630 _cleanup_free_ ExecCommand
*nce
= NULL
;
631 _cleanup_strv_free_
char **n
= NULL
;
632 size_t nlen
= 0, nbufsize
= 0;
637 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
643 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
644 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
645 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
646 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
647 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
648 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
649 * other sandboxing, with some special exceptions for changing UID.
651 * The idea is that '!!' may be used to write services that can take benefit of systemd's
652 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
653 * privilege dropping within the daemon if the kernel does not offer that. */
655 if (*f
== '-' && !(flags
& EXEC_COMMAND_IGNORE_FAILURE
)) {
656 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
658 } else if (*f
== '@' && !separate_argv0
)
659 separate_argv0
= true;
660 else if (*f
== '+' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
661 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
662 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
663 flags
|= EXEC_COMMAND_NO_SETUID
;
664 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
665 flags
&= ~EXEC_COMMAND_NO_SETUID
;
666 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
672 r
= unit_full_printf(u
, f
, &path
);
674 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
675 "Failed to resolve unit specifiers on %s%s: %m",
676 f
, ignore
? ", ignoring" : "");
677 return ignore
? 0 : -ENOEXEC
;
681 /* First word is either "-" or "@" with no command. */
682 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
683 "Empty path in command line%s: \"%s\"",
684 ignore
? ", ignoring" : "", rvalue
);
685 return ignore
? 0 : -ENOEXEC
;
687 if (!string_is_safe(path
)) {
688 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
689 "Executable path contains special characters%s: %s",
690 ignore
? ", ignoring" : "", rvalue
);
691 return ignore
? 0 : -ENOEXEC
;
693 if (!path_is_absolute(path
)) {
694 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
695 "Executable path is not absolute%s: %s",
696 ignore
? ", ignoring" : "", rvalue
);
697 return ignore
? 0 : -ENOEXEC
;
699 if (endswith(path
, "/")) {
700 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
701 "Executable path specifies a directory%s: %s",
702 ignore
? ", ignoring" : "", rvalue
);
703 return ignore
? 0 : -ENOEXEC
;
706 if (!separate_argv0
) {
709 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
719 path_kill_slashes(path
);
721 while (!isempty(p
)) {
722 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
724 /* Check explicitly for an unquoted semicolon as
725 * command separator token. */
726 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
728 p
+= strspn(p
, WHITESPACE
);
733 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
734 * extract_first_word() would return the same for all of those. */
735 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
739 p
+= strspn(p
, WHITESPACE
);
741 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
752 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
756 return ignore
? 0 : -ENOEXEC
;
758 r
= unit_full_printf(u
, word
, &resolved
);
760 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
761 "Failed to resolve unit specifiers on %s%s: %m",
762 word
, ignore
? ", ignoring" : "");
763 return ignore
? 0 : -ENOEXEC
;
766 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
768 n
[nlen
++] = resolved
;
774 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
775 "Empty executable name or zeroeth argument%s: %s",
776 ignore
? ", ignoring" : "", rvalue
);
777 return ignore
? 0 : -ENOEXEC
;
780 nce
= new0(ExecCommand
, 1);
788 exec_command_append_list(e
, nce
);
790 /* Do not _cleanup_free_ these. */
801 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
802 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
804 int config_parse_socket_bindtodevice(
806 const char *filename
,
809 unsigned section_line
,
824 if (rvalue
[0] && !streq(rvalue
, "*")) {
825 if (!ifname_valid(rvalue
)) {
826 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
836 free(s
->bind_to_device
);
837 s
->bind_to_device
= n
;
842 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
843 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
845 int config_parse_exec_input(const char *unit
,
846 const char *filename
,
849 unsigned section_line
,
855 ExecContext
*c
= data
;
864 name
= startswith(rvalue
, "fd:");
866 /* Strip prefix and validate fd name */
867 if (!fdname_is_valid(name
)) {
868 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
871 c
->std_input
= EXEC_INPUT_NAMED_FD
;
872 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
877 ExecInput ei
= exec_input_from_string(rvalue
);
878 if (ei
== _EXEC_INPUT_INVALID
)
879 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
886 int config_parse_exec_output(const char *unit
,
887 const char *filename
,
890 unsigned section_line
,
896 ExecContext
*c
= data
;
907 name
= startswith(rvalue
, "fd:");
909 /* Strip prefix and validate fd name */
910 if (!fdname_is_valid(name
)) {
911 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
914 eo
= EXEC_OUTPUT_NAMED_FD
;
916 eo
= exec_output_from_string(rvalue
);
917 if (eo
== _EXEC_OUTPUT_INVALID
) {
918 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
923 if (streq(lvalue
, "StandardOutput")) {
925 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
929 } else if (streq(lvalue
, "StandardError")) {
931 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
936 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
941 int config_parse_exec_io_class(const char *unit
,
942 const char *filename
,
945 unsigned section_line
,
952 ExecContext
*c
= data
;
960 x
= ioprio_class_from_string(rvalue
);
962 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
966 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
967 c
->ioprio_set
= true;
972 int config_parse_exec_io_priority(const char *unit
,
973 const char *filename
,
976 unsigned section_line
,
983 ExecContext
*c
= data
;
991 r
= ioprio_parse_priority(rvalue
, &i
);
993 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
997 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
998 c
->ioprio_set
= true;
1003 int config_parse_exec_cpu_sched_policy(const char *unit
,
1004 const char *filename
,
1006 const char *section
,
1007 unsigned section_line
,
1015 ExecContext
*c
= data
;
1023 x
= sched_policy_from_string(rvalue
);
1025 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1029 c
->cpu_sched_policy
= x
;
1030 /* Moving to or from real-time policy? We need to adjust the priority */
1031 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1032 c
->cpu_sched_set
= true;
1037 int config_parse_exec_cpu_sched_prio(const char *unit
,
1038 const char *filename
,
1040 const char *section
,
1041 unsigned section_line
,
1048 ExecContext
*c
= data
;
1056 r
= safe_atoi(rvalue
, &i
);
1058 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1062 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1063 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1064 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1066 if (i
< min
|| i
> max
) {
1067 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1071 c
->cpu_sched_priority
= i
;
1072 c
->cpu_sched_set
= true;
1077 int config_parse_exec_cpu_affinity(const char *unit
,
1078 const char *filename
,
1080 const char *section
,
1081 unsigned section_line
,
1088 ExecContext
*c
= data
;
1089 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1097 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1102 CPU_FREE(c
->cpuset
);
1105 /* An empty assignment resets the CPU list */
1111 c
->cpuset_ncpus
= ncpus
;
1116 int config_parse_exec_secure_bits(const char *unit
,
1117 const char *filename
,
1119 const char *section
,
1120 unsigned section_line
,
1127 ExecContext
*c
= data
;
1135 if (isempty(rvalue
)) {
1136 /* An empty assignment resets the field */
1141 r
= secure_bits_from_string(rvalue
);
1145 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1146 "Invalid syntax, ignoring: %s", rvalue
);
1155 int config_parse_capability_set(
1157 const char *filename
,
1159 const char *section
,
1160 unsigned section_line
,
1167 uint64_t *capability_set
= data
;
1168 uint64_t sum
= 0, initial
= 0;
1169 bool invert
= false;
1177 if (rvalue
[0] == '~') {
1182 if (streq(lvalue
, "CapabilityBoundingSet"))
1183 initial
= CAP_ALL
; /* initialized to all bits on */
1184 /* else "AmbientCapabilities" initialized to all bits off */
1186 r
= capability_set_from_string(rvalue
, &sum
);
1190 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1194 if (sum
== 0 || *capability_set
== initial
)
1195 /* "", "~" or uninitialized data -> replace */
1196 *capability_set
= invert
? ~sum
: sum
;
1198 /* previous data -> merge */
1200 *capability_set
&= ~sum
;
1202 *capability_set
|= sum
;
1208 int config_parse_limit(
1210 const char *filename
,
1212 const char *section
,
1213 unsigned section_line
,
1220 struct rlimit
**rl
= data
, d
= {};
1228 r
= rlimit_parse(ltype
, rvalue
, &d
);
1230 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1234 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1241 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1249 #if HAVE_SYSV_COMPAT
1250 int config_parse_sysv_priority(const char *unit
,
1251 const char *filename
,
1253 const char *section
,
1254 unsigned section_line
,
1261 int *priority
= data
;
1269 r
= safe_atoi(rvalue
, &i
);
1270 if (r
< 0 || i
< 0) {
1271 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1275 *priority
= (int) i
;
1280 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1281 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1283 int config_parse_exec_mount_flags(
1285 const char *filename
,
1287 const char *section
,
1288 unsigned section_line
,
1296 ExecContext
*c
= data
;
1304 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1306 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1311 int config_parse_exec_selinux_context(
1313 const char *filename
,
1315 const char *section
,
1316 unsigned section_line
,
1323 ExecContext
*c
= data
;
1334 if (isempty(rvalue
)) {
1335 c
->selinux_context
= mfree(c
->selinux_context
);
1336 c
->selinux_context_ignore
= false;
1340 if (rvalue
[0] == '-') {
1346 r
= unit_full_printf(u
, rvalue
, &k
);
1348 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1349 "Failed to resolve specifiers%s: %m",
1350 ignore
? ", ignoring" : "");
1351 return ignore
? 0 : -ENOEXEC
;
1354 free(c
->selinux_context
);
1355 c
->selinux_context
= k
;
1356 c
->selinux_context_ignore
= ignore
;
1361 int config_parse_exec_apparmor_profile(
1363 const char *filename
,
1365 const char *section
,
1366 unsigned section_line
,
1373 ExecContext
*c
= data
;
1384 if (isempty(rvalue
)) {
1385 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1386 c
->apparmor_profile_ignore
= false;
1390 if (rvalue
[0] == '-') {
1396 r
= unit_full_printf(u
, rvalue
, &k
);
1398 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1399 "Failed to resolve specifiers%s: %m",
1400 ignore
? ", ignoring" : "");
1401 return ignore
? 0 : -ENOEXEC
;
1404 free(c
->apparmor_profile
);
1405 c
->apparmor_profile
= k
;
1406 c
->apparmor_profile_ignore
= ignore
;
1411 int config_parse_exec_smack_process_label(
1413 const char *filename
,
1415 const char *section
,
1416 unsigned section_line
,
1423 ExecContext
*c
= data
;
1434 if (isempty(rvalue
)) {
1435 c
->smack_process_label
= mfree(c
->smack_process_label
);
1436 c
->smack_process_label_ignore
= false;
1440 if (rvalue
[0] == '-') {
1446 r
= unit_full_printf(u
, rvalue
, &k
);
1448 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1449 "Failed to resolve specifiers%s: %m",
1450 ignore
? ", ignoring" : "");
1451 return ignore
? 0 : -ENOEXEC
;
1454 free(c
->smack_process_label
);
1455 c
->smack_process_label
= k
;
1456 c
->smack_process_label_ignore
= ignore
;
1461 int config_parse_timer(const char *unit
,
1462 const char *filename
,
1464 const char *section
,
1465 unsigned section_line
,
1476 CalendarSpec
*c
= NULL
;
1478 _cleanup_free_
char *k
= NULL
;
1486 if (isempty(rvalue
)) {
1487 /* Empty assignment resets list */
1488 timer_free_values(t
);
1492 b
= timer_base_from_string(lvalue
);
1494 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1498 r
= unit_full_printf(u
, rvalue
, &k
);
1500 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1504 if (b
== TIMER_CALENDAR
) {
1505 if (calendar_spec_from_string(k
, &c
) < 0) {
1506 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1510 if (parse_sec(k
, &usec
) < 0) {
1511 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1516 v
= new0(TimerValue
, 1);
1518 calendar_spec_free(c
);
1524 v
->calendar_spec
= c
;
1526 LIST_PREPEND(value
, t
->values
, v
);
1531 int config_parse_trigger_unit(
1533 const char *filename
,
1535 const char *section
,
1536 unsigned section_line
,
1543 _cleanup_free_
char *p
= NULL
;
1553 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1554 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1558 r
= unit_name_printf(u
, rvalue
, &p
);
1560 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1564 type
= unit_name_to_type(p
);
1566 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1570 if (type
== u
->type
) {
1571 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1575 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1577 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1584 int config_parse_path_spec(const char *unit
,
1585 const char *filename
,
1587 const char *section
,
1588 unsigned section_line
,
1598 _cleanup_free_
char *k
= NULL
;
1606 if (isempty(rvalue
)) {
1607 /* Empty assignment clears list */
1612 b
= path_type_from_string(lvalue
);
1614 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1618 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1620 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1624 if (!path_is_absolute(k
)) {
1625 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1629 s
= new0(PathSpec
, 1);
1634 s
->path
= path_kill_slashes(k
);
1639 LIST_PREPEND(spec
, p
->specs
, s
);
1644 int config_parse_socket_service(
1646 const char *filename
,
1648 const char *section
,
1649 unsigned section_line
,
1656 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1657 _cleanup_free_
char *p
= NULL
;
1667 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1669 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1673 if (!endswith(p
, ".service")) {
1674 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1678 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1680 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1684 unit_ref_set(&s
->service
, x
);
1689 int config_parse_fdname(
1691 const char *filename
,
1693 const char *section
,
1694 unsigned section_line
,
1701 _cleanup_free_
char *p
= NULL
;
1710 if (isempty(rvalue
)) {
1711 s
->fdname
= mfree(s
->fdname
);
1715 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1717 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1721 if (!fdname_is_valid(p
)) {
1722 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1726 return free_and_replace(s
->fdname
, p
);
1729 int config_parse_service_sockets(
1731 const char *filename
,
1733 const char *section
,
1734 unsigned section_line
,
1752 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1754 r
= extract_first_word(&p
, &word
, NULL
, 0);
1760 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1764 r
= unit_name_printf(UNIT(s
), word
, &k
);
1766 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1770 if (!endswith(k
, ".socket")) {
1771 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1775 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1777 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1779 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1781 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1787 int config_parse_bus_name(
1789 const char *filename
,
1791 const char *section
,
1792 unsigned section_line
,
1799 _cleanup_free_
char *k
= NULL
;
1808 r
= unit_full_printf(u
, rvalue
, &k
);
1810 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1814 if (!service_name_is_valid(k
)) {
1815 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1819 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1822 int config_parse_service_timeout(
1824 const char *filename
,
1826 const char *section
,
1827 unsigned section_line
,
1834 Service
*s
= userdata
;
1843 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1845 r
= parse_sec(rvalue
, &usec
);
1847 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1851 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1852 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1853 * all other timeouts. */
1855 usec
= USEC_INFINITY
;
1857 if (!streq(lvalue
, "TimeoutStopSec")) {
1858 s
->start_timeout_defined
= true;
1859 s
->timeout_start_usec
= usec
;
1862 if (!streq(lvalue
, "TimeoutStartSec"))
1863 s
->timeout_stop_usec
= usec
;
1868 int config_parse_sec_fix_0(
1870 const char *filename
,
1872 const char *section
,
1873 unsigned section_line
,
1880 usec_t
*usec
= data
;
1888 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1889 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1892 r
= parse_sec_fix_0(rvalue
, usec
);
1894 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1901 int config_parse_user_group(
1903 const char *filename
,
1905 const char *section
,
1906 unsigned section_line
,
1913 char **user
= data
, *n
;
1922 if (isempty(rvalue
))
1925 _cleanup_free_
char *k
= NULL
;
1927 r
= unit_full_printf(u
, rvalue
, &k
);
1929 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
1933 if (!valid_user_group_name_or_id(k
)) {
1934 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1948 int config_parse_user_group_strv(
1950 const char *filename
,
1952 const char *section
,
1953 unsigned section_line
,
1960 char ***users
= data
;
1970 if (isempty(rvalue
)) {
1973 empty
= new0(char*, 1);
1985 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1987 r
= extract_first_word(&p
, &word
, NULL
, 0);
1993 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
1997 r
= unit_full_printf(u
, word
, &k
);
1999 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
2003 if (!valid_user_group_name_or_id(k
)) {
2004 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2008 r
= strv_push(users
, k
);
2018 int config_parse_working_directory(
2020 const char *filename
,
2022 const char *section
,
2023 unsigned section_line
,
2030 ExecContext
*c
= data
;
2041 if (rvalue
[0] == '-') {
2047 if (streq(rvalue
, "~")) {
2048 c
->working_directory_home
= true;
2049 c
->working_directory
= mfree(c
->working_directory
);
2051 _cleanup_free_
char *k
= NULL
;
2053 r
= unit_full_printf(u
, rvalue
, &k
);
2055 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2056 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2057 rvalue
, missing_ok
? ", ignoring" : "");
2058 return missing_ok
? 0 : -ENOEXEC
;
2061 path_kill_slashes(k
);
2063 if (!utf8_is_valid(k
)) {
2064 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2065 return missing_ok
? 0 : -ENOEXEC
;
2068 if (!path_is_absolute(k
)) {
2069 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2070 "Working directory path '%s' is not absolute%s.",
2071 rvalue
, missing_ok
? ", ignoring" : "");
2072 return missing_ok
? 0 : -ENOEXEC
;
2075 c
->working_directory_home
= false;
2076 free_and_replace(c
->working_directory
, k
);
2079 c
->working_directory_missing_ok
= missing_ok
;
2083 int config_parse_unit_env_file(const char *unit
,
2084 const char *filename
,
2086 const char *section
,
2087 unsigned section_line
,
2096 _cleanup_free_
char *n
= NULL
;
2104 if (isempty(rvalue
)) {
2105 /* Empty assignment frees the list */
2106 *env
= strv_free(*env
);
2110 r
= unit_full_printf(u
, rvalue
, &n
);
2112 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2116 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2117 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2121 r
= strv_extend(env
, n
);
2128 int config_parse_environ(
2130 const char *filename
,
2132 const char *section
,
2133 unsigned section_line
,
2150 if (isempty(rvalue
)) {
2151 /* Empty assignment resets the list */
2152 *env
= strv_free(*env
);
2156 for (p
= rvalue
;; ) {
2157 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2159 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2165 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2166 "Invalid syntax, ignoring: %s", rvalue
);
2171 r
= unit_full_printf(u
, word
, &k
);
2173 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2174 "Failed to resolve specifiers, ignoring: %s", word
);
2182 if (!env_assignment_is_valid(k
)) {
2183 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2184 "Invalid environment assignment, ignoring: %s", k
);
2188 r
= strv_env_replace(env
, k
);
2196 int config_parse_pass_environ(
2198 const char *filename
,
2200 const char *section
,
2201 unsigned section_line
,
2208 const char *whole_rvalue
= rvalue
;
2209 _cleanup_strv_free_
char **n
= NULL
;
2210 size_t nlen
= 0, nbufsize
= 0;
2211 char*** passenv
= data
;
2220 if (isempty(rvalue
)) {
2221 /* Empty assignment resets the list */
2222 *passenv
= strv_free(*passenv
);
2227 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2229 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2235 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2236 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2241 r
= unit_full_printf(u
, word
, &k
);
2243 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2244 "Failed to resolve specifiers, ignoring: %s", word
);
2252 if (!env_name_is_valid(k
)) {
2253 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2254 "Invalid environment name for %s, ignoring: %s", lvalue
, k
);
2258 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2267 r
= strv_extend_strv(passenv
, n
, true);
2275 int config_parse_unset_environ(
2277 const char *filename
,
2279 const char *section
,
2280 unsigned section_line
,
2287 _cleanup_strv_free_
char **n
= NULL
;
2288 const char *whole_rvalue
= rvalue
;
2289 size_t nlen
= 0, nbufsize
= 0;
2290 char*** unsetenv
= data
;
2299 if (isempty(rvalue
)) {
2300 /* Empty assignment resets the list */
2301 *unsetenv
= strv_free(*unsetenv
);
2306 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2308 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2314 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2315 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2320 r
= unit_full_printf(u
, word
, &k
);
2322 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2323 "Failed to resolve specifiers, ignoring: %s", word
);
2331 if (!env_assignment_is_valid(k
) && !env_name_is_valid(k
)) {
2332 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2333 "Invalid environment name or assignment %s, ignoring: %s", lvalue
, k
);
2337 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2346 r
= strv_extend_strv(unsetenv
, n
, true);
2354 int config_parse_ip_tos(const char *unit
,
2355 const char *filename
,
2357 const char *section
,
2358 unsigned section_line
,
2365 int *ip_tos
= data
, x
;
2372 x
= ip_tos_from_string(rvalue
);
2374 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2382 int config_parse_unit_condition_path(
2384 const char *filename
,
2386 const char *section
,
2387 unsigned section_line
,
2394 _cleanup_free_
char *p
= NULL
;
2395 Condition
**list
= data
, *c
;
2396 ConditionType t
= ltype
;
2397 bool trigger
, negate
;
2406 if (isempty(rvalue
)) {
2407 /* Empty assignment resets the list */
2408 *list
= condition_free_list(*list
);
2412 trigger
= rvalue
[0] == '|';
2416 negate
= rvalue
[0] == '!';
2420 r
= unit_full_printf(u
, rvalue
, &p
);
2422 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2426 if (!path_is_absolute(p
)) {
2427 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2431 c
= condition_new(t
, p
, trigger
, negate
);
2435 LIST_PREPEND(conditions
, *list
, c
);
2439 int config_parse_unit_condition_string(
2441 const char *filename
,
2443 const char *section
,
2444 unsigned section_line
,
2451 _cleanup_free_
char *s
= NULL
;
2452 Condition
**list
= data
, *c
;
2453 ConditionType t
= ltype
;
2454 bool trigger
, negate
;
2463 if (isempty(rvalue
)) {
2464 /* Empty assignment resets the list */
2465 *list
= condition_free_list(*list
);
2469 trigger
= rvalue
[0] == '|';
2473 negate
= rvalue
[0] == '!';
2477 r
= unit_full_printf(u
, rvalue
, &s
);
2479 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2483 c
= condition_new(t
, s
, trigger
, negate
);
2487 LIST_PREPEND(conditions
, *list
, c
);
2491 int config_parse_unit_condition_null(
2493 const char *filename
,
2495 const char *section
,
2496 unsigned section_line
,
2503 Condition
**list
= data
, *c
;
2504 bool trigger
, negate
;
2512 if (isempty(rvalue
)) {
2513 /* Empty assignment resets the list */
2514 *list
= condition_free_list(*list
);
2518 trigger
= rvalue
[0] == '|';
2522 negate
= rvalue
[0] == '!';
2526 b
= parse_boolean(rvalue
);
2528 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2535 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2539 LIST_PREPEND(conditions
, *list
, c
);
2543 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2544 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2546 int config_parse_unit_requires_mounts_for(
2548 const char *filename
,
2550 const char *section
,
2551 unsigned section_line
,
2567 for (p
= rvalue
;; ) {
2568 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2570 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2576 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2577 "Invalid syntax, ignoring: %s", rvalue
);
2581 if (!utf8_is_valid(word
)) {
2582 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2586 r
= unit_full_printf(u
, word
, &resolved
);
2588 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2592 r
= unit_require_mounts_for(u
, resolved
);
2594 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2600 int config_parse_documentation(const char *unit
,
2601 const char *filename
,
2603 const char *section
,
2604 unsigned section_line
,
2620 if (isempty(rvalue
)) {
2621 /* Empty assignment resets the list */
2622 u
->documentation
= strv_free(u
->documentation
);
2626 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2627 rvalue
, data
, userdata
);
2631 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2633 if (documentation_url_is_valid(*a
))
2636 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2648 static int syscall_filter_parse_one(
2650 const char *filename
,
2659 const SyscallFilterSet
*set
;
2662 set
= syscall_filter_set_find(t
);
2665 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2669 NULSTR_FOREACH(i
, set
->value
) {
2670 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2677 id
= seccomp_syscall_resolve_name(t
);
2678 if (id
== __NR_SCMP_ERROR
) {
2680 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2684 /* If we previously wanted to forbid a syscall and now
2685 * we want to allow it, then remove it from the list
2687 if (!invert
== c
->syscall_whitelist
) {
2688 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2694 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2700 int config_parse_syscall_filter(
2702 const char *filename
,
2704 const char *section
,
2705 unsigned section_line
,
2712 ExecContext
*c
= data
;
2714 bool invert
= false;
2723 if (isempty(rvalue
)) {
2724 /* Empty assignment resets the list */
2725 c
->syscall_filter
= set_free(c
->syscall_filter
);
2726 c
->syscall_whitelist
= false;
2730 if (rvalue
[0] == '~') {
2735 if (!c
->syscall_filter
) {
2736 c
->syscall_filter
= set_new(NULL
);
2737 if (!c
->syscall_filter
)
2741 /* Allow everything but the ones listed */
2742 c
->syscall_whitelist
= false;
2744 /* Allow nothing but the ones listed */
2745 c
->syscall_whitelist
= true;
2747 /* Accept default syscalls if we are on a whitelist */
2748 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2756 _cleanup_free_
char *word
= NULL
;
2758 r
= extract_first_word(&p
, &word
, NULL
, 0);
2764 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2768 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2776 int config_parse_syscall_archs(
2778 const char *filename
,
2780 const char *section
,
2781 unsigned section_line
,
2792 if (isempty(rvalue
)) {
2793 *archs
= set_free(*archs
);
2797 r
= set_ensure_allocated(archs
, NULL
);
2801 for (p
= rvalue
;;) {
2802 _cleanup_free_
char *word
= NULL
;
2805 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2811 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2812 "Invalid syntax, ignoring: %s", rvalue
);
2816 r
= seccomp_arch_from_string(word
, &a
);
2818 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2819 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2823 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2829 int config_parse_syscall_errno(
2831 const char *filename
,
2833 const char *section
,
2834 unsigned section_line
,
2841 ExecContext
*c
= data
;
2848 if (isempty(rvalue
)) {
2849 /* Empty assignment resets to KILL */
2850 c
->syscall_errno
= 0;
2854 e
= errno_from_name(rvalue
);
2856 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2860 c
->syscall_errno
= e
;
2864 int config_parse_address_families(
2866 const char *filename
,
2868 const char *section
,
2869 unsigned section_line
,
2876 ExecContext
*c
= data
;
2877 bool invert
= false;
2885 if (isempty(rvalue
)) {
2886 /* Empty assignment resets the list */
2887 c
->address_families
= set_free(c
->address_families
);
2888 c
->address_families_whitelist
= false;
2892 if (rvalue
[0] == '~') {
2897 if (!c
->address_families
) {
2898 c
->address_families
= set_new(NULL
);
2899 if (!c
->address_families
)
2902 c
->address_families_whitelist
= !invert
;
2905 for (p
= rvalue
;;) {
2906 _cleanup_free_
char *word
= NULL
;
2909 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2915 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2916 "Invalid syntax, ignoring: %s", rvalue
);
2920 af
= af_from_name(word
);
2922 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2923 "Failed to parse address family \"%s\", ignoring: %m", word
);
2927 /* If we previously wanted to forbid an address family and now
2928 * we want to allow it, then just remove it from the list.
2930 if (!invert
== c
->address_families_whitelist
) {
2931 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2935 set_remove(c
->address_families
, INT_TO_PTR(af
));
2939 int config_parse_restrict_namespaces(
2941 const char *filename
,
2943 const char *section
,
2944 unsigned section_line
,
2951 ExecContext
*c
= data
;
2952 bool invert
= false;
2955 if (isempty(rvalue
)) {
2956 /* Reset to the default. */
2957 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2961 if (rvalue
[0] == '~') {
2966 r
= parse_boolean(rvalue
);
2968 c
->restrict_namespaces
= 0;
2970 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2972 /* Not a boolean argument, in this case it's a list of namespace types. */
2974 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2976 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2982 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2988 int config_parse_unit_slice(
2990 const char *filename
,
2992 const char *section
,
2993 unsigned section_line
,
3000 _cleanup_free_
char *k
= NULL
;
3001 Unit
*u
= userdata
, *slice
= NULL
;
3009 r
= unit_name_printf(u
, rvalue
, &k
);
3011 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3015 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3017 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3021 r
= unit_set_slice(u
, slice
);
3023 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3030 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3032 int config_parse_cpu_weight(
3034 const char *filename
,
3036 const char *section
,
3037 unsigned section_line
,
3044 uint64_t *weight
= data
;
3051 r
= cg_weight_parse(rvalue
, weight
);
3053 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3060 int config_parse_cpu_shares(
3062 const char *filename
,
3064 const char *section
,
3065 unsigned section_line
,
3072 uint64_t *shares
= data
;
3079 r
= cg_cpu_shares_parse(rvalue
, shares
);
3081 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3088 int config_parse_cpu_quota(
3090 const char *filename
,
3092 const char *section
,
3093 unsigned section_line
,
3100 CGroupContext
*c
= data
;
3107 if (isempty(rvalue
)) {
3108 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3112 r
= parse_percent_unbounded(rvalue
);
3114 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3118 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3122 int config_parse_memory_limit(
3124 const char *filename
,
3126 const char *section
,
3127 unsigned section_line
,
3134 CGroupContext
*c
= data
;
3135 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3138 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3140 r
= parse_percent(rvalue
);
3142 r
= parse_size(rvalue
, 1024, &bytes
);
3144 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3148 bytes
= physical_memory_scale(r
, 100U);
3150 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3151 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3156 if (streq(lvalue
, "MemoryLow"))
3157 c
->memory_low
= bytes
;
3158 else if (streq(lvalue
, "MemoryHigh"))
3159 c
->memory_high
= bytes
;
3160 else if (streq(lvalue
, "MemoryMax"))
3161 c
->memory_max
= bytes
;
3162 else if (streq(lvalue
, "MemorySwapMax"))
3163 c
->memory_swap_max
= bytes
;
3164 else if (streq(lvalue
, "MemoryLimit"))
3165 c
->memory_limit
= bytes
;
3172 int config_parse_tasks_max(
3174 const char *filename
,
3176 const char *section
,
3177 unsigned section_line
,
3184 uint64_t *tasks_max
= data
, v
;
3188 if (isempty(rvalue
)) {
3189 *tasks_max
= u
->manager
->default_tasks_max
;
3193 if (streq(rvalue
, "infinity")) {
3194 *tasks_max
= CGROUP_LIMIT_MAX
;
3198 r
= parse_percent(rvalue
);
3200 r
= safe_atou64(rvalue
, &v
);
3202 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3206 v
= system_tasks_max_scale(r
, 100U);
3208 if (v
<= 0 || v
>= UINT64_MAX
) {
3209 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3217 int config_parse_device_allow(
3219 const char *filename
,
3221 const char *section
,
3222 unsigned section_line
,
3229 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3230 CGroupContext
*c
= data
;
3231 CGroupDeviceAllow
*a
;
3232 const char *m
= NULL
;
3236 if (isempty(rvalue
)) {
3237 while (c
->device_allow
)
3238 cgroup_context_free_device_allow(c
, c
->device_allow
);
3243 r
= unit_full_printf(userdata
, rvalue
, &t
);
3245 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3246 "Failed to resolve specifiers in %s, ignoring: %m",
3250 n
= strcspn(t
, WHITESPACE
);
3252 path
= strndup(t
, n
);
3256 if (!is_deviceallow_pattern(path
)) {
3257 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3261 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3265 if (!in_charset(m
, "rwm")) {
3266 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3270 a
= new0(CGroupDeviceAllow
, 1);
3276 a
->r
= !!strchr(m
, 'r');
3277 a
->w
= !!strchr(m
, 'w');
3278 a
->m
= !!strchr(m
, 'm');
3280 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3284 int config_parse_io_weight(
3286 const char *filename
,
3288 const char *section
,
3289 unsigned section_line
,
3296 uint64_t *weight
= data
;
3303 r
= cg_weight_parse(rvalue
, weight
);
3305 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3312 int config_parse_io_device_weight(
3314 const char *filename
,
3316 const char *section
,
3317 unsigned section_line
,
3324 _cleanup_free_
char *path
= NULL
;
3325 CGroupIODeviceWeight
*w
;
3326 CGroupContext
*c
= data
;
3336 if (isempty(rvalue
)) {
3337 while (c
->io_device_weights
)
3338 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3343 n
= strcspn(rvalue
, WHITESPACE
);
3344 weight
= rvalue
+ n
;
3345 weight
+= strspn(weight
, WHITESPACE
);
3347 if (isempty(weight
)) {
3348 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3352 path
= strndup(rvalue
, n
);
3356 if (!path_startswith(path
, "/dev")) {
3357 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3361 r
= cg_weight_parse(weight
, &u
);
3363 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3367 assert(u
!= CGROUP_WEIGHT_INVALID
);
3369 w
= new0(CGroupIODeviceWeight
, 1);
3378 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3382 int config_parse_io_limit(
3384 const char *filename
,
3386 const char *section
,
3387 unsigned section_line
,
3394 _cleanup_free_
char *path
= NULL
;
3395 CGroupIODeviceLimit
*l
= NULL
, *t
;
3396 CGroupContext
*c
= data
;
3397 CGroupIOLimitType type
;
3407 type
= cgroup_io_limit_type_from_string(lvalue
);
3410 if (isempty(rvalue
)) {
3411 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3412 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3416 n
= strcspn(rvalue
, WHITESPACE
);
3418 limit
+= strspn(limit
, WHITESPACE
);
3421 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3425 path
= strndup(rvalue
, n
);
3429 if (!path_startswith(path
, "/dev")) {
3430 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3434 if (streq("infinity", limit
)) {
3435 num
= CGROUP_LIMIT_MAX
;
3437 r
= parse_size(limit
, 1000, &num
);
3438 if (r
< 0 || num
<= 0) {
3439 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3444 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3445 if (path_equal(path
, t
->path
)) {
3452 CGroupIOLimitType ttype
;
3454 l
= new0(CGroupIODeviceLimit
, 1);
3460 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3461 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3463 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3466 l
->limits
[type
] = num
;
3471 int config_parse_blockio_weight(
3473 const char *filename
,
3475 const char *section
,
3476 unsigned section_line
,
3483 uint64_t *weight
= data
;
3490 r
= cg_blkio_weight_parse(rvalue
, weight
);
3492 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3499 int config_parse_blockio_device_weight(
3501 const char *filename
,
3503 const char *section
,
3504 unsigned section_line
,
3511 _cleanup_free_
char *path
= NULL
;
3512 CGroupBlockIODeviceWeight
*w
;
3513 CGroupContext
*c
= data
;
3523 if (isempty(rvalue
)) {
3524 while (c
->blockio_device_weights
)
3525 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3530 n
= strcspn(rvalue
, WHITESPACE
);
3531 weight
= rvalue
+ n
;
3532 weight
+= strspn(weight
, WHITESPACE
);
3534 if (isempty(weight
)) {
3535 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3539 path
= strndup(rvalue
, n
);
3543 if (!path_startswith(path
, "/dev")) {
3544 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3548 r
= cg_blkio_weight_parse(weight
, &u
);
3550 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3554 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3556 w
= new0(CGroupBlockIODeviceWeight
, 1);
3565 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3569 int config_parse_blockio_bandwidth(
3571 const char *filename
,
3573 const char *section
,
3574 unsigned section_line
,
3581 _cleanup_free_
char *path
= NULL
;
3582 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3583 CGroupContext
*c
= data
;
3584 const char *bandwidth
;
3594 read
= streq("BlockIOReadBandwidth", lvalue
);
3596 if (isempty(rvalue
)) {
3597 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3598 b
->rbps
= CGROUP_LIMIT_MAX
;
3599 b
->wbps
= CGROUP_LIMIT_MAX
;
3604 n
= strcspn(rvalue
, WHITESPACE
);
3605 bandwidth
= rvalue
+ n
;
3606 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3609 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3613 path
= strndup(rvalue
, n
);
3617 if (!path_startswith(path
, "/dev")) {
3618 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3622 r
= parse_size(bandwidth
, 1000, &bytes
);
3623 if (r
< 0 || bytes
<= 0) {
3624 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3628 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3629 if (path_equal(path
, t
->path
)) {
3636 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3642 b
->rbps
= CGROUP_LIMIT_MAX
;
3643 b
->wbps
= CGROUP_LIMIT_MAX
;
3645 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3656 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3658 int config_parse_job_mode_isolate(
3660 const char *filename
,
3662 const char *section
,
3663 unsigned section_line
,
3677 r
= parse_boolean(rvalue
);
3679 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3683 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3687 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3689 int config_parse_exec_directories(
3691 const char *filename
,
3693 const char *section
,
3694 unsigned section_line
,
3711 if (isempty(rvalue
)) {
3712 /* Empty assignment resets the list */
3713 *rt
= strv_free(*rt
);
3717 for (p
= rvalue
;;) {
3718 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3720 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3724 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3725 "Invalid syntax, ignoring: %s", rvalue
);
3731 r
= unit_full_printf(u
, word
, &k
);
3733 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3734 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3738 if (!path_is_safe(k
) || path_is_absolute(k
)) {
3739 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3740 "%s= path is not valid, ignoring assignment: %s", lvalue
, rvalue
);
3744 r
= strv_push(rt
, k
);
3751 int config_parse_set_status(
3753 const char *filename
,
3755 const char *section
,
3756 unsigned section_line
,
3764 const char *word
, *state
;
3766 ExitStatusSet
*status_set
= data
;
3773 /* Empty assignment resets the list */
3774 if (isempty(rvalue
)) {
3775 exit_status_set_free(status_set
);
3779 FOREACH_WORD(word
, l
, rvalue
, state
) {
3780 _cleanup_free_
char *temp
;
3784 temp
= strndup(word
, l
);
3788 r
= safe_atoi(temp
, &val
);
3790 val
= signal_from_string_try_harder(temp
);
3793 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3796 set
= &status_set
->signal
;
3798 if (val
< 0 || val
> 255) {
3799 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3802 set
= &status_set
->status
;
3805 r
= set_ensure_allocated(set
, NULL
);
3809 r
= set_put(*set
, INT_TO_PTR(val
));
3811 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3815 if (!isempty(state
))
3816 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3821 int config_parse_namespace_path_strv(
3823 const char *filename
,
3825 const char *section
,
3826 unsigned section_line
,
3843 if (isempty(rvalue
)) {
3844 /* Empty assignment resets the list */
3845 *sv
= strv_free(*sv
);
3851 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3853 bool ignore_enoent
= false, shall_prefix
= false;
3855 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3861 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3865 if (!utf8_is_valid(word
)) {
3866 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3871 if (startswith(w
, "-")) {
3872 ignore_enoent
= true;
3875 if (startswith(w
, "+")) {
3876 shall_prefix
= true;
3880 r
= unit_full_printf(u
, w
, &resolved
);
3882 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3886 if (!path_is_absolute(resolved
)) {
3887 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3891 path_kill_slashes(resolved
);
3893 joined
= strjoin(ignore_enoent
? "-" : "",
3894 shall_prefix
? "+" : "",
3897 r
= strv_push(sv
, joined
);
3907 int config_parse_bind_paths(
3909 const char *filename
,
3911 const char *section
,
3912 unsigned section_line
,
3919 ExecContext
*c
= data
;
3929 if (isempty(rvalue
)) {
3930 /* Empty assignment resets the list */
3931 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3932 c
->bind_mounts
= NULL
;
3933 c
->n_bind_mounts
= 0;
3939 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3940 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3941 char *s
= NULL
, *d
= NULL
;
3942 bool rbind
= true, ignore_enoent
= false;
3944 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3950 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3954 r
= unit_full_printf(u
, source
, &sresolved
);
3956 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3957 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3963 ignore_enoent
= true;
3967 if (!utf8_is_valid(s
)) {
3968 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3971 if (!path_is_absolute(s
)) {
3972 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3976 path_kill_slashes(s
);
3978 /* Optionally, the destination is specified. */
3979 if (p
&& p
[-1] == ':') {
3980 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3984 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3988 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3992 r
= unit_full_printf(u
, destination
, &dresolved
);
3994 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3995 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3999 if (!utf8_is_valid(dresolved
)) {
4000 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
4003 if (!path_is_absolute(dresolved
)) {
4004 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
4008 d
= path_kill_slashes(dresolved
);
4010 /* Optionally, there's also a short option string specified */
4011 if (p
&& p
[-1] == ':') {
4012 _cleanup_free_
char *options
= NULL
;
4014 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
4018 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4022 if (isempty(options
) || streq(options
, "rbind"))
4024 else if (streq(options
, "norbind"))
4027 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4034 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4038 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4040 .ignore_enoent
= ignore_enoent
,
4049 int config_parse_no_new_privileges(
4051 const char *filename
,
4053 const char *section
,
4054 unsigned section_line
,
4061 ExecContext
*c
= data
;
4069 k
= parse_boolean(rvalue
);
4071 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4075 c
->no_new_privileges
= k
;
4080 int config_parse_protect_home(
4082 const char *filename
,
4084 const char *section
,
4085 unsigned section_line
,
4092 ExecContext
*c
= data
;
4100 /* Our enum shall be a superset of booleans, hence first try
4101 * to parse as boolean, and then as enum */
4103 k
= parse_boolean(rvalue
);
4105 c
->protect_home
= PROTECT_HOME_YES
;
4107 c
->protect_home
= PROTECT_HOME_NO
;
4111 h
= protect_home_from_string(rvalue
);
4113 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4117 c
->protect_home
= h
;
4123 int config_parse_protect_system(
4125 const char *filename
,
4127 const char *section
,
4128 unsigned section_line
,
4135 ExecContext
*c
= data
;
4143 /* Our enum shall be a superset of booleans, hence first try
4144 * to parse as boolean, and then as enum */
4146 k
= parse_boolean(rvalue
);
4148 c
->protect_system
= PROTECT_SYSTEM_YES
;
4150 c
->protect_system
= PROTECT_SYSTEM_NO
;
4154 s
= protect_system_from_string(rvalue
);
4156 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4160 c
->protect_system
= s
;
4166 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode
, exec_keyring_mode
, ExecKeyringMode
, "Failed to parse keyring mode");
4168 #define FOLLOW_MAX 8
4170 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4181 /* This will update the filename pointer if the loaded file is
4182 * reached by a symlink. The old string will be freed. */
4185 char *target
, *name
;
4187 if (c
++ >= FOLLOW_MAX
)
4190 path_kill_slashes(*filename
);
4192 /* Add the file name we are currently looking at to
4193 * the names of this unit, but only if it is a valid
4195 name
= basename(*filename
);
4196 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4198 id
= set_get(names
, name
);
4204 r
= set_consume(names
, id
);
4210 /* Try to open the file name, but don't if its a symlink */
4211 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4218 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4219 r
= readlink_and_make_absolute(*filename
, &target
);
4227 f
= fdopen(fd
, "re");
4239 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4247 /* Let's try to add in all symlink names we found */
4248 while ((k
= set_steal_first(names
))) {
4250 /* First try to merge in the other name into our
4252 r
= unit_merge_by_name(*u
, k
);
4256 /* Hmm, we couldn't merge the other unit into
4257 * ours? Then let's try it the other way
4260 /* If the symlink name we are looking at is unit template, then
4261 we must search for instance of this template */
4262 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4263 _cleanup_free_
char *instance
= NULL
;
4265 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4269 other
= manager_get_unit((*u
)->manager
, instance
);
4271 other
= manager_get_unit((*u
)->manager
, k
);
4276 r
= unit_merge(other
, *u
);
4279 return merge_by_names(u
, names
, NULL
);
4287 unit_choose_id(*u
, id
);
4295 static int load_from_path(Unit
*u
, const char *path
) {
4296 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4297 _cleanup_fclose_
FILE *f
= NULL
;
4298 _cleanup_free_
char *filename
= NULL
;
4307 symlink_names
= set_new(&string_hash_ops
);
4311 if (path_is_absolute(path
)) {
4313 filename
= strdup(path
);
4317 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4319 filename
= mfree(filename
);
4327 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4329 /* Instead of opening the path right away, we manually
4330 * follow all symlinks and add their name to our unit
4331 * name set while doing so */
4332 filename
= path_make_absolute(path
, *p
);
4336 if (u
->manager
->unit_path_cache
&&
4337 !set_get(u
->manager
->unit_path_cache
, filename
))
4340 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4343 filename
= mfree(filename
);
4345 /* ENOENT means that the file is missing or is a dangling symlink.
4346 * ENOTDIR means that one of paths we expect to be is a directory
4347 * is not a directory, we should just ignore that.
4348 * EACCES means that the directory or file permissions are wrong.
4351 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4352 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4355 /* Empty the symlink names for the next run */
4356 set_clear_free(symlink_names
);
4361 /* Hmm, no suitable file found? */
4364 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4365 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4370 r
= merge_by_names(&merged
, symlink_names
, id
);
4375 u
->load_state
= UNIT_MERGED
;
4379 if (fstat(fileno(f
), &st
) < 0)
4382 if (null_or_empty(&st
)) {
4383 u
->load_state
= UNIT_MASKED
;
4384 u
->fragment_mtime
= 0;
4386 u
->load_state
= UNIT_LOADED
;
4387 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4389 /* Now, parse the file contents */
4390 r
= config_parse(u
->id
, filename
, f
,
4391 UNIT_VTABLE(u
)->sections
,
4392 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4393 false, true, false, u
);
4398 free(u
->fragment_path
);
4399 u
->fragment_path
= filename
;
4402 if (u
->source_path
) {
4403 if (stat(u
->source_path
, &st
) >= 0)
4404 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4406 u
->source_mtime
= 0;
4412 int unit_load_fragment(Unit
*u
) {
4418 assert(u
->load_state
== UNIT_STUB
);
4422 u
->load_state
= UNIT_LOADED
;
4426 /* First, try to find the unit under its id. We always look
4427 * for unit files in the default directories, to make it easy
4428 * to override things by placing things in /etc/systemd/system */
4429 r
= load_from_path(u
, u
->id
);
4433 /* Try to find an alias we can load this with */
4434 if (u
->load_state
== UNIT_STUB
) {
4435 SET_FOREACH(t
, u
->names
, i
) {
4440 r
= load_from_path(u
, t
);
4444 if (u
->load_state
!= UNIT_STUB
)
4449 /* And now, try looking for it under the suggested (originally linked) path */
4450 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4452 r
= load_from_path(u
, u
->fragment_path
);
4456 if (u
->load_state
== UNIT_STUB
)
4457 /* Hmm, this didn't work? Then let's get rid
4458 * of the fragment path stored for us, so that
4459 * we don't point to an invalid location. */
4460 u
->fragment_path
= mfree(u
->fragment_path
);
4463 /* Look for a template */
4464 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4465 _cleanup_free_
char *k
= NULL
;
4467 r
= unit_name_template(u
->id
, &k
);
4471 r
= load_from_path(u
, k
);
4474 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4478 if (u
->load_state
== UNIT_STUB
) {
4479 SET_FOREACH(t
, u
->names
, i
) {
4480 _cleanup_free_
char *z
= NULL
;
4485 r
= unit_name_template(t
, &z
);
4489 r
= load_from_path(u
, z
);
4493 if (u
->load_state
!= UNIT_STUB
)
4502 void unit_dump_config_items(FILE *f
) {
4503 static const struct {
4504 const ConfigParserCallback callback
;
4507 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !HAVE_SMACK || !HAVE_APPARMOR
4508 { config_parse_warn_compat
, "NOTSUPPORTED" },
4510 { config_parse_int
, "INTEGER" },
4511 { config_parse_unsigned
, "UNSIGNED" },
4512 { config_parse_iec_size
, "SIZE" },
4513 { config_parse_iec_uint64
, "SIZE" },
4514 { config_parse_si_size
, "SIZE" },
4515 { config_parse_bool
, "BOOLEAN" },
4516 { config_parse_string
, "STRING" },
4517 { config_parse_path
, "PATH" },
4518 { config_parse_unit_path_printf
, "PATH" },
4519 { config_parse_strv
, "STRING [...]" },
4520 { config_parse_exec_nice
, "NICE" },
4521 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4522 { config_parse_exec_io_class
, "IOCLASS" },
4523 { config_parse_exec_io_priority
, "IOPRIORITY" },
4524 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4525 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4526 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4527 { config_parse_mode
, "MODE" },
4528 { config_parse_unit_env_file
, "FILE" },
4529 { config_parse_exec_output
, "OUTPUT" },
4530 { config_parse_exec_input
, "INPUT" },
4531 { config_parse_log_facility
, "FACILITY" },
4532 { config_parse_log_level
, "LEVEL" },
4533 { config_parse_exec_secure_bits
, "SECUREBITS" },
4534 { config_parse_capability_set
, "BOUNDINGSET" },
4535 { config_parse_limit
, "LIMIT" },
4536 { config_parse_unit_deps
, "UNIT [...]" },
4537 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4538 { config_parse_service_type
, "SERVICETYPE" },
4539 { config_parse_service_restart
, "SERVICERESTART" },
4540 #if HAVE_SYSV_COMPAT
4541 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4543 { config_parse_kill_mode
, "KILLMODE" },
4544 { config_parse_signal
, "SIGNAL" },
4545 { config_parse_socket_listen
, "SOCKET [...]" },
4546 { config_parse_socket_bind
, "SOCKETBIND" },
4547 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4548 { config_parse_sec
, "SECONDS" },
4549 { config_parse_nsec
, "NANOSECONDS" },
4550 { config_parse_namespace_path_strv
, "PATH [...]" },
4551 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4552 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4553 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4554 { config_parse_unit_string_printf
, "STRING" },
4555 { config_parse_trigger_unit
, "UNIT" },
4556 { config_parse_timer
, "TIMER" },
4557 { config_parse_path_spec
, "PATH" },
4558 { config_parse_notify_access
, "ACCESS" },
4559 { config_parse_ip_tos
, "TOS" },
4560 { config_parse_unit_condition_path
, "CONDITION" },
4561 { config_parse_unit_condition_string
, "CONDITION" },
4562 { config_parse_unit_condition_null
, "CONDITION" },
4563 { config_parse_unit_slice
, "SLICE" },
4564 { config_parse_documentation
, "URL" },
4565 { config_parse_service_timeout
, "SECONDS" },
4566 { config_parse_emergency_action
, "ACTION" },
4567 { config_parse_set_status
, "STATUS" },
4568 { config_parse_service_sockets
, "SOCKETS" },
4569 { config_parse_environ
, "ENVIRON" },
4571 { config_parse_syscall_filter
, "SYSCALLS" },
4572 { config_parse_syscall_archs
, "ARCHS" },
4573 { config_parse_syscall_errno
, "ERRNO" },
4574 { config_parse_address_families
, "FAMILIES" },
4575 { config_parse_restrict_namespaces
, "NAMESPACES" },
4577 { config_parse_cpu_shares
, "SHARES" },
4578 { config_parse_cpu_weight
, "WEIGHT" },
4579 { config_parse_memory_limit
, "LIMIT" },
4580 { config_parse_device_allow
, "DEVICE" },
4581 { config_parse_device_policy
, "POLICY" },
4582 { config_parse_io_limit
, "LIMIT" },
4583 { config_parse_io_weight
, "WEIGHT" },
4584 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4585 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4586 { config_parse_blockio_weight
, "WEIGHT" },
4587 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4588 { config_parse_long
, "LONG" },
4589 { config_parse_socket_service
, "SERVICE" },
4591 { config_parse_exec_selinux_context
, "LABEL" },
4593 { config_parse_job_mode
, "MODE" },
4594 { config_parse_job_mode_isolate
, "BOOLEAN" },
4595 { config_parse_personality
, "PERSONALITY" },
4598 const char *prev
= NULL
;
4603 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4604 const char *rvalue
= "OTHER", *lvalue
;
4608 const ConfigPerfItem
*p
;
4610 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4612 dot
= strchr(i
, '.');
4613 lvalue
= dot
? dot
+ 1 : i
;
4617 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4621 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4624 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4625 if (p
->parse
== table
[j
].callback
) {
4626 rvalue
= table
[j
].rvalue
;
4630 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);