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_fix_0(rvalue
, usec
);
1875 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1882 int config_parse_user_group(
1884 const char *filename
,
1886 const char *section
,
1887 unsigned section_line
,
1894 char **user
= data
, *n
;
1903 if (isempty(rvalue
))
1906 _cleanup_free_
char *k
= NULL
;
1908 r
= unit_full_printf(u
, rvalue
, &k
);
1910 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1914 if (!valid_user_group_name_or_id(k
)) {
1915 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1929 int config_parse_user_group_strv(
1931 const char *filename
,
1933 const char *section
,
1934 unsigned section_line
,
1941 char ***users
= data
;
1951 if (isempty(rvalue
)) {
1954 empty
= new0(char*, 1);
1966 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1968 r
= extract_first_word(&p
, &word
, NULL
, 0);
1974 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1978 r
= unit_full_printf(u
, word
, &k
);
1980 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", word
);
1984 if (!valid_user_group_name_or_id(k
)) {
1985 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1989 r
= strv_push(users
, k
);
1999 int config_parse_busname_service(
2001 const char *filename
,
2003 const char *section
,
2004 unsigned section_line
,
2011 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2015 _cleanup_free_
char *p
= NULL
;
2022 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
2024 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2028 if (!endswith(p
, ".service")) {
2029 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
2033 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
2035 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
2039 unit_ref_set(&n
->service
, x
);
2044 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
2046 int config_parse_bus_policy(
2048 const char *filename
,
2050 const char *section
,
2051 unsigned section_line
,
2058 _cleanup_free_ BusNamePolicy
*p
= NULL
;
2059 _cleanup_free_
char *id_str
= NULL
;
2060 BusName
*busname
= data
;
2068 p
= new0(BusNamePolicy
, 1);
2072 if (streq(lvalue
, "AllowUser"))
2073 p
->type
= BUSNAME_POLICY_TYPE_USER
;
2074 else if (streq(lvalue
, "AllowGroup"))
2075 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
2077 assert_not_reached("Unknown lvalue");
2079 id_str
= strdup(rvalue
);
2083 access_str
= strpbrk(id_str
, WHITESPACE
);
2085 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
2091 access_str
+= strspn(access_str
, WHITESPACE
);
2093 p
->access
= bus_policy_access_from_string(access_str
);
2094 if (p
->access
< 0) {
2095 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
2102 LIST_PREPEND(policy
, busname
->policy
, p
);
2108 int config_parse_working_directory(
2110 const char *filename
,
2112 const char *section
,
2113 unsigned section_line
,
2120 ExecContext
*c
= data
;
2131 if (rvalue
[0] == '-') {
2137 if (streq(rvalue
, "~")) {
2138 c
->working_directory_home
= true;
2139 c
->working_directory
= mfree(c
->working_directory
);
2141 _cleanup_free_
char *k
= NULL
;
2143 r
= unit_full_printf(u
, rvalue
, &k
);
2145 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2149 path_kill_slashes(k
);
2151 if (!utf8_is_valid(k
)) {
2152 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2156 if (!path_is_absolute(k
)) {
2157 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2161 free_and_replace(c
->working_directory
, k
);
2163 c
->working_directory_home
= false;
2166 c
->working_directory_missing_ok
= missing_ok
;
2170 int config_parse_unit_env_file(const char *unit
,
2171 const char *filename
,
2173 const char *section
,
2174 unsigned section_line
,
2183 _cleanup_free_
char *n
= NULL
;
2191 if (isempty(rvalue
)) {
2192 /* Empty assignment frees the list */
2193 *env
= strv_free(*env
);
2197 r
= unit_full_printf(u
, rvalue
, &n
);
2199 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2203 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2204 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2208 r
= strv_extend(env
, n
);
2215 int config_parse_environ(const char *unit
,
2216 const char *filename
,
2218 const char *section
,
2219 unsigned section_line
,
2236 if (isempty(rvalue
)) {
2237 /* Empty assignment resets the list */
2238 *env
= strv_free(*env
);
2242 for (p
= rvalue
;; ) {
2243 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2245 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2251 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2252 "Invalid syntax, ignoring: %s", rvalue
);
2257 r
= unit_full_printf(u
, word
, &k
);
2259 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2260 "Failed to resolve specifiers, ignoring: %s", k
);
2268 if (!env_assignment_is_valid(k
)) {
2269 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2270 "Invalid environment assignment, ignoring: %s", k
);
2274 r
= strv_env_replace(env
, k
);
2281 int config_parse_pass_environ(const char *unit
,
2282 const char *filename
,
2284 const char *section
,
2285 unsigned section_line
,
2292 const char *whole_rvalue
= rvalue
;
2293 char*** passenv
= data
;
2294 _cleanup_strv_free_
char **n
= NULL
;
2295 size_t nlen
= 0, nbufsize
= 0;
2303 if (isempty(rvalue
)) {
2304 /* Empty assignment resets the list */
2305 *passenv
= strv_free(*passenv
);
2310 _cleanup_free_
char *word
= NULL
;
2312 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2318 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2319 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2323 if (!env_name_is_valid(word
)) {
2324 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2325 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2329 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2337 r
= strv_extend_strv(passenv
, n
, true);
2345 int config_parse_ip_tos(const char *unit
,
2346 const char *filename
,
2348 const char *section
,
2349 unsigned section_line
,
2356 int *ip_tos
= data
, x
;
2363 x
= ip_tos_from_string(rvalue
);
2365 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2373 int config_parse_unit_condition_path(
2375 const char *filename
,
2377 const char *section
,
2378 unsigned section_line
,
2385 _cleanup_free_
char *p
= NULL
;
2386 Condition
**list
= data
, *c
;
2387 ConditionType t
= ltype
;
2388 bool trigger
, negate
;
2397 if (isempty(rvalue
)) {
2398 /* Empty assignment resets the list */
2399 *list
= condition_free_list(*list
);
2403 trigger
= rvalue
[0] == '|';
2407 negate
= rvalue
[0] == '!';
2411 r
= unit_full_printf(u
, rvalue
, &p
);
2413 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2417 if (!path_is_absolute(p
)) {
2418 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2422 c
= condition_new(t
, p
, trigger
, negate
);
2426 LIST_PREPEND(conditions
, *list
, c
);
2430 int config_parse_unit_condition_string(
2432 const char *filename
,
2434 const char *section
,
2435 unsigned section_line
,
2442 _cleanup_free_
char *s
= NULL
;
2443 Condition
**list
= data
, *c
;
2444 ConditionType t
= ltype
;
2445 bool trigger
, negate
;
2454 if (isempty(rvalue
)) {
2455 /* Empty assignment resets the list */
2456 *list
= condition_free_list(*list
);
2460 trigger
= rvalue
[0] == '|';
2464 negate
= rvalue
[0] == '!';
2468 r
= unit_full_printf(u
, rvalue
, &s
);
2470 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2474 c
= condition_new(t
, s
, trigger
, negate
);
2478 LIST_PREPEND(conditions
, *list
, c
);
2482 int config_parse_unit_condition_null(
2484 const char *filename
,
2486 const char *section
,
2487 unsigned section_line
,
2494 Condition
**list
= data
, *c
;
2495 bool trigger
, negate
;
2503 if (isempty(rvalue
)) {
2504 /* Empty assignment resets the list */
2505 *list
= condition_free_list(*list
);
2509 trigger
= rvalue
[0] == '|';
2513 negate
= rvalue
[0] == '!';
2517 b
= parse_boolean(rvalue
);
2519 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2526 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2530 LIST_PREPEND(conditions
, *list
, c
);
2534 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2535 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2537 int config_parse_unit_requires_mounts_for(
2539 const char *filename
,
2541 const char *section
,
2542 unsigned section_line
,
2558 for (p
= rvalue
;; ) {
2559 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2561 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2567 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2568 "Invalid syntax, ignoring: %s", rvalue
);
2572 if (!utf8_is_valid(word
)) {
2573 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2577 r
= unit_full_printf(u
, word
, &resolved
);
2579 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2583 r
= unit_require_mounts_for(u
, resolved
);
2585 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2591 int config_parse_documentation(const char *unit
,
2592 const char *filename
,
2594 const char *section
,
2595 unsigned section_line
,
2611 if (isempty(rvalue
)) {
2612 /* Empty assignment resets the list */
2613 u
->documentation
= strv_free(u
->documentation
);
2617 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2618 rvalue
, data
, userdata
);
2622 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2624 if (documentation_url_is_valid(*a
))
2627 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2639 static int syscall_filter_parse_one(
2641 const char *filename
,
2650 const SyscallFilterSet
*set
;
2653 set
= syscall_filter_set_find(t
);
2656 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2660 NULSTR_FOREACH(i
, set
->value
) {
2661 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2668 id
= seccomp_syscall_resolve_name(t
);
2669 if (id
== __NR_SCMP_ERROR
) {
2671 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2675 /* If we previously wanted to forbid a syscall and now
2676 * we want to allow it, then remove it from the list
2678 if (!invert
== c
->syscall_whitelist
) {
2679 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2685 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2691 int config_parse_syscall_filter(
2693 const char *filename
,
2695 const char *section
,
2696 unsigned section_line
,
2703 ExecContext
*c
= data
;
2705 bool invert
= false;
2714 if (isempty(rvalue
)) {
2715 /* Empty assignment resets the list */
2716 c
->syscall_filter
= set_free(c
->syscall_filter
);
2717 c
->syscall_whitelist
= false;
2721 if (rvalue
[0] == '~') {
2726 if (!c
->syscall_filter
) {
2727 c
->syscall_filter
= set_new(NULL
);
2728 if (!c
->syscall_filter
)
2732 /* Allow everything but the ones listed */
2733 c
->syscall_whitelist
= false;
2735 /* Allow nothing but the ones listed */
2736 c
->syscall_whitelist
= true;
2738 /* Accept default syscalls if we are on a whitelist */
2739 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2747 _cleanup_free_
char *word
= NULL
;
2749 r
= extract_first_word(&p
, &word
, NULL
, 0);
2755 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2759 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2767 int config_parse_syscall_archs(
2769 const char *filename
,
2771 const char *section
,
2772 unsigned section_line
,
2783 if (isempty(rvalue
)) {
2784 *archs
= set_free(*archs
);
2788 r
= set_ensure_allocated(archs
, NULL
);
2792 for (p
= rvalue
;;) {
2793 _cleanup_free_
char *word
= NULL
;
2796 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2802 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2803 "Invalid syntax, ignoring: %s", rvalue
);
2807 r
= seccomp_arch_from_string(word
, &a
);
2809 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2810 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2814 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2820 int config_parse_syscall_errno(
2822 const char *filename
,
2824 const char *section
,
2825 unsigned section_line
,
2832 ExecContext
*c
= data
;
2839 if (isempty(rvalue
)) {
2840 /* Empty assignment resets to KILL */
2841 c
->syscall_errno
= 0;
2845 e
= errno_from_name(rvalue
);
2847 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2851 c
->syscall_errno
= e
;
2855 int config_parse_address_families(
2857 const char *filename
,
2859 const char *section
,
2860 unsigned section_line
,
2867 ExecContext
*c
= data
;
2868 bool invert
= false;
2876 if (isempty(rvalue
)) {
2877 /* Empty assignment resets the list */
2878 c
->address_families
= set_free(c
->address_families
);
2879 c
->address_families_whitelist
= false;
2883 if (rvalue
[0] == '~') {
2888 if (!c
->address_families
) {
2889 c
->address_families
= set_new(NULL
);
2890 if (!c
->address_families
)
2893 c
->address_families_whitelist
= !invert
;
2896 for (p
= rvalue
;;) {
2897 _cleanup_free_
char *word
= NULL
;
2900 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2906 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2907 "Invalid syntax, ignoring: %s", rvalue
);
2911 af
= af_from_name(word
);
2913 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2914 "Failed to parse address family \"%s\", ignoring: %m", word
);
2918 /* If we previously wanted to forbid an address family and now
2919 * we want to allow it, then just remove it from the list.
2921 if (!invert
== c
->address_families_whitelist
) {
2922 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2926 set_remove(c
->address_families
, INT_TO_PTR(af
));
2930 int config_parse_restrict_namespaces(
2932 const char *filename
,
2934 const char *section
,
2935 unsigned section_line
,
2942 ExecContext
*c
= data
;
2943 bool invert
= false;
2946 if (isempty(rvalue
)) {
2947 /* Reset to the default. */
2948 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2952 if (rvalue
[0] == '~') {
2957 r
= parse_boolean(rvalue
);
2959 c
->restrict_namespaces
= 0;
2961 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2963 /* Not a boolean argument, in this case it's a list of namespace types. */
2965 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2967 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2973 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2979 int config_parse_unit_slice(
2981 const char *filename
,
2983 const char *section
,
2984 unsigned section_line
,
2991 _cleanup_free_
char *k
= NULL
;
2992 Unit
*u
= userdata
, *slice
= NULL
;
3000 r
= unit_name_printf(u
, rvalue
, &k
);
3002 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3006 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3008 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3012 r
= unit_set_slice(u
, slice
);
3014 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3021 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3023 int config_parse_cpu_weight(
3025 const char *filename
,
3027 const char *section
,
3028 unsigned section_line
,
3035 uint64_t *weight
= data
;
3042 r
= cg_weight_parse(rvalue
, weight
);
3044 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3051 int config_parse_cpu_shares(
3053 const char *filename
,
3055 const char *section
,
3056 unsigned section_line
,
3063 uint64_t *shares
= data
;
3070 r
= cg_cpu_shares_parse(rvalue
, shares
);
3072 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3079 int config_parse_cpu_quota(
3081 const char *filename
,
3083 const char *section
,
3084 unsigned section_line
,
3091 CGroupContext
*c
= data
;
3098 if (isempty(rvalue
)) {
3099 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3103 r
= parse_percent_unbounded(rvalue
);
3105 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3109 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3113 int config_parse_memory_limit(
3115 const char *filename
,
3117 const char *section
,
3118 unsigned section_line
,
3125 CGroupContext
*c
= data
;
3126 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3129 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3131 r
= parse_percent(rvalue
);
3133 r
= parse_size(rvalue
, 1024, &bytes
);
3135 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3139 bytes
= physical_memory_scale(r
, 100U);
3141 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3142 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3147 if (streq(lvalue
, "MemoryLow"))
3148 c
->memory_low
= bytes
;
3149 else if (streq(lvalue
, "MemoryHigh"))
3150 c
->memory_high
= bytes
;
3151 else if (streq(lvalue
, "MemoryMax"))
3152 c
->memory_max
= bytes
;
3153 else if (streq(lvalue
, "MemorySwapMax"))
3154 c
->memory_swap_max
= bytes
;
3155 else if (streq(lvalue
, "MemoryLimit"))
3156 c
->memory_limit
= bytes
;
3163 int config_parse_tasks_max(
3165 const char *filename
,
3167 const char *section
,
3168 unsigned section_line
,
3175 uint64_t *tasks_max
= data
, v
;
3179 if (isempty(rvalue
)) {
3180 *tasks_max
= u
->manager
->default_tasks_max
;
3184 if (streq(rvalue
, "infinity")) {
3185 *tasks_max
= CGROUP_LIMIT_MAX
;
3189 r
= parse_percent(rvalue
);
3191 r
= safe_atou64(rvalue
, &v
);
3193 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3197 v
= system_tasks_max_scale(r
, 100U);
3199 if (v
<= 0 || v
>= UINT64_MAX
) {
3200 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3208 int config_parse_device_allow(
3210 const char *filename
,
3212 const char *section
,
3213 unsigned section_line
,
3220 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3221 CGroupContext
*c
= data
;
3222 CGroupDeviceAllow
*a
;
3223 const char *m
= NULL
;
3227 if (isempty(rvalue
)) {
3228 while (c
->device_allow
)
3229 cgroup_context_free_device_allow(c
, c
->device_allow
);
3234 r
= unit_full_printf(userdata
, rvalue
, &t
);
3236 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3237 "Failed to resolve specifiers in %s, ignoring: %m",
3241 n
= strcspn(t
, WHITESPACE
);
3243 path
= strndup(t
, n
);
3247 if (!is_deviceallow_pattern(path
)) {
3248 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3252 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3256 if (!in_charset(m
, "rwm")) {
3257 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3261 a
= new0(CGroupDeviceAllow
, 1);
3267 a
->r
= !!strchr(m
, 'r');
3268 a
->w
= !!strchr(m
, 'w');
3269 a
->m
= !!strchr(m
, 'm');
3271 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3275 int config_parse_io_weight(
3277 const char *filename
,
3279 const char *section
,
3280 unsigned section_line
,
3287 uint64_t *weight
= data
;
3294 r
= cg_weight_parse(rvalue
, weight
);
3296 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3303 int config_parse_io_device_weight(
3305 const char *filename
,
3307 const char *section
,
3308 unsigned section_line
,
3315 _cleanup_free_
char *path
= NULL
;
3316 CGroupIODeviceWeight
*w
;
3317 CGroupContext
*c
= data
;
3327 if (isempty(rvalue
)) {
3328 while (c
->io_device_weights
)
3329 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3334 n
= strcspn(rvalue
, WHITESPACE
);
3335 weight
= rvalue
+ n
;
3336 weight
+= strspn(weight
, WHITESPACE
);
3338 if (isempty(weight
)) {
3339 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3343 path
= strndup(rvalue
, n
);
3347 if (!path_startswith(path
, "/dev")) {
3348 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3352 r
= cg_weight_parse(weight
, &u
);
3354 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3358 assert(u
!= CGROUP_WEIGHT_INVALID
);
3360 w
= new0(CGroupIODeviceWeight
, 1);
3369 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3373 int config_parse_io_limit(
3375 const char *filename
,
3377 const char *section
,
3378 unsigned section_line
,
3385 _cleanup_free_
char *path
= NULL
;
3386 CGroupIODeviceLimit
*l
= NULL
, *t
;
3387 CGroupContext
*c
= data
;
3388 CGroupIOLimitType type
;
3398 type
= cgroup_io_limit_type_from_string(lvalue
);
3401 if (isempty(rvalue
)) {
3402 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3403 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3407 n
= strcspn(rvalue
, WHITESPACE
);
3409 limit
+= strspn(limit
, WHITESPACE
);
3412 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3416 path
= strndup(rvalue
, n
);
3420 if (!path_startswith(path
, "/dev")) {
3421 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3425 if (streq("infinity", limit
)) {
3426 num
= CGROUP_LIMIT_MAX
;
3428 r
= parse_size(limit
, 1000, &num
);
3429 if (r
< 0 || num
<= 0) {
3430 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3435 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3436 if (path_equal(path
, t
->path
)) {
3443 CGroupIOLimitType ttype
;
3445 l
= new0(CGroupIODeviceLimit
, 1);
3451 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3452 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3454 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3457 l
->limits
[type
] = num
;
3462 int config_parse_blockio_weight(
3464 const char *filename
,
3466 const char *section
,
3467 unsigned section_line
,
3474 uint64_t *weight
= data
;
3481 r
= cg_blkio_weight_parse(rvalue
, weight
);
3483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3490 int config_parse_blockio_device_weight(
3492 const char *filename
,
3494 const char *section
,
3495 unsigned section_line
,
3502 _cleanup_free_
char *path
= NULL
;
3503 CGroupBlockIODeviceWeight
*w
;
3504 CGroupContext
*c
= data
;
3514 if (isempty(rvalue
)) {
3515 while (c
->blockio_device_weights
)
3516 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3521 n
= strcspn(rvalue
, WHITESPACE
);
3522 weight
= rvalue
+ n
;
3523 weight
+= strspn(weight
, WHITESPACE
);
3525 if (isempty(weight
)) {
3526 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3530 path
= strndup(rvalue
, n
);
3534 if (!path_startswith(path
, "/dev")) {
3535 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3539 r
= cg_blkio_weight_parse(weight
, &u
);
3541 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3545 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3547 w
= new0(CGroupBlockIODeviceWeight
, 1);
3556 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3560 int config_parse_blockio_bandwidth(
3562 const char *filename
,
3564 const char *section
,
3565 unsigned section_line
,
3572 _cleanup_free_
char *path
= NULL
;
3573 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3574 CGroupContext
*c
= data
;
3575 const char *bandwidth
;
3585 read
= streq("BlockIOReadBandwidth", lvalue
);
3587 if (isempty(rvalue
)) {
3588 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3589 b
->rbps
= CGROUP_LIMIT_MAX
;
3590 b
->wbps
= CGROUP_LIMIT_MAX
;
3595 n
= strcspn(rvalue
, WHITESPACE
);
3596 bandwidth
= rvalue
+ n
;
3597 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3600 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3604 path
= strndup(rvalue
, n
);
3608 if (!path_startswith(path
, "/dev")) {
3609 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3613 r
= parse_size(bandwidth
, 1000, &bytes
);
3614 if (r
< 0 || bytes
<= 0) {
3615 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3619 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3620 if (path_equal(path
, t
->path
)) {
3627 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3633 b
->rbps
= CGROUP_LIMIT_MAX
;
3634 b
->wbps
= CGROUP_LIMIT_MAX
;
3636 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3647 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3649 int config_parse_job_mode_isolate(
3651 const char *filename
,
3653 const char *section
,
3654 unsigned section_line
,
3668 r
= parse_boolean(rvalue
);
3670 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3674 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3678 int config_parse_runtime_directory(
3680 const char *filename
,
3682 const char *section
,
3683 unsigned section_line
,
3700 if (isempty(rvalue
)) {
3701 /* Empty assignment resets the list */
3702 *rt
= strv_free(*rt
);
3706 for (p
= rvalue
;;) {
3707 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3709 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3715 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3716 "Invalid syntax, ignoring: %s", rvalue
);
3720 r
= unit_full_printf(u
, word
, &k
);
3722 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3723 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3727 if (!filename_is_valid(k
)) {
3728 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3729 "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3733 r
= strv_push(rt
, k
);
3740 int config_parse_set_status(
3742 const char *filename
,
3744 const char *section
,
3745 unsigned section_line
,
3753 const char *word
, *state
;
3755 ExitStatusSet
*status_set
= data
;
3762 /* Empty assignment resets the list */
3763 if (isempty(rvalue
)) {
3764 exit_status_set_free(status_set
);
3768 FOREACH_WORD(word
, l
, rvalue
, state
) {
3769 _cleanup_free_
char *temp
;
3773 temp
= strndup(word
, l
);
3777 r
= safe_atoi(temp
, &val
);
3779 val
= signal_from_string_try_harder(temp
);
3782 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3785 set
= &status_set
->signal
;
3787 if (val
< 0 || val
> 255) {
3788 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3791 set
= &status_set
->status
;
3794 r
= set_ensure_allocated(set
, NULL
);
3798 r
= set_put(*set
, INT_TO_PTR(val
));
3800 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3804 if (!isempty(state
))
3805 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3810 int config_parse_namespace_path_strv(
3812 const char *filename
,
3814 const char *section
,
3815 unsigned section_line
,
3832 if (isempty(rvalue
)) {
3833 /* Empty assignment resets the list */
3834 *sv
= strv_free(*sv
);
3840 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3842 bool ignore_enoent
= false, shall_prefix
= false;
3844 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3850 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3854 if (!utf8_is_valid(word
)) {
3855 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3860 if (startswith(w
, "-")) {
3861 ignore_enoent
= true;
3864 if (startswith(w
, "+")) {
3865 shall_prefix
= true;
3869 r
= unit_full_printf(u
, w
, &resolved
);
3871 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3875 if (!path_is_absolute(resolved
)) {
3876 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3880 path_kill_slashes(resolved
);
3882 joined
= strjoin(ignore_enoent
? "-" : "",
3883 shall_prefix
? "+" : "",
3886 r
= strv_push(sv
, joined
);
3896 int config_parse_bind_paths(
3898 const char *filename
,
3900 const char *section
,
3901 unsigned section_line
,
3908 ExecContext
*c
= data
;
3918 if (isempty(rvalue
)) {
3919 /* Empty assignment resets the list */
3920 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3921 c
->bind_mounts
= NULL
;
3922 c
->n_bind_mounts
= 0;
3928 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3929 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3930 char *s
= NULL
, *d
= NULL
;
3931 bool rbind
= true, ignore_enoent
= false;
3933 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3939 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3943 r
= unit_full_printf(u
, source
, &sresolved
);
3945 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3946 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3952 ignore_enoent
= true;
3956 if (!utf8_is_valid(s
)) {
3957 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3960 if (!path_is_absolute(s
)) {
3961 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3965 path_kill_slashes(s
);
3967 /* Optionally, the destination is specified. */
3968 if (p
&& p
[-1] == ':') {
3969 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3973 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3977 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3981 r
= unit_full_printf(u
, destination
, &dresolved
);
3983 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3984 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3988 if (!utf8_is_valid(dresolved
)) {
3989 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
3992 if (!path_is_absolute(dresolved
)) {
3993 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
3997 d
= path_kill_slashes(dresolved
);
3999 /* Optionally, there's also a short option string specified */
4000 if (p
&& p
[-1] == ':') {
4001 _cleanup_free_
char *options
= NULL
;
4003 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
4007 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4011 if (isempty(options
) || streq(options
, "rbind"))
4013 else if (streq(options
, "norbind"))
4016 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4023 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4027 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4029 .ignore_enoent
= ignore_enoent
,
4038 int config_parse_no_new_privileges(
4040 const char *filename
,
4042 const char *section
,
4043 unsigned section_line
,
4050 ExecContext
*c
= data
;
4058 k
= parse_boolean(rvalue
);
4060 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4064 c
->no_new_privileges
= k
;
4069 int config_parse_protect_home(
4071 const char *filename
,
4073 const char *section
,
4074 unsigned section_line
,
4081 ExecContext
*c
= data
;
4089 /* Our enum shall be a superset of booleans, hence first try
4090 * to parse as boolean, and then as enum */
4092 k
= parse_boolean(rvalue
);
4094 c
->protect_home
= PROTECT_HOME_YES
;
4096 c
->protect_home
= PROTECT_HOME_NO
;
4100 h
= protect_home_from_string(rvalue
);
4102 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4106 c
->protect_home
= h
;
4112 int config_parse_protect_system(
4114 const char *filename
,
4116 const char *section
,
4117 unsigned section_line
,
4124 ExecContext
*c
= data
;
4132 /* Our enum shall be a superset of booleans, hence first try
4133 * to parse as boolean, and then as enum */
4135 k
= parse_boolean(rvalue
);
4137 c
->protect_system
= PROTECT_SYSTEM_YES
;
4139 c
->protect_system
= PROTECT_SYSTEM_NO
;
4143 s
= protect_system_from_string(rvalue
);
4145 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4149 c
->protect_system
= s
;
4155 #define FOLLOW_MAX 8
4157 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4168 /* This will update the filename pointer if the loaded file is
4169 * reached by a symlink. The old string will be freed. */
4172 char *target
, *name
;
4174 if (c
++ >= FOLLOW_MAX
)
4177 path_kill_slashes(*filename
);
4179 /* Add the file name we are currently looking at to
4180 * the names of this unit, but only if it is a valid
4182 name
= basename(*filename
);
4183 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4185 id
= set_get(names
, name
);
4191 r
= set_consume(names
, id
);
4197 /* Try to open the file name, but don't if its a symlink */
4198 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4205 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4206 r
= readlink_and_make_absolute(*filename
, &target
);
4214 f
= fdopen(fd
, "re");
4226 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4234 /* Let's try to add in all symlink names we found */
4235 while ((k
= set_steal_first(names
))) {
4237 /* First try to merge in the other name into our
4239 r
= unit_merge_by_name(*u
, k
);
4243 /* Hmm, we couldn't merge the other unit into
4244 * ours? Then let's try it the other way
4247 /* If the symlink name we are looking at is unit template, then
4248 we must search for instance of this template */
4249 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4250 _cleanup_free_
char *instance
= NULL
;
4252 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4256 other
= manager_get_unit((*u
)->manager
, instance
);
4258 other
= manager_get_unit((*u
)->manager
, k
);
4263 r
= unit_merge(other
, *u
);
4266 return merge_by_names(u
, names
, NULL
);
4274 unit_choose_id(*u
, id
);
4282 static int load_from_path(Unit
*u
, const char *path
) {
4283 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4284 _cleanup_fclose_
FILE *f
= NULL
;
4285 _cleanup_free_
char *filename
= NULL
;
4294 symlink_names
= set_new(&string_hash_ops
);
4298 if (path_is_absolute(path
)) {
4300 filename
= strdup(path
);
4304 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4306 filename
= mfree(filename
);
4314 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4316 /* Instead of opening the path right away, we manually
4317 * follow all symlinks and add their name to our unit
4318 * name set while doing so */
4319 filename
= path_make_absolute(path
, *p
);
4323 if (u
->manager
->unit_path_cache
&&
4324 !set_get(u
->manager
->unit_path_cache
, filename
))
4327 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4330 filename
= mfree(filename
);
4332 /* ENOENT means that the file is missing or is a dangling symlink.
4333 * ENOTDIR means that one of paths we expect to be is a directory
4334 * is not a directory, we should just ignore that.
4335 * EACCES means that the directory or file permissions are wrong.
4338 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4339 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4342 /* Empty the symlink names for the next run */
4343 set_clear_free(symlink_names
);
4348 /* Hmm, no suitable file found? */
4351 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4352 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4357 r
= merge_by_names(&merged
, symlink_names
, id
);
4362 u
->load_state
= UNIT_MERGED
;
4366 if (fstat(fileno(f
), &st
) < 0)
4369 if (null_or_empty(&st
)) {
4370 u
->load_state
= UNIT_MASKED
;
4371 u
->fragment_mtime
= 0;
4373 u
->load_state
= UNIT_LOADED
;
4374 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4376 /* Now, parse the file contents */
4377 r
= config_parse(u
->id
, filename
, f
,
4378 UNIT_VTABLE(u
)->sections
,
4379 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4380 false, true, false, u
);
4385 free(u
->fragment_path
);
4386 u
->fragment_path
= filename
;
4389 if (u
->source_path
) {
4390 if (stat(u
->source_path
, &st
) >= 0)
4391 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4393 u
->source_mtime
= 0;
4399 int unit_load_fragment(Unit
*u
) {
4405 assert(u
->load_state
== UNIT_STUB
);
4409 u
->load_state
= UNIT_LOADED
;
4413 /* First, try to find the unit under its id. We always look
4414 * for unit files in the default directories, to make it easy
4415 * to override things by placing things in /etc/systemd/system */
4416 r
= load_from_path(u
, u
->id
);
4420 /* Try to find an alias we can load this with */
4421 if (u
->load_state
== UNIT_STUB
) {
4422 SET_FOREACH(t
, u
->names
, i
) {
4427 r
= load_from_path(u
, t
);
4431 if (u
->load_state
!= UNIT_STUB
)
4436 /* And now, try looking for it under the suggested (originally linked) path */
4437 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4439 r
= load_from_path(u
, u
->fragment_path
);
4443 if (u
->load_state
== UNIT_STUB
)
4444 /* Hmm, this didn't work? Then let's get rid
4445 * of the fragment path stored for us, so that
4446 * we don't point to an invalid location. */
4447 u
->fragment_path
= mfree(u
->fragment_path
);
4450 /* Look for a template */
4451 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4452 _cleanup_free_
char *k
= NULL
;
4454 r
= unit_name_template(u
->id
, &k
);
4458 r
= load_from_path(u
, k
);
4462 if (u
->load_state
== UNIT_STUB
) {
4463 SET_FOREACH(t
, u
->names
, i
) {
4464 _cleanup_free_
char *z
= NULL
;
4469 r
= unit_name_template(t
, &z
);
4473 r
= load_from_path(u
, z
);
4477 if (u
->load_state
!= UNIT_STUB
)
4486 void unit_dump_config_items(FILE *f
) {
4487 static const struct {
4488 const ConfigParserCallback callback
;
4491 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4492 { config_parse_warn_compat
, "NOTSUPPORTED" },
4494 { config_parse_int
, "INTEGER" },
4495 { config_parse_unsigned
, "UNSIGNED" },
4496 { config_parse_iec_size
, "SIZE" },
4497 { config_parse_iec_uint64
, "SIZE" },
4498 { config_parse_si_size
, "SIZE" },
4499 { config_parse_bool
, "BOOLEAN" },
4500 { config_parse_string
, "STRING" },
4501 { config_parse_path
, "PATH" },
4502 { config_parse_unit_path_printf
, "PATH" },
4503 { config_parse_strv
, "STRING [...]" },
4504 { config_parse_exec_nice
, "NICE" },
4505 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4506 { config_parse_exec_io_class
, "IOCLASS" },
4507 { config_parse_exec_io_priority
, "IOPRIORITY" },
4508 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4509 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4510 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4511 { config_parse_mode
, "MODE" },
4512 { config_parse_unit_env_file
, "FILE" },
4513 { config_parse_exec_output
, "OUTPUT" },
4514 { config_parse_exec_input
, "INPUT" },
4515 { config_parse_log_facility
, "FACILITY" },
4516 { config_parse_log_level
, "LEVEL" },
4517 { config_parse_exec_secure_bits
, "SECUREBITS" },
4518 { config_parse_capability_set
, "BOUNDINGSET" },
4519 { config_parse_limit
, "LIMIT" },
4520 { config_parse_unit_deps
, "UNIT [...]" },
4521 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4522 { config_parse_service_type
, "SERVICETYPE" },
4523 { config_parse_service_restart
, "SERVICERESTART" },
4524 #ifdef HAVE_SYSV_COMPAT
4525 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4527 { config_parse_kill_mode
, "KILLMODE" },
4528 { config_parse_signal
, "SIGNAL" },
4529 { config_parse_socket_listen
, "SOCKET [...]" },
4530 { config_parse_socket_bind
, "SOCKETBIND" },
4531 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4532 { config_parse_sec
, "SECONDS" },
4533 { config_parse_nsec
, "NANOSECONDS" },
4534 { config_parse_namespace_path_strv
, "PATH [...]" },
4535 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4536 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4537 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4538 { config_parse_unit_string_printf
, "STRING" },
4539 { config_parse_trigger_unit
, "UNIT" },
4540 { config_parse_timer
, "TIMER" },
4541 { config_parse_path_spec
, "PATH" },
4542 { config_parse_notify_access
, "ACCESS" },
4543 { config_parse_ip_tos
, "TOS" },
4544 { config_parse_unit_condition_path
, "CONDITION" },
4545 { config_parse_unit_condition_string
, "CONDITION" },
4546 { config_parse_unit_condition_null
, "CONDITION" },
4547 { config_parse_unit_slice
, "SLICE" },
4548 { config_parse_documentation
, "URL" },
4549 { config_parse_service_timeout
, "SECONDS" },
4550 { config_parse_emergency_action
, "ACTION" },
4551 { config_parse_set_status
, "STATUS" },
4552 { config_parse_service_sockets
, "SOCKETS" },
4553 { config_parse_environ
, "ENVIRON" },
4555 { config_parse_syscall_filter
, "SYSCALLS" },
4556 { config_parse_syscall_archs
, "ARCHS" },
4557 { config_parse_syscall_errno
, "ERRNO" },
4558 { config_parse_address_families
, "FAMILIES" },
4559 { config_parse_restrict_namespaces
, "NAMESPACES" },
4561 { config_parse_cpu_shares
, "SHARES" },
4562 { config_parse_cpu_weight
, "WEIGHT" },
4563 { config_parse_memory_limit
, "LIMIT" },
4564 { config_parse_device_allow
, "DEVICE" },
4565 { config_parse_device_policy
, "POLICY" },
4566 { config_parse_io_limit
, "LIMIT" },
4567 { config_parse_io_weight
, "WEIGHT" },
4568 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4569 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4570 { config_parse_blockio_weight
, "WEIGHT" },
4571 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4572 { config_parse_long
, "LONG" },
4573 { config_parse_socket_service
, "SERVICE" },
4575 { config_parse_exec_selinux_context
, "LABEL" },
4577 { config_parse_job_mode
, "MODE" },
4578 { config_parse_job_mode_isolate
, "BOOLEAN" },
4579 { config_parse_personality
, "PERSONALITY" },
4582 const char *prev
= NULL
;
4587 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4588 const char *rvalue
= "OTHER", *lvalue
;
4592 const ConfigPerfItem
*p
;
4594 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4596 dot
= strchr(i
, '.');
4597 lvalue
= dot
? dot
+ 1 : i
;
4601 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4605 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4608 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4609 if (p
->parse
== table
[j
].callback
) {
4610 rvalue
= table
[j
].rvalue
;
4614 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);