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 "signal-util.h"
62 #include "stat-util.h"
63 #include "string-util.h"
65 #include "unit-name.h"
66 #include "unit-printf.h"
68 #include "user-util.h"
72 int config_parse_warn_compat(
77 unsigned section_line
,
83 Disabled reason
= ltype
;
86 case DISABLED_CONFIGURATION
:
87 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
88 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
91 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
92 "Support for option %s= has been removed and it is ignored", lvalue
);
94 case DISABLED_EXPERIMENTAL
:
95 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
96 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
103 int config_parse_unit_deps(
105 const char *filename
,
108 unsigned section_line
,
115 UnitDependency d
= ltype
;
125 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
128 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
134 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
138 r
= unit_name_printf(u
, word
, &k
);
140 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
144 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
146 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
152 int config_parse_obsolete_unit_deps(
154 const char *filename
,
157 unsigned section_line
,
164 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
165 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
167 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
170 int config_parse_unit_string_printf(
172 const char *filename
,
175 unsigned section_line
,
182 _cleanup_free_
char *k
= NULL
;
191 r
= unit_full_printf(u
, rvalue
, &k
);
193 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
197 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
200 int config_parse_unit_strv_printf(
202 const char *filename
,
205 unsigned section_line
,
213 _cleanup_free_
char *k
= NULL
;
221 r
= unit_full_printf(u
, rvalue
, &k
);
223 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
227 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
230 int config_parse_unit_path_printf(
232 const char *filename
,
235 unsigned section_line
,
242 _cleanup_free_
char *k
= NULL
;
251 r
= unit_full_printf(u
, rvalue
, &k
);
253 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
257 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
260 int config_parse_unit_path_strv_printf(
262 const char *filename
,
265 unsigned section_line
,
283 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
285 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
291 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
292 "Invalid syntax, ignoring: %s", rvalue
);
296 r
= unit_full_printf(u
, word
, &k
);
298 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
299 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
303 if (!utf8_is_valid(k
)) {
304 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
308 if (!path_is_absolute(k
)) {
309 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
310 "Symlink path is not absolute: %s", k
);
314 path_kill_slashes(k
);
323 int config_parse_socket_listen(const char *unit
,
324 const char *filename
,
327 unsigned section_line
,
334 _cleanup_free_ SocketPort
*p
= NULL
;
346 if (isempty(rvalue
)) {
347 /* An empty assignment removes all ports */
348 socket_free_ports(s
);
352 p
= new0(SocketPort
, 1);
356 if (ltype
!= SOCKET_SOCKET
) {
359 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
361 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
365 path_kill_slashes(p
->path
);
367 } else if (streq(lvalue
, "ListenNetlink")) {
368 _cleanup_free_
char *k
= NULL
;
370 p
->type
= SOCKET_SOCKET
;
371 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
373 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
377 r
= socket_address_parse_netlink(&p
->address
, k
);
379 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
384 _cleanup_free_
char *k
= NULL
;
386 p
->type
= SOCKET_SOCKET
;
387 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
389 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
393 r
= socket_address_parse_and_warn(&p
->address
, k
);
395 if (r
!= -EAFNOSUPPORT
)
396 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
401 if (streq(lvalue
, "ListenStream"))
402 p
->address
.type
= SOCK_STREAM
;
403 else if (streq(lvalue
, "ListenDatagram"))
404 p
->address
.type
= SOCK_DGRAM
;
406 assert(streq(lvalue
, "ListenSequentialPacket"));
407 p
->address
.type
= SOCK_SEQPACKET
;
410 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
411 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
417 p
->auxiliary_fds
= NULL
;
418 p
->n_auxiliary_fds
= 0;
422 LIST_FIND_TAIL(port
, s
->ports
, tail
);
423 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
425 LIST_PREPEND(port
, s
->ports
, p
);
431 int config_parse_socket_protocol(const char *unit
,
432 const char *filename
,
435 unsigned section_line
,
450 if (streq(rvalue
, "udplite"))
451 s
->socket_protocol
= IPPROTO_UDPLITE
;
452 else if (streq(rvalue
, "sctp"))
453 s
->socket_protocol
= IPPROTO_SCTP
;
455 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
462 int config_parse_socket_bind(const char *unit
,
463 const char *filename
,
466 unsigned section_line
,
474 SocketAddressBindIPv6Only b
;
483 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
487 r
= parse_boolean(rvalue
);
489 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
493 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
495 s
->bind_ipv6_only
= b
;
500 int config_parse_exec_nice(
502 const char *filename
,
505 unsigned section_line
,
512 ExecContext
*c
= data
;
520 r
= parse_nice(rvalue
, &priority
);
523 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
525 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
536 int config_parse_exec_oom_score_adjust(const char* unit
,
537 const char *filename
,
540 unsigned section_line
,
547 ExecContext
*c
= data
;
555 r
= safe_atoi(rvalue
, &oa
);
557 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
561 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
562 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
566 c
->oom_score_adjust
= oa
;
567 c
->oom_score_adjust_set
= true;
572 int config_parse_exec(
574 const char *filename
,
577 unsigned section_line
,
584 ExecCommand
**e
= data
;
596 rvalue
+= strspn(rvalue
, WHITESPACE
);
598 if (isempty(rvalue
)) {
599 /* An empty assignment resets the list */
600 *e
= exec_command_free_list(*e
);
606 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
607 bool separate_argv0
= false, ignore
= false, privileged
= false;
608 _cleanup_free_ ExecCommand
*nce
= NULL
;
609 _cleanup_strv_free_
char **n
= NULL
;
610 size_t nlen
= 0, nbufsize
= 0;
615 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
621 /* We accept an absolute path as first argument.
622 * If it's prefixed with - and the path doesn't exist,
623 * we ignore it instead of erroring out;
624 * if it's prefixed with @, we allow overriding of argv[0];
625 * and if it's prefixed with +, it will be run with full privileges */
626 if (*f
== '-' && !ignore
)
628 else if (*f
== '@' && !separate_argv0
)
629 separate_argv0
= true;
630 else if (*f
== '+' && !privileged
)
637 r
= unit_full_printf(u
, f
, &path
);
639 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", f
);
644 /* First word is either "-" or "@" with no command. */
645 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty path in command line, ignoring: \"%s\"", rvalue
);
648 if (!string_is_safe(path
)) {
649 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path contains special characters, ignoring: %s", rvalue
);
652 if (!path_is_absolute(path
)) {
653 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path is not absolute, ignoring: %s", rvalue
);
656 if (endswith(path
, "/")) {
657 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path specifies a directory, ignoring: %s", rvalue
);
661 if (!separate_argv0
) {
664 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
674 path_kill_slashes(path
);
676 while (!isempty(p
)) {
677 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
679 /* Check explicitly for an unquoted semicolon as
680 * command separator token. */
681 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
683 p
+= strspn(p
, WHITESPACE
);
688 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
689 * extract_first_word() would return the same for all of those. */
690 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
694 p
+= strspn(p
, WHITESPACE
);
696 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
707 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
713 r
= unit_full_printf(u
, word
, &resolved
);
715 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to resolve unit specifiers on %s, ignoring: %m", word
);
719 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
721 n
[nlen
++] = resolved
;
727 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue
);
731 nce
= new0(ExecCommand
, 1);
737 nce
->ignore
= ignore
;
738 nce
->privileged
= privileged
;
740 exec_command_append_list(e
, nce
);
742 /* Do not _cleanup_free_ these. */
753 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
754 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
756 int config_parse_socket_bindtodevice(
758 const char *filename
,
761 unsigned section_line
,
776 if (rvalue
[0] && !streq(rvalue
, "*")) {
777 if (!ifname_valid(rvalue
)) {
778 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
788 free(s
->bind_to_device
);
789 s
->bind_to_device
= n
;
794 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
795 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
797 int config_parse_exec_input(const char *unit
,
798 const char *filename
,
801 unsigned section_line
,
807 ExecContext
*c
= data
;
816 name
= startswith(rvalue
, "fd:");
818 /* Strip prefix and validate fd name */
819 if (!fdname_is_valid(name
)) {
820 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
823 c
->std_input
= EXEC_INPUT_NAMED_FD
;
824 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
829 ExecInput ei
= exec_input_from_string(rvalue
);
830 if (ei
== _EXEC_INPUT_INVALID
)
831 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
838 int config_parse_exec_output(const char *unit
,
839 const char *filename
,
842 unsigned section_line
,
848 ExecContext
*c
= data
;
859 name
= startswith(rvalue
, "fd:");
861 /* Strip prefix and validate fd name */
862 if (!fdname_is_valid(name
)) {
863 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
866 eo
= EXEC_OUTPUT_NAMED_FD
;
868 eo
= exec_output_from_string(rvalue
);
869 if (eo
== _EXEC_OUTPUT_INVALID
) {
870 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
875 if (streq(lvalue
, "StandardOutput")) {
877 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
881 } else if (streq(lvalue
, "StandardError")) {
883 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
888 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
893 int config_parse_exec_io_class(const char *unit
,
894 const char *filename
,
897 unsigned section_line
,
904 ExecContext
*c
= data
;
912 x
= ioprio_class_from_string(rvalue
);
914 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
918 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
919 c
->ioprio_set
= true;
924 int config_parse_exec_io_priority(const char *unit
,
925 const char *filename
,
928 unsigned section_line
,
935 ExecContext
*c
= data
;
943 r
= ioprio_parse_priority(rvalue
, &i
);
945 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
949 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
950 c
->ioprio_set
= true;
955 int config_parse_exec_cpu_sched_policy(const char *unit
,
956 const char *filename
,
959 unsigned section_line
,
967 ExecContext
*c
= data
;
975 x
= sched_policy_from_string(rvalue
);
977 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
981 c
->cpu_sched_policy
= x
;
982 /* Moving to or from real-time policy? We need to adjust the priority */
983 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
984 c
->cpu_sched_set
= true;
989 int config_parse_exec_cpu_sched_prio(const char *unit
,
990 const char *filename
,
993 unsigned section_line
,
1000 ExecContext
*c
= data
;
1008 r
= safe_atoi(rvalue
, &i
);
1010 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1014 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1015 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1016 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1018 if (i
< min
|| i
> max
) {
1019 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1023 c
->cpu_sched_priority
= i
;
1024 c
->cpu_sched_set
= true;
1029 int config_parse_exec_cpu_affinity(const char *unit
,
1030 const char *filename
,
1032 const char *section
,
1033 unsigned section_line
,
1040 ExecContext
*c
= data
;
1041 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1049 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1054 CPU_FREE(c
->cpuset
);
1057 /* An empty assignment resets the CPU list */
1063 c
->cpuset_ncpus
= ncpus
;
1068 int config_parse_exec_secure_bits(const char *unit
,
1069 const char *filename
,
1071 const char *section
,
1072 unsigned section_line
,
1079 ExecContext
*c
= data
;
1088 if (isempty(rvalue
)) {
1089 /* An empty assignment resets the field */
1094 for (p
= rvalue
;;) {
1095 _cleanup_free_
char *word
= NULL
;
1097 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1103 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1104 "Invalid syntax, ignoring: %s", rvalue
);
1108 if (streq(word
, "keep-caps"))
1109 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
1110 else if (streq(word
, "keep-caps-locked"))
1111 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
1112 else if (streq(word
, "no-setuid-fixup"))
1113 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
1114 else if (streq(word
, "no-setuid-fixup-locked"))
1115 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
1116 else if (streq(word
, "noroot"))
1117 c
->secure_bits
|= 1<<SECURE_NOROOT
;
1118 else if (streq(word
, "noroot-locked"))
1119 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
1121 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
1122 "Failed to parse secure bit \"%s\", ignoring.", word
);
1128 int config_parse_capability_set(
1130 const char *filename
,
1132 const char *section
,
1133 unsigned section_line
,
1140 uint64_t *capability_set
= data
;
1141 uint64_t sum
= 0, initial
= 0;
1142 bool invert
= false;
1150 if (rvalue
[0] == '~') {
1155 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1156 initial
= CAP_ALL
; /* initialized to all bits on */
1157 /* else "AmbientCapabilities" initialized to all bits off */
1161 _cleanup_free_
char *word
= NULL
;
1164 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1170 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1174 cap
= capability_from_name(word
);
1176 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1180 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1183 sum
= invert
? ~sum
: sum
;
1185 if (sum
== 0 || *capability_set
== initial
)
1186 /* "" or uninitialized data -> replace */
1187 *capability_set
= sum
;
1189 /* previous data -> merge */
1190 *capability_set
|= sum
;
1195 int config_parse_limit(
1197 const char *filename
,
1199 const char *section
,
1200 unsigned section_line
,
1207 struct rlimit
**rl
= data
, d
= {};
1215 r
= rlimit_parse(ltype
, rvalue
, &d
);
1217 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1221 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1228 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1236 #ifdef HAVE_SYSV_COMPAT
1237 int config_parse_sysv_priority(const char *unit
,
1238 const char *filename
,
1240 const char *section
,
1241 unsigned section_line
,
1248 int *priority
= data
;
1256 r
= safe_atoi(rvalue
, &i
);
1257 if (r
< 0 || i
< 0) {
1258 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1262 *priority
= (int) i
;
1267 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1268 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1270 int config_parse_exec_mount_flags(
1272 const char *filename
,
1274 const char *section
,
1275 unsigned section_line
,
1283 ExecContext
*c
= data
;
1291 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1293 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1298 int config_parse_exec_selinux_context(
1300 const char *filename
,
1302 const char *section
,
1303 unsigned section_line
,
1310 ExecContext
*c
= data
;
1321 if (isempty(rvalue
)) {
1322 c
->selinux_context
= mfree(c
->selinux_context
);
1323 c
->selinux_context_ignore
= false;
1327 if (rvalue
[0] == '-') {
1333 r
= unit_full_printf(u
, rvalue
, &k
);
1335 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1339 free(c
->selinux_context
);
1340 c
->selinux_context
= k
;
1341 c
->selinux_context_ignore
= ignore
;
1346 int config_parse_exec_apparmor_profile(
1348 const char *filename
,
1350 const char *section
,
1351 unsigned section_line
,
1358 ExecContext
*c
= data
;
1369 if (isempty(rvalue
)) {
1370 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1371 c
->apparmor_profile_ignore
= false;
1375 if (rvalue
[0] == '-') {
1381 r
= unit_full_printf(u
, rvalue
, &k
);
1383 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1387 free(c
->apparmor_profile
);
1388 c
->apparmor_profile
= k
;
1389 c
->apparmor_profile_ignore
= ignore
;
1394 int config_parse_exec_smack_process_label(
1396 const char *filename
,
1398 const char *section
,
1399 unsigned section_line
,
1406 ExecContext
*c
= data
;
1417 if (isempty(rvalue
)) {
1418 c
->smack_process_label
= mfree(c
->smack_process_label
);
1419 c
->smack_process_label_ignore
= false;
1423 if (rvalue
[0] == '-') {
1429 r
= unit_full_printf(u
, rvalue
, &k
);
1431 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1435 free(c
->smack_process_label
);
1436 c
->smack_process_label
= k
;
1437 c
->smack_process_label_ignore
= ignore
;
1442 int config_parse_timer(const char *unit
,
1443 const char *filename
,
1445 const char *section
,
1446 unsigned section_line
,
1457 CalendarSpec
*c
= NULL
;
1459 _cleanup_free_
char *k
= NULL
;
1467 if (isempty(rvalue
)) {
1468 /* Empty assignment resets list */
1469 timer_free_values(t
);
1473 b
= timer_base_from_string(lvalue
);
1475 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1479 r
= unit_full_printf(u
, rvalue
, &k
);
1481 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1485 if (b
== TIMER_CALENDAR
) {
1486 if (calendar_spec_from_string(k
, &c
) < 0) {
1487 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1491 if (parse_sec(k
, &usec
) < 0) {
1492 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1497 v
= new0(TimerValue
, 1);
1499 calendar_spec_free(c
);
1505 v
->calendar_spec
= c
;
1507 LIST_PREPEND(value
, t
->values
, v
);
1512 int config_parse_trigger_unit(
1514 const char *filename
,
1516 const char *section
,
1517 unsigned section_line
,
1524 _cleanup_free_
char *p
= NULL
;
1534 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1535 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1539 r
= unit_name_printf(u
, rvalue
, &p
);
1541 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1545 type
= unit_name_to_type(p
);
1547 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1551 if (type
== u
->type
) {
1552 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1556 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1558 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1565 int config_parse_path_spec(const char *unit
,
1566 const char *filename
,
1568 const char *section
,
1569 unsigned section_line
,
1579 _cleanup_free_
char *k
= NULL
;
1587 if (isempty(rvalue
)) {
1588 /* Empty assignment clears list */
1593 b
= path_type_from_string(lvalue
);
1595 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1599 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1601 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1605 if (!path_is_absolute(k
)) {
1606 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1610 s
= new0(PathSpec
, 1);
1615 s
->path
= path_kill_slashes(k
);
1620 LIST_PREPEND(spec
, p
->specs
, s
);
1625 int config_parse_socket_service(
1627 const char *filename
,
1629 const char *section
,
1630 unsigned section_line
,
1637 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1638 _cleanup_free_
char *p
= NULL
;
1648 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1650 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1654 if (!endswith(p
, ".service")) {
1655 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1659 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1661 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1665 unit_ref_set(&s
->service
, x
);
1670 int config_parse_fdname(
1672 const char *filename
,
1674 const char *section
,
1675 unsigned section_line
,
1682 _cleanup_free_
char *p
= NULL
;
1691 if (isempty(rvalue
)) {
1692 s
->fdname
= mfree(s
->fdname
);
1696 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1698 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1702 if (!fdname_is_valid(p
)) {
1703 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1707 return free_and_replace(s
->fdname
, p
);
1710 int config_parse_service_sockets(
1712 const char *filename
,
1714 const char *section
,
1715 unsigned section_line
,
1733 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1735 r
= extract_first_word(&p
, &word
, NULL
, 0);
1741 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1745 r
= unit_name_printf(UNIT(s
), word
, &k
);
1747 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1751 if (!endswith(k
, ".socket")) {
1752 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1756 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1758 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1760 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1762 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1768 int config_parse_bus_name(
1770 const char *filename
,
1772 const char *section
,
1773 unsigned section_line
,
1780 _cleanup_free_
char *k
= NULL
;
1789 r
= unit_full_printf(u
, rvalue
, &k
);
1791 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1795 if (!service_name_is_valid(k
)) {
1796 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1800 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1803 int config_parse_service_timeout(
1805 const char *filename
,
1807 const char *section
,
1808 unsigned section_line
,
1815 Service
*s
= userdata
;
1824 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1826 r
= parse_sec(rvalue
, &usec
);
1828 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1832 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1833 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1834 * all other timeouts. */
1836 usec
= USEC_INFINITY
;
1838 if (!streq(lvalue
, "TimeoutStopSec")) {
1839 s
->start_timeout_defined
= true;
1840 s
->timeout_start_usec
= usec
;
1843 if (!streq(lvalue
, "TimeoutStartSec"))
1844 s
->timeout_stop_usec
= usec
;
1849 int config_parse_sec_fix_0(
1851 const char *filename
,
1853 const char *section
,
1854 unsigned section_line
,
1861 usec_t
*usec
= data
;
1869 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1870 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1873 r
= parse_sec(rvalue
, usec
);
1875 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1880 *usec
= USEC_INFINITY
;
1885 int config_parse_user_group(
1887 const char *filename
,
1889 const char *section
,
1890 unsigned section_line
,
1897 char **user
= data
, *n
;
1906 if (isempty(rvalue
))
1909 _cleanup_free_
char *k
= NULL
;
1911 r
= unit_full_printf(u
, rvalue
, &k
);
1913 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1917 if (!valid_user_group_name_or_id(k
)) {
1918 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1932 int config_parse_user_group_strv(
1934 const char *filename
,
1936 const char *section
,
1937 unsigned section_line
,
1944 char ***users
= data
;
1954 if (isempty(rvalue
)) {
1957 empty
= new0(char*, 1);
1969 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1971 r
= extract_first_word(&p
, &word
, NULL
, 0);
1977 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1981 r
= unit_full_printf(u
, word
, &k
);
1983 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", word
);
1987 if (!valid_user_group_name_or_id(k
)) {
1988 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1992 r
= strv_push(users
, k
);
2002 int config_parse_busname_service(
2004 const char *filename
,
2006 const char *section
,
2007 unsigned section_line
,
2014 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2018 _cleanup_free_
char *p
= NULL
;
2025 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
2027 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2031 if (!endswith(p
, ".service")) {
2032 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
2036 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
2038 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
2042 unit_ref_set(&n
->service
, x
);
2047 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
2049 int config_parse_bus_policy(
2051 const char *filename
,
2053 const char *section
,
2054 unsigned section_line
,
2061 _cleanup_free_ BusNamePolicy
*p
= NULL
;
2062 _cleanup_free_
char *id_str
= NULL
;
2063 BusName
*busname
= data
;
2071 p
= new0(BusNamePolicy
, 1);
2075 if (streq(lvalue
, "AllowUser"))
2076 p
->type
= BUSNAME_POLICY_TYPE_USER
;
2077 else if (streq(lvalue
, "AllowGroup"))
2078 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
2080 assert_not_reached("Unknown lvalue");
2082 id_str
= strdup(rvalue
);
2086 access_str
= strpbrk(id_str
, WHITESPACE
);
2088 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
2094 access_str
+= strspn(access_str
, WHITESPACE
);
2096 p
->access
= bus_policy_access_from_string(access_str
);
2097 if (p
->access
< 0) {
2098 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
2105 LIST_PREPEND(policy
, busname
->policy
, p
);
2111 int config_parse_working_directory(
2113 const char *filename
,
2115 const char *section
,
2116 unsigned section_line
,
2123 ExecContext
*c
= data
;
2134 if (rvalue
[0] == '-') {
2140 if (streq(rvalue
, "~")) {
2141 c
->working_directory_home
= true;
2142 c
->working_directory
= mfree(c
->working_directory
);
2144 _cleanup_free_
char *k
= NULL
;
2146 r
= unit_full_printf(u
, rvalue
, &k
);
2148 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2152 path_kill_slashes(k
);
2154 if (!utf8_is_valid(k
)) {
2155 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2159 if (!path_is_absolute(k
)) {
2160 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2164 free_and_replace(c
->working_directory
, k
);
2166 c
->working_directory_home
= false;
2169 c
->working_directory_missing_ok
= missing_ok
;
2173 int config_parse_unit_env_file(const char *unit
,
2174 const char *filename
,
2176 const char *section
,
2177 unsigned section_line
,
2186 _cleanup_free_
char *n
= NULL
;
2194 if (isempty(rvalue
)) {
2195 /* Empty assignment frees the list */
2196 *env
= strv_free(*env
);
2200 r
= unit_full_printf(u
, rvalue
, &n
);
2202 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2206 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2207 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2211 r
= strv_extend(env
, n
);
2218 int config_parse_environ(const char *unit
,
2219 const char *filename
,
2221 const char *section
,
2222 unsigned section_line
,
2239 if (isempty(rvalue
)) {
2240 /* Empty assignment resets the list */
2241 *env
= strv_free(*env
);
2245 for (p
= rvalue
;; ) {
2246 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2248 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2254 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2255 "Invalid syntax, ignoring: %s", rvalue
);
2260 r
= unit_full_printf(u
, word
, &k
);
2262 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2263 "Failed to resolve specifiers, ignoring: %s", k
);
2271 if (!env_assignment_is_valid(k
)) {
2272 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2273 "Invalid environment assignment, ignoring: %s", k
);
2277 r
= strv_env_replace(env
, k
);
2284 int config_parse_pass_environ(const char *unit
,
2285 const char *filename
,
2287 const char *section
,
2288 unsigned section_line
,
2295 const char *whole_rvalue
= rvalue
;
2296 char*** passenv
= data
;
2297 _cleanup_strv_free_
char **n
= NULL
;
2298 size_t nlen
= 0, nbufsize
= 0;
2306 if (isempty(rvalue
)) {
2307 /* Empty assignment resets the list */
2308 *passenv
= strv_free(*passenv
);
2313 _cleanup_free_
char *word
= NULL
;
2315 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2321 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2322 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2326 if (!env_name_is_valid(word
)) {
2327 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2328 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2332 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2340 r
= strv_extend_strv(passenv
, n
, true);
2348 int config_parse_ip_tos(const char *unit
,
2349 const char *filename
,
2351 const char *section
,
2352 unsigned section_line
,
2359 int *ip_tos
= data
, x
;
2366 x
= ip_tos_from_string(rvalue
);
2368 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2376 int config_parse_unit_condition_path(
2378 const char *filename
,
2380 const char *section
,
2381 unsigned section_line
,
2388 _cleanup_free_
char *p
= NULL
;
2389 Condition
**list
= data
, *c
;
2390 ConditionType t
= ltype
;
2391 bool trigger
, negate
;
2400 if (isempty(rvalue
)) {
2401 /* Empty assignment resets the list */
2402 *list
= condition_free_list(*list
);
2406 trigger
= rvalue
[0] == '|';
2410 negate
= rvalue
[0] == '!';
2414 r
= unit_full_printf(u
, rvalue
, &p
);
2416 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2420 if (!path_is_absolute(p
)) {
2421 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2425 c
= condition_new(t
, p
, trigger
, negate
);
2429 LIST_PREPEND(conditions
, *list
, c
);
2433 int config_parse_unit_condition_string(
2435 const char *filename
,
2437 const char *section
,
2438 unsigned section_line
,
2445 _cleanup_free_
char *s
= NULL
;
2446 Condition
**list
= data
, *c
;
2447 ConditionType t
= ltype
;
2448 bool trigger
, negate
;
2457 if (isempty(rvalue
)) {
2458 /* Empty assignment resets the list */
2459 *list
= condition_free_list(*list
);
2463 trigger
= rvalue
[0] == '|';
2467 negate
= rvalue
[0] == '!';
2471 r
= unit_full_printf(u
, rvalue
, &s
);
2473 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2477 c
= condition_new(t
, s
, trigger
, negate
);
2481 LIST_PREPEND(conditions
, *list
, c
);
2485 int config_parse_unit_condition_null(
2487 const char *filename
,
2489 const char *section
,
2490 unsigned section_line
,
2497 Condition
**list
= data
, *c
;
2498 bool trigger
, negate
;
2506 if (isempty(rvalue
)) {
2507 /* Empty assignment resets the list */
2508 *list
= condition_free_list(*list
);
2512 trigger
= rvalue
[0] == '|';
2516 negate
= rvalue
[0] == '!';
2520 b
= parse_boolean(rvalue
);
2522 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2529 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2533 LIST_PREPEND(conditions
, *list
, c
);
2537 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2538 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2540 int config_parse_unit_requires_mounts_for(
2542 const char *filename
,
2544 const char *section
,
2545 unsigned section_line
,
2561 for (p
= rvalue
;; ) {
2562 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2564 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2570 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2571 "Invalid syntax, ignoring: %s", rvalue
);
2575 if (!utf8_is_valid(word
)) {
2576 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2580 r
= unit_full_printf(u
, word
, &resolved
);
2582 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2586 r
= unit_require_mounts_for(u
, resolved
);
2588 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2594 int config_parse_documentation(const char *unit
,
2595 const char *filename
,
2597 const char *section
,
2598 unsigned section_line
,
2614 if (isempty(rvalue
)) {
2615 /* Empty assignment resets the list */
2616 u
->documentation
= strv_free(u
->documentation
);
2620 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2621 rvalue
, data
, userdata
);
2625 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2627 if (documentation_url_is_valid(*a
))
2630 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2642 static int syscall_filter_parse_one(
2644 const char *filename
,
2653 const SyscallFilterSet
*set
;
2656 set
= syscall_filter_set_find(t
);
2659 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2663 NULSTR_FOREACH(i
, set
->value
) {
2664 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2671 id
= seccomp_syscall_resolve_name(t
);
2672 if (id
== __NR_SCMP_ERROR
) {
2674 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2678 /* If we previously wanted to forbid a syscall and now
2679 * we want to allow it, then remove it from the list
2681 if (!invert
== c
->syscall_whitelist
) {
2682 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2688 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2694 int config_parse_syscall_filter(
2696 const char *filename
,
2698 const char *section
,
2699 unsigned section_line
,
2706 ExecContext
*c
= data
;
2708 bool invert
= false;
2717 if (isempty(rvalue
)) {
2718 /* Empty assignment resets the list */
2719 c
->syscall_filter
= set_free(c
->syscall_filter
);
2720 c
->syscall_whitelist
= false;
2724 if (rvalue
[0] == '~') {
2729 if (!c
->syscall_filter
) {
2730 c
->syscall_filter
= set_new(NULL
);
2731 if (!c
->syscall_filter
)
2735 /* Allow everything but the ones listed */
2736 c
->syscall_whitelist
= false;
2738 /* Allow nothing but the ones listed */
2739 c
->syscall_whitelist
= true;
2741 /* Accept default syscalls if we are on a whitelist */
2742 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2750 _cleanup_free_
char *word
= NULL
;
2752 r
= extract_first_word(&p
, &word
, NULL
, 0);
2758 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2762 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2770 int config_parse_syscall_archs(
2772 const char *filename
,
2774 const char *section
,
2775 unsigned section_line
,
2786 if (isempty(rvalue
)) {
2787 *archs
= set_free(*archs
);
2791 r
= set_ensure_allocated(archs
, NULL
);
2795 for (p
= rvalue
;;) {
2796 _cleanup_free_
char *word
= NULL
;
2799 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2805 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2806 "Invalid syntax, ignoring: %s", rvalue
);
2810 r
= seccomp_arch_from_string(word
, &a
);
2812 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2813 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2817 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2823 int config_parse_syscall_errno(
2825 const char *filename
,
2827 const char *section
,
2828 unsigned section_line
,
2835 ExecContext
*c
= data
;
2842 if (isempty(rvalue
)) {
2843 /* Empty assignment resets to KILL */
2844 c
->syscall_errno
= 0;
2848 e
= errno_from_name(rvalue
);
2850 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2854 c
->syscall_errno
= e
;
2858 int config_parse_address_families(
2860 const char *filename
,
2862 const char *section
,
2863 unsigned section_line
,
2870 ExecContext
*c
= data
;
2871 bool invert
= false;
2879 if (isempty(rvalue
)) {
2880 /* Empty assignment resets the list */
2881 c
->address_families
= set_free(c
->address_families
);
2882 c
->address_families_whitelist
= false;
2886 if (rvalue
[0] == '~') {
2891 if (!c
->address_families
) {
2892 c
->address_families
= set_new(NULL
);
2893 if (!c
->address_families
)
2896 c
->address_families_whitelist
= !invert
;
2899 for (p
= rvalue
;;) {
2900 _cleanup_free_
char *word
= NULL
;
2903 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2909 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2910 "Invalid syntax, ignoring: %s", rvalue
);
2914 af
= af_from_name(word
);
2916 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2917 "Failed to parse address family \"%s\", ignoring: %m", word
);
2921 /* If we previously wanted to forbid an address family and now
2922 * we want to allow it, then just remove it from the list.
2924 if (!invert
== c
->address_families_whitelist
) {
2925 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2929 set_remove(c
->address_families
, INT_TO_PTR(af
));
2933 int config_parse_restrict_namespaces(
2935 const char *filename
,
2937 const char *section
,
2938 unsigned section_line
,
2945 ExecContext
*c
= data
;
2946 bool invert
= false;
2949 if (isempty(rvalue
)) {
2950 /* Reset to the default. */
2951 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2955 if (rvalue
[0] == '~') {
2960 r
= parse_boolean(rvalue
);
2962 c
->restrict_namespaces
= 0;
2964 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2966 /* Not a boolean argument, in this case it's a list of namespace types. */
2968 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2970 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2976 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2982 int config_parse_unit_slice(
2984 const char *filename
,
2986 const char *section
,
2987 unsigned section_line
,
2994 _cleanup_free_
char *k
= NULL
;
2995 Unit
*u
= userdata
, *slice
= NULL
;
3003 r
= unit_name_printf(u
, rvalue
, &k
);
3005 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3009 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3011 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3015 r
= unit_set_slice(u
, slice
);
3017 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3024 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3026 int config_parse_cpu_weight(
3028 const char *filename
,
3030 const char *section
,
3031 unsigned section_line
,
3038 uint64_t *weight
= data
;
3045 r
= cg_weight_parse(rvalue
, weight
);
3047 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3054 int config_parse_cpu_shares(
3056 const char *filename
,
3058 const char *section
,
3059 unsigned section_line
,
3066 uint64_t *shares
= data
;
3073 r
= cg_cpu_shares_parse(rvalue
, shares
);
3075 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3082 int config_parse_cpu_quota(
3084 const char *filename
,
3086 const char *section
,
3087 unsigned section_line
,
3094 CGroupContext
*c
= data
;
3101 if (isempty(rvalue
)) {
3102 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3106 r
= parse_percent_unbounded(rvalue
);
3108 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3112 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3116 int config_parse_memory_limit(
3118 const char *filename
,
3120 const char *section
,
3121 unsigned section_line
,
3128 CGroupContext
*c
= data
;
3129 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3132 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3134 r
= parse_percent(rvalue
);
3136 r
= parse_size(rvalue
, 1024, &bytes
);
3138 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3142 bytes
= physical_memory_scale(r
, 100U);
3144 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3145 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3150 if (streq(lvalue
, "MemoryLow"))
3151 c
->memory_low
= bytes
;
3152 else if (streq(lvalue
, "MemoryHigh"))
3153 c
->memory_high
= bytes
;
3154 else if (streq(lvalue
, "MemoryMax"))
3155 c
->memory_max
= bytes
;
3156 else if (streq(lvalue
, "MemorySwapMax"))
3157 c
->memory_swap_max
= bytes
;
3158 else if (streq(lvalue
, "MemoryLimit"))
3159 c
->memory_limit
= bytes
;
3166 int config_parse_tasks_max(
3168 const char *filename
,
3170 const char *section
,
3171 unsigned section_line
,
3178 uint64_t *tasks_max
= data
, v
;
3182 if (isempty(rvalue
)) {
3183 *tasks_max
= u
->manager
->default_tasks_max
;
3187 if (streq(rvalue
, "infinity")) {
3188 *tasks_max
= CGROUP_LIMIT_MAX
;
3192 r
= parse_percent(rvalue
);
3194 r
= safe_atou64(rvalue
, &v
);
3196 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3200 v
= system_tasks_max_scale(r
, 100U);
3202 if (v
<= 0 || v
>= UINT64_MAX
) {
3203 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3211 int config_parse_device_allow(
3213 const char *filename
,
3215 const char *section
,
3216 unsigned section_line
,
3223 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3224 CGroupContext
*c
= data
;
3225 CGroupDeviceAllow
*a
;
3226 const char *m
= NULL
;
3230 if (isempty(rvalue
)) {
3231 while (c
->device_allow
)
3232 cgroup_context_free_device_allow(c
, c
->device_allow
);
3237 r
= unit_full_printf(userdata
, rvalue
, &t
);
3239 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3240 "Failed to resolve specifiers in %s, ignoring: %m",
3244 n
= strcspn(t
, WHITESPACE
);
3246 path
= strndup(t
, n
);
3250 if (!is_deviceallow_pattern(path
)) {
3251 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3255 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3259 if (!in_charset(m
, "rwm")) {
3260 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3264 a
= new0(CGroupDeviceAllow
, 1);
3270 a
->r
= !!strchr(m
, 'r');
3271 a
->w
= !!strchr(m
, 'w');
3272 a
->m
= !!strchr(m
, 'm');
3274 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3278 int config_parse_io_weight(
3280 const char *filename
,
3282 const char *section
,
3283 unsigned section_line
,
3290 uint64_t *weight
= data
;
3297 r
= cg_weight_parse(rvalue
, weight
);
3299 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3306 int config_parse_io_device_weight(
3308 const char *filename
,
3310 const char *section
,
3311 unsigned section_line
,
3318 _cleanup_free_
char *path
= NULL
;
3319 CGroupIODeviceWeight
*w
;
3320 CGroupContext
*c
= data
;
3330 if (isempty(rvalue
)) {
3331 while (c
->io_device_weights
)
3332 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3337 n
= strcspn(rvalue
, WHITESPACE
);
3338 weight
= rvalue
+ n
;
3339 weight
+= strspn(weight
, WHITESPACE
);
3341 if (isempty(weight
)) {
3342 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3346 path
= strndup(rvalue
, n
);
3350 if (!path_startswith(path
, "/dev")) {
3351 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3355 r
= cg_weight_parse(weight
, &u
);
3357 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3361 assert(u
!= CGROUP_WEIGHT_INVALID
);
3363 w
= new0(CGroupIODeviceWeight
, 1);
3372 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3376 int config_parse_io_limit(
3378 const char *filename
,
3380 const char *section
,
3381 unsigned section_line
,
3388 _cleanup_free_
char *path
= NULL
;
3389 CGroupIODeviceLimit
*l
= NULL
, *t
;
3390 CGroupContext
*c
= data
;
3391 CGroupIOLimitType type
;
3401 type
= cgroup_io_limit_type_from_string(lvalue
);
3404 if (isempty(rvalue
)) {
3405 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3406 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3410 n
= strcspn(rvalue
, WHITESPACE
);
3412 limit
+= strspn(limit
, WHITESPACE
);
3415 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3419 path
= strndup(rvalue
, n
);
3423 if (!path_startswith(path
, "/dev")) {
3424 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3428 if (streq("infinity", limit
)) {
3429 num
= CGROUP_LIMIT_MAX
;
3431 r
= parse_size(limit
, 1000, &num
);
3432 if (r
< 0 || num
<= 0) {
3433 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3438 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3439 if (path_equal(path
, t
->path
)) {
3446 CGroupIOLimitType ttype
;
3448 l
= new0(CGroupIODeviceLimit
, 1);
3454 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3455 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3457 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3460 l
->limits
[type
] = num
;
3465 int config_parse_blockio_weight(
3467 const char *filename
,
3469 const char *section
,
3470 unsigned section_line
,
3477 uint64_t *weight
= data
;
3484 r
= cg_blkio_weight_parse(rvalue
, weight
);
3486 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3493 int config_parse_blockio_device_weight(
3495 const char *filename
,
3497 const char *section
,
3498 unsigned section_line
,
3505 _cleanup_free_
char *path
= NULL
;
3506 CGroupBlockIODeviceWeight
*w
;
3507 CGroupContext
*c
= data
;
3517 if (isempty(rvalue
)) {
3518 while (c
->blockio_device_weights
)
3519 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3524 n
= strcspn(rvalue
, WHITESPACE
);
3525 weight
= rvalue
+ n
;
3526 weight
+= strspn(weight
, WHITESPACE
);
3528 if (isempty(weight
)) {
3529 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3533 path
= strndup(rvalue
, n
);
3537 if (!path_startswith(path
, "/dev")) {
3538 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3542 r
= cg_blkio_weight_parse(weight
, &u
);
3544 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3548 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3550 w
= new0(CGroupBlockIODeviceWeight
, 1);
3559 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3563 int config_parse_blockio_bandwidth(
3565 const char *filename
,
3567 const char *section
,
3568 unsigned section_line
,
3575 _cleanup_free_
char *path
= NULL
;
3576 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3577 CGroupContext
*c
= data
;
3578 const char *bandwidth
;
3588 read
= streq("BlockIOReadBandwidth", lvalue
);
3590 if (isempty(rvalue
)) {
3591 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3592 b
->rbps
= CGROUP_LIMIT_MAX
;
3593 b
->wbps
= CGROUP_LIMIT_MAX
;
3598 n
= strcspn(rvalue
, WHITESPACE
);
3599 bandwidth
= rvalue
+ n
;
3600 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3603 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3607 path
= strndup(rvalue
, n
);
3611 if (!path_startswith(path
, "/dev")) {
3612 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3616 r
= parse_size(bandwidth
, 1000, &bytes
);
3617 if (r
< 0 || bytes
<= 0) {
3618 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3622 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3623 if (path_equal(path
, t
->path
)) {
3630 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3636 b
->rbps
= CGROUP_LIMIT_MAX
;
3637 b
->wbps
= CGROUP_LIMIT_MAX
;
3639 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3650 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3652 int config_parse_job_mode_isolate(
3654 const char *filename
,
3656 const char *section
,
3657 unsigned section_line
,
3671 r
= parse_boolean(rvalue
);
3673 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3677 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3681 int config_parse_runtime_directory(
3683 const char *filename
,
3685 const char *section
,
3686 unsigned section_line
,
3703 if (isempty(rvalue
)) {
3704 /* Empty assignment resets the list */
3705 *rt
= strv_free(*rt
);
3709 for (p
= rvalue
;;) {
3710 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3712 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3718 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3719 "Invalid syntax, ignoring: %s", rvalue
);
3723 r
= unit_full_printf(u
, word
, &k
);
3725 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3726 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3730 if (!filename_is_valid(k
)) {
3731 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3732 "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3736 r
= strv_push(rt
, k
);
3743 int config_parse_set_status(
3745 const char *filename
,
3747 const char *section
,
3748 unsigned section_line
,
3756 const char *word
, *state
;
3758 ExitStatusSet
*status_set
= data
;
3765 /* Empty assignment resets the list */
3766 if (isempty(rvalue
)) {
3767 exit_status_set_free(status_set
);
3771 FOREACH_WORD(word
, l
, rvalue
, state
) {
3772 _cleanup_free_
char *temp
;
3776 temp
= strndup(word
, l
);
3780 r
= safe_atoi(temp
, &val
);
3782 val
= signal_from_string_try_harder(temp
);
3785 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3788 set
= &status_set
->signal
;
3790 if (val
< 0 || val
> 255) {
3791 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3794 set
= &status_set
->status
;
3797 r
= set_ensure_allocated(set
, NULL
);
3801 r
= set_put(*set
, INT_TO_PTR(val
));
3803 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3807 if (!isempty(state
))
3808 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3813 int config_parse_namespace_path_strv(
3815 const char *filename
,
3817 const char *section
,
3818 unsigned section_line
,
3835 if (isempty(rvalue
)) {
3836 /* Empty assignment resets the list */
3837 *sv
= strv_free(*sv
);
3843 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3845 bool ignore_enoent
= false, shall_prefix
= false;
3847 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3853 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3857 if (!utf8_is_valid(word
)) {
3858 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3863 if (startswith(w
, "-")) {
3864 ignore_enoent
= true;
3867 if (startswith(w
, "+")) {
3868 shall_prefix
= true;
3872 r
= unit_full_printf(u
, w
, &resolved
);
3874 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3878 if (!path_is_absolute(resolved
)) {
3879 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3883 path_kill_slashes(resolved
);
3885 joined
= strjoin(ignore_enoent
? "-" : "",
3886 shall_prefix
? "+" : "",
3889 r
= strv_push(sv
, joined
);
3899 int config_parse_bind_paths(
3901 const char *filename
,
3903 const char *section
,
3904 unsigned section_line
,
3911 ExecContext
*c
= data
;
3921 if (isempty(rvalue
)) {
3922 /* Empty assignment resets the list */
3923 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3924 c
->bind_mounts
= NULL
;
3925 c
->n_bind_mounts
= 0;
3931 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3932 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3933 char *s
= NULL
, *d
= NULL
;
3934 bool rbind
= true, ignore_enoent
= false;
3936 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3942 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3946 r
= unit_full_printf(u
, source
, &sresolved
);
3948 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3949 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3955 ignore_enoent
= true;
3959 if (!utf8_is_valid(s
)) {
3960 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3963 if (!path_is_absolute(s
)) {
3964 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3968 path_kill_slashes(s
);
3970 /* Optionally, the destination is specified. */
3971 if (p
&& p
[-1] == ':') {
3972 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3976 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3980 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3984 r
= unit_full_printf(u
, destination
, &dresolved
);
3986 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3987 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3991 if (!utf8_is_valid(dresolved
)) {
3992 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
3995 if (!path_is_absolute(dresolved
)) {
3996 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
4000 d
= path_kill_slashes(dresolved
);
4002 /* Optionally, there's also a short option string specified */
4003 if (p
&& p
[-1] == ':') {
4004 _cleanup_free_
char *options
= NULL
;
4006 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
4010 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4014 if (isempty(options
) || streq(options
, "rbind"))
4016 else if (streq(options
, "norbind"))
4019 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4026 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4030 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4032 .ignore_enoent
= ignore_enoent
,
4041 int config_parse_no_new_privileges(
4043 const char *filename
,
4045 const char *section
,
4046 unsigned section_line
,
4053 ExecContext
*c
= data
;
4061 k
= parse_boolean(rvalue
);
4063 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4067 c
->no_new_privileges
= k
;
4072 int config_parse_protect_home(
4074 const char *filename
,
4076 const char *section
,
4077 unsigned section_line
,
4084 ExecContext
*c
= data
;
4092 /* Our enum shall be a superset of booleans, hence first try
4093 * to parse as boolean, and then as enum */
4095 k
= parse_boolean(rvalue
);
4097 c
->protect_home
= PROTECT_HOME_YES
;
4099 c
->protect_home
= PROTECT_HOME_NO
;
4103 h
= protect_home_from_string(rvalue
);
4105 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4109 c
->protect_home
= h
;
4115 int config_parse_protect_system(
4117 const char *filename
,
4119 const char *section
,
4120 unsigned section_line
,
4127 ExecContext
*c
= data
;
4135 /* Our enum shall be a superset of booleans, hence first try
4136 * to parse as boolean, and then as enum */
4138 k
= parse_boolean(rvalue
);
4140 c
->protect_system
= PROTECT_SYSTEM_YES
;
4142 c
->protect_system
= PROTECT_SYSTEM_NO
;
4146 s
= protect_system_from_string(rvalue
);
4148 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4152 c
->protect_system
= s
;
4158 #define FOLLOW_MAX 8
4160 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4171 /* This will update the filename pointer if the loaded file is
4172 * reached by a symlink. The old string will be freed. */
4175 char *target
, *name
;
4177 if (c
++ >= FOLLOW_MAX
)
4180 path_kill_slashes(*filename
);
4182 /* Add the file name we are currently looking at to
4183 * the names of this unit, but only if it is a valid
4185 name
= basename(*filename
);
4186 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4188 id
= set_get(names
, name
);
4194 r
= set_consume(names
, id
);
4200 /* Try to open the file name, but don't if its a symlink */
4201 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4208 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4209 r
= readlink_and_make_absolute(*filename
, &target
);
4217 f
= fdopen(fd
, "re");
4229 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4237 /* Let's try to add in all symlink names we found */
4238 while ((k
= set_steal_first(names
))) {
4240 /* First try to merge in the other name into our
4242 r
= unit_merge_by_name(*u
, k
);
4246 /* Hmm, we couldn't merge the other unit into
4247 * ours? Then let's try it the other way
4250 /* If the symlink name we are looking at is unit template, then
4251 we must search for instance of this template */
4252 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4253 _cleanup_free_
char *instance
= NULL
;
4255 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4259 other
= manager_get_unit((*u
)->manager
, instance
);
4261 other
= manager_get_unit((*u
)->manager
, k
);
4266 r
= unit_merge(other
, *u
);
4269 return merge_by_names(u
, names
, NULL
);
4277 unit_choose_id(*u
, id
);
4285 static int load_from_path(Unit
*u
, const char *path
) {
4286 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4287 _cleanup_fclose_
FILE *f
= NULL
;
4288 _cleanup_free_
char *filename
= NULL
;
4297 symlink_names
= set_new(&string_hash_ops
);
4301 if (path_is_absolute(path
)) {
4303 filename
= strdup(path
);
4307 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4309 filename
= mfree(filename
);
4317 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4319 /* Instead of opening the path right away, we manually
4320 * follow all symlinks and add their name to our unit
4321 * name set while doing so */
4322 filename
= path_make_absolute(path
, *p
);
4326 if (u
->manager
->unit_path_cache
&&
4327 !set_get(u
->manager
->unit_path_cache
, filename
))
4330 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4333 filename
= mfree(filename
);
4335 /* ENOENT means that the file is missing or is a dangling symlink.
4336 * ENOTDIR means that one of paths we expect to be is a directory
4337 * is not a directory, we should just ignore that.
4338 * EACCES means that the directory or file permissions are wrong.
4341 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4342 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4345 /* Empty the symlink names for the next run */
4346 set_clear_free(symlink_names
);
4351 /* Hmm, no suitable file found? */
4354 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4355 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4360 r
= merge_by_names(&merged
, symlink_names
, id
);
4365 u
->load_state
= UNIT_MERGED
;
4369 if (fstat(fileno(f
), &st
) < 0)
4372 if (null_or_empty(&st
)) {
4373 u
->load_state
= UNIT_MASKED
;
4374 u
->fragment_mtime
= 0;
4376 u
->load_state
= UNIT_LOADED
;
4377 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4379 /* Now, parse the file contents */
4380 r
= config_parse(u
->id
, filename
, f
,
4381 UNIT_VTABLE(u
)->sections
,
4382 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4383 false, true, false, u
);
4388 free(u
->fragment_path
);
4389 u
->fragment_path
= filename
;
4392 if (u
->source_path
) {
4393 if (stat(u
->source_path
, &st
) >= 0)
4394 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4396 u
->source_mtime
= 0;
4402 int unit_load_fragment(Unit
*u
) {
4408 assert(u
->load_state
== UNIT_STUB
);
4412 u
->load_state
= UNIT_LOADED
;
4416 /* First, try to find the unit under its id. We always look
4417 * for unit files in the default directories, to make it easy
4418 * to override things by placing things in /etc/systemd/system */
4419 r
= load_from_path(u
, u
->id
);
4423 /* Try to find an alias we can load this with */
4424 if (u
->load_state
== UNIT_STUB
) {
4425 SET_FOREACH(t
, u
->names
, i
) {
4430 r
= load_from_path(u
, t
);
4434 if (u
->load_state
!= UNIT_STUB
)
4439 /* And now, try looking for it under the suggested (originally linked) path */
4440 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4442 r
= load_from_path(u
, u
->fragment_path
);
4446 if (u
->load_state
== UNIT_STUB
)
4447 /* Hmm, this didn't work? Then let's get rid
4448 * of the fragment path stored for us, so that
4449 * we don't point to an invalid location. */
4450 u
->fragment_path
= mfree(u
->fragment_path
);
4453 /* Look for a template */
4454 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4455 _cleanup_free_
char *k
= NULL
;
4457 r
= unit_name_template(u
->id
, &k
);
4461 r
= load_from_path(u
, k
);
4465 if (u
->load_state
== UNIT_STUB
) {
4466 SET_FOREACH(t
, u
->names
, i
) {
4467 _cleanup_free_
char *z
= NULL
;
4472 r
= unit_name_template(t
, &z
);
4476 r
= load_from_path(u
, z
);
4480 if (u
->load_state
!= UNIT_STUB
)
4489 void unit_dump_config_items(FILE *f
) {
4490 static const struct {
4491 const ConfigParserCallback callback
;
4494 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4495 { config_parse_warn_compat
, "NOTSUPPORTED" },
4497 { config_parse_int
, "INTEGER" },
4498 { config_parse_unsigned
, "UNSIGNED" },
4499 { config_parse_iec_size
, "SIZE" },
4500 { config_parse_iec_uint64
, "SIZE" },
4501 { config_parse_si_size
, "SIZE" },
4502 { config_parse_bool
, "BOOLEAN" },
4503 { config_parse_string
, "STRING" },
4504 { config_parse_path
, "PATH" },
4505 { config_parse_unit_path_printf
, "PATH" },
4506 { config_parse_strv
, "STRING [...]" },
4507 { config_parse_exec_nice
, "NICE" },
4508 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4509 { config_parse_exec_io_class
, "IOCLASS" },
4510 { config_parse_exec_io_priority
, "IOPRIORITY" },
4511 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4512 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4513 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4514 { config_parse_mode
, "MODE" },
4515 { config_parse_unit_env_file
, "FILE" },
4516 { config_parse_exec_output
, "OUTPUT" },
4517 { config_parse_exec_input
, "INPUT" },
4518 { config_parse_log_facility
, "FACILITY" },
4519 { config_parse_log_level
, "LEVEL" },
4520 { config_parse_exec_secure_bits
, "SECUREBITS" },
4521 { config_parse_capability_set
, "BOUNDINGSET" },
4522 { config_parse_limit
, "LIMIT" },
4523 { config_parse_unit_deps
, "UNIT [...]" },
4524 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4525 { config_parse_service_type
, "SERVICETYPE" },
4526 { config_parse_service_restart
, "SERVICERESTART" },
4527 #ifdef HAVE_SYSV_COMPAT
4528 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4530 { config_parse_kill_mode
, "KILLMODE" },
4531 { config_parse_signal
, "SIGNAL" },
4532 { config_parse_socket_listen
, "SOCKET [...]" },
4533 { config_parse_socket_bind
, "SOCKETBIND" },
4534 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4535 { config_parse_sec
, "SECONDS" },
4536 { config_parse_nsec
, "NANOSECONDS" },
4537 { config_parse_namespace_path_strv
, "PATH [...]" },
4538 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4539 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4540 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4541 { config_parse_unit_string_printf
, "STRING" },
4542 { config_parse_trigger_unit
, "UNIT" },
4543 { config_parse_timer
, "TIMER" },
4544 { config_parse_path_spec
, "PATH" },
4545 { config_parse_notify_access
, "ACCESS" },
4546 { config_parse_ip_tos
, "TOS" },
4547 { config_parse_unit_condition_path
, "CONDITION" },
4548 { config_parse_unit_condition_string
, "CONDITION" },
4549 { config_parse_unit_condition_null
, "CONDITION" },
4550 { config_parse_unit_slice
, "SLICE" },
4551 { config_parse_documentation
, "URL" },
4552 { config_parse_service_timeout
, "SECONDS" },
4553 { config_parse_emergency_action
, "ACTION" },
4554 { config_parse_set_status
, "STATUS" },
4555 { config_parse_service_sockets
, "SOCKETS" },
4556 { config_parse_environ
, "ENVIRON" },
4558 { config_parse_syscall_filter
, "SYSCALLS" },
4559 { config_parse_syscall_archs
, "ARCHS" },
4560 { config_parse_syscall_errno
, "ERRNO" },
4561 { config_parse_address_families
, "FAMILIES" },
4562 { config_parse_restrict_namespaces
, "NAMESPACES" },
4564 { config_parse_cpu_shares
, "SHARES" },
4565 { config_parse_cpu_weight
, "WEIGHT" },
4566 { config_parse_memory_limit
, "LIMIT" },
4567 { config_parse_device_allow
, "DEVICE" },
4568 { config_parse_device_policy
, "POLICY" },
4569 { config_parse_io_limit
, "LIMIT" },
4570 { config_parse_io_weight
, "WEIGHT" },
4571 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4572 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4573 { config_parse_blockio_weight
, "WEIGHT" },
4574 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4575 { config_parse_long
, "LONG" },
4576 { config_parse_socket_service
, "SERVICE" },
4578 { config_parse_exec_selinux_context
, "LABEL" },
4580 { config_parse_job_mode
, "MODE" },
4581 { config_parse_job_mode_isolate
, "BOOLEAN" },
4582 { config_parse_personality
, "PERSONALITY" },
4585 const char *prev
= NULL
;
4590 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4591 const char *rvalue
= "OTHER", *lvalue
;
4595 const ConfigPerfItem
*p
;
4597 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4599 dot
= strchr(i
, '.');
4600 lvalue
= dot
? dot
+ 1 : i
;
4604 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4608 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4611 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4612 if (p
->parse
== table
[j
].callback
) {
4613 rvalue
= table
[j
].rvalue
;
4617 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);