2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
5 Copyright 2012 Holger Hans Peter Freyther
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/oom.h>
30 #include <sys/resource.h>
34 #include "alloc-util.h"
35 #include "bus-error.h"
36 #include "bus-internal.h"
39 #include "capability-util.h"
41 #include "conf-parser.h"
42 #include "cpu-set-util.h"
44 #include "errno-list.h"
49 #include "load-fragment.h"
52 #include "mount-util.h"
53 #include "parse-util.h"
54 #include "path-util.h"
55 #include "process-util.h"
56 #include "rlimit-util.h"
58 #include "seccomp-util.h"
60 #include "securebits.h"
61 #include "securebits-util.h"
62 #include "signal-util.h"
63 #include "stat-util.h"
64 #include "string-util.h"
66 #include "unit-name.h"
67 #include "unit-printf.h"
69 #include "user-util.h"
73 int config_parse_warn_compat(
78 unsigned section_line
,
84 Disabled reason
= ltype
;
87 case DISABLED_CONFIGURATION
:
88 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
89 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
92 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
93 "Support for option %s= has been removed and it is ignored", lvalue
);
95 case DISABLED_EXPERIMENTAL
:
96 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
97 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
104 int config_parse_unit_deps(
106 const char *filename
,
109 unsigned section_line
,
116 UnitDependency d
= ltype
;
126 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
129 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
135 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
139 r
= unit_name_printf(u
, word
, &k
);
141 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
145 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
147 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
153 int config_parse_obsolete_unit_deps(
155 const char *filename
,
158 unsigned section_line
,
165 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
166 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
168 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
171 int config_parse_unit_string_printf(
173 const char *filename
,
176 unsigned section_line
,
183 _cleanup_free_
char *k
= NULL
;
192 r
= unit_full_printf(u
, rvalue
, &k
);
194 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
198 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
201 int config_parse_unit_strv_printf(
203 const char *filename
,
206 unsigned section_line
,
214 _cleanup_free_
char *k
= NULL
;
222 r
= unit_full_printf(u
, rvalue
, &k
);
224 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
228 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
231 int config_parse_unit_path_printf(
233 const char *filename
,
236 unsigned section_line
,
243 _cleanup_free_
char *k
= NULL
;
253 r
= unit_full_printf(u
, rvalue
, &k
);
255 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
256 "Failed to resolve unit specifiers on %s%s: %m",
257 fatal
? "" : ", ignoring", rvalue
);
258 return fatal
? -ENOEXEC
: 0;
261 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
264 int config_parse_unit_path_strv_printf(
266 const char *filename
,
269 unsigned section_line
,
287 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
289 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
295 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
296 "Invalid syntax, ignoring: %s", rvalue
);
300 r
= unit_full_printf(u
, word
, &k
);
302 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
303 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
307 if (!utf8_is_valid(k
)) {
308 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
312 if (!path_is_absolute(k
)) {
313 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
314 "Symlink path is not absolute: %s", k
);
318 path_kill_slashes(k
);
327 int config_parse_socket_listen(const char *unit
,
328 const char *filename
,
331 unsigned section_line
,
338 _cleanup_free_ SocketPort
*p
= NULL
;
350 if (isempty(rvalue
)) {
351 /* An empty assignment removes all ports */
352 socket_free_ports(s
);
356 p
= new0(SocketPort
, 1);
360 if (ltype
!= SOCKET_SOCKET
) {
363 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
365 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
369 path_kill_slashes(p
->path
);
371 } else if (streq(lvalue
, "ListenNetlink")) {
372 _cleanup_free_
char *k
= NULL
;
374 p
->type
= SOCKET_SOCKET
;
375 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
377 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
381 r
= socket_address_parse_netlink(&p
->address
, k
);
383 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
388 _cleanup_free_
char *k
= NULL
;
390 p
->type
= SOCKET_SOCKET
;
391 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
393 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
397 r
= socket_address_parse_and_warn(&p
->address
, k
);
399 if (r
!= -EAFNOSUPPORT
)
400 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
405 if (streq(lvalue
, "ListenStream"))
406 p
->address
.type
= SOCK_STREAM
;
407 else if (streq(lvalue
, "ListenDatagram"))
408 p
->address
.type
= SOCK_DGRAM
;
410 assert(streq(lvalue
, "ListenSequentialPacket"));
411 p
->address
.type
= SOCK_SEQPACKET
;
414 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
415 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
421 p
->auxiliary_fds
= NULL
;
422 p
->n_auxiliary_fds
= 0;
426 LIST_FIND_TAIL(port
, s
->ports
, tail
);
427 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
429 LIST_PREPEND(port
, s
->ports
, p
);
435 int config_parse_socket_protocol(const char *unit
,
436 const char *filename
,
439 unsigned section_line
,
454 if (streq(rvalue
, "udplite"))
455 s
->socket_protocol
= IPPROTO_UDPLITE
;
456 else if (streq(rvalue
, "sctp"))
457 s
->socket_protocol
= IPPROTO_SCTP
;
459 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
466 int config_parse_socket_bind(const char *unit
,
467 const char *filename
,
470 unsigned section_line
,
478 SocketAddressBindIPv6Only b
;
487 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
491 r
= parse_boolean(rvalue
);
493 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
497 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
499 s
->bind_ipv6_only
= b
;
504 int config_parse_exec_nice(
506 const char *filename
,
509 unsigned section_line
,
516 ExecContext
*c
= data
;
524 r
= parse_nice(rvalue
, &priority
);
527 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
529 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
540 int config_parse_exec_oom_score_adjust(const char* unit
,
541 const char *filename
,
544 unsigned section_line
,
551 ExecContext
*c
= data
;
559 r
= safe_atoi(rvalue
, &oa
);
561 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
565 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
566 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
570 c
->oom_score_adjust
= oa
;
571 c
->oom_score_adjust_set
= true;
576 int config_parse_exec(
578 const char *filename
,
581 unsigned section_line
,
588 ExecCommand
**e
= data
;
600 rvalue
+= strspn(rvalue
, WHITESPACE
);
602 if (isempty(rvalue
)) {
603 /* An empty assignment resets the list */
604 *e
= exec_command_free_list(*e
);
610 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
611 bool separate_argv0
= false, ignore
= false, privileged
= false;
612 _cleanup_free_ ExecCommand
*nce
= NULL
;
613 _cleanup_strv_free_
char **n
= NULL
;
614 size_t nlen
= 0, nbufsize
= 0;
619 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
625 /* We accept an absolute path as first argument.
626 * If it's prefixed with - and the path doesn't exist,
627 * we ignore it instead of erroring out;
628 * if it's prefixed with @, we allow overriding of argv[0];
629 * and if it's prefixed with +, it will be run with full privileges */
630 if (*f
== '-' && !ignore
)
632 else if (*f
== '@' && !separate_argv0
)
633 separate_argv0
= true;
634 else if (*f
== '+' && !privileged
)
641 r
= unit_full_printf(u
, f
, &path
);
643 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
644 "Failed to resolve unit specifiers on %s%s: %m",
645 f
, ignore
? ", ignoring" : "");
646 return ignore
? 0 : -ENOEXEC
;
650 /* First word is either "-" or "@" with no command. */
651 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
652 "Empty path in command line%s: \"%s\"",
653 ignore
? ", ignoring" : "", rvalue
);
654 return ignore
? 0 : -ENOEXEC
;
656 if (!string_is_safe(path
)) {
657 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
658 "Executable path contains special characters%s: %s",
659 ignore
? ", ignoring" : "", rvalue
);
660 return ignore
? 0 : -ENOEXEC
;
662 if (!path_is_absolute(path
)) {
663 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
664 "Executable path is not absolute%s: %s",
665 ignore
? ", ignoring" : "", rvalue
);
666 return ignore
? 0 : -ENOEXEC
;
668 if (endswith(path
, "/")) {
669 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
670 "Executable path specifies a directory%s: %s",
671 ignore
? ", ignoring" : "", rvalue
);
672 return ignore
? 0 : -ENOEXEC
;
675 if (!separate_argv0
) {
678 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
688 path_kill_slashes(path
);
690 while (!isempty(p
)) {
691 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
693 /* Check explicitly for an unquoted semicolon as
694 * command separator token. */
695 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
697 p
+= strspn(p
, WHITESPACE
);
702 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
703 * extract_first_word() would return the same for all of those. */
704 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
708 p
+= strspn(p
, WHITESPACE
);
710 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
721 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
725 return ignore
? 0 : -ENOEXEC
;
727 r
= unit_full_printf(u
, word
, &resolved
);
729 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
730 "Failed to resolve unit specifiers on %s%s: %m",
731 word
, ignore
? ", ignoring" : "");
732 return ignore
? 0 : -ENOEXEC
;
735 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
737 n
[nlen
++] = resolved
;
743 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
744 "Empty executable name or zeroeth argument%s: %s",
745 ignore
? ", ignoring" : "", rvalue
);
746 return ignore
? 0 : -ENOEXEC
;
749 nce
= new0(ExecCommand
, 1);
755 nce
->ignore
= ignore
;
756 nce
->privileged
= privileged
;
758 exec_command_append_list(e
, nce
);
760 /* Do not _cleanup_free_ these. */
771 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
772 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
774 int config_parse_socket_bindtodevice(
776 const char *filename
,
779 unsigned section_line
,
794 if (rvalue
[0] && !streq(rvalue
, "*")) {
795 if (!ifname_valid(rvalue
)) {
796 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
806 free(s
->bind_to_device
);
807 s
->bind_to_device
= n
;
812 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
813 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
815 int config_parse_exec_input(const char *unit
,
816 const char *filename
,
819 unsigned section_line
,
825 ExecContext
*c
= data
;
834 name
= startswith(rvalue
, "fd:");
836 /* Strip prefix and validate fd name */
837 if (!fdname_is_valid(name
)) {
838 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
841 c
->std_input
= EXEC_INPUT_NAMED_FD
;
842 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
847 ExecInput ei
= exec_input_from_string(rvalue
);
848 if (ei
== _EXEC_INPUT_INVALID
)
849 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
856 int config_parse_exec_output(const char *unit
,
857 const char *filename
,
860 unsigned section_line
,
866 ExecContext
*c
= data
;
877 name
= startswith(rvalue
, "fd:");
879 /* Strip prefix and validate fd name */
880 if (!fdname_is_valid(name
)) {
881 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
884 eo
= EXEC_OUTPUT_NAMED_FD
;
886 eo
= exec_output_from_string(rvalue
);
887 if (eo
== _EXEC_OUTPUT_INVALID
) {
888 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
893 if (streq(lvalue
, "StandardOutput")) {
895 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
899 } else if (streq(lvalue
, "StandardError")) {
901 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
906 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
911 int config_parse_exec_io_class(const char *unit
,
912 const char *filename
,
915 unsigned section_line
,
922 ExecContext
*c
= data
;
930 x
= ioprio_class_from_string(rvalue
);
932 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
936 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
937 c
->ioprio_set
= true;
942 int config_parse_exec_io_priority(const char *unit
,
943 const char *filename
,
946 unsigned section_line
,
953 ExecContext
*c
= data
;
961 r
= ioprio_parse_priority(rvalue
, &i
);
963 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
967 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
968 c
->ioprio_set
= true;
973 int config_parse_exec_cpu_sched_policy(const char *unit
,
974 const char *filename
,
977 unsigned section_line
,
985 ExecContext
*c
= data
;
993 x
= sched_policy_from_string(rvalue
);
995 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
999 c
->cpu_sched_policy
= x
;
1000 /* Moving to or from real-time policy? We need to adjust the priority */
1001 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1002 c
->cpu_sched_set
= true;
1007 int config_parse_exec_cpu_sched_prio(const char *unit
,
1008 const char *filename
,
1010 const char *section
,
1011 unsigned section_line
,
1018 ExecContext
*c
= data
;
1026 r
= safe_atoi(rvalue
, &i
);
1028 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1032 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1033 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1034 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1036 if (i
< min
|| i
> max
) {
1037 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1041 c
->cpu_sched_priority
= i
;
1042 c
->cpu_sched_set
= true;
1047 int config_parse_exec_cpu_affinity(const char *unit
,
1048 const char *filename
,
1050 const char *section
,
1051 unsigned section_line
,
1058 ExecContext
*c
= data
;
1059 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1067 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1072 CPU_FREE(c
->cpuset
);
1075 /* An empty assignment resets the CPU list */
1081 c
->cpuset_ncpus
= ncpus
;
1086 int config_parse_exec_secure_bits(const char *unit
,
1087 const char *filename
,
1089 const char *section
,
1090 unsigned section_line
,
1097 ExecContext
*c
= data
;
1105 if (isempty(rvalue
)) {
1106 /* An empty assignment resets the field */
1111 r
= secure_bits_from_string(rvalue
);
1115 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1116 "Invalid syntax, ignoring: %s", rvalue
);
1125 int config_parse_capability_set(
1127 const char *filename
,
1129 const char *section
,
1130 unsigned section_line
,
1137 uint64_t *capability_set
= data
;
1138 uint64_t sum
= 0, initial
= 0;
1139 bool invert
= false;
1147 if (rvalue
[0] == '~') {
1152 if (streq(lvalue
, "CapabilityBoundingSet"))
1153 initial
= CAP_ALL
; /* initialized to all bits on */
1154 /* else "AmbientCapabilities" initialized to all bits off */
1156 r
= capability_set_from_string(rvalue
, &sum
);
1160 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1164 sum
= invert
? ~sum
: sum
;
1166 if (sum
== 0 || *capability_set
== initial
)
1167 /* "" or uninitialized data -> replace */
1168 *capability_set
= sum
;
1170 /* previous data -> merge */
1171 *capability_set
|= sum
;
1176 int config_parse_limit(
1178 const char *filename
,
1180 const char *section
,
1181 unsigned section_line
,
1188 struct rlimit
**rl
= data
, d
= {};
1196 r
= rlimit_parse(ltype
, rvalue
, &d
);
1198 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1202 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1209 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1217 #ifdef HAVE_SYSV_COMPAT
1218 int config_parse_sysv_priority(const char *unit
,
1219 const char *filename
,
1221 const char *section
,
1222 unsigned section_line
,
1229 int *priority
= data
;
1237 r
= safe_atoi(rvalue
, &i
);
1238 if (r
< 0 || i
< 0) {
1239 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1243 *priority
= (int) i
;
1248 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1249 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1251 int config_parse_exec_mount_flags(
1253 const char *filename
,
1255 const char *section
,
1256 unsigned section_line
,
1264 ExecContext
*c
= data
;
1272 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1274 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1279 int config_parse_exec_selinux_context(
1281 const char *filename
,
1283 const char *section
,
1284 unsigned section_line
,
1291 ExecContext
*c
= data
;
1302 if (isempty(rvalue
)) {
1303 c
->selinux_context
= mfree(c
->selinux_context
);
1304 c
->selinux_context_ignore
= false;
1308 if (rvalue
[0] == '-') {
1314 r
= unit_full_printf(u
, rvalue
, &k
);
1316 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1317 "Failed to resolve specifiers%s: %m",
1318 ignore
? ", ignoring" : "");
1319 return ignore
? 0 : -ENOEXEC
;
1322 free(c
->selinux_context
);
1323 c
->selinux_context
= k
;
1324 c
->selinux_context_ignore
= ignore
;
1329 int config_parse_exec_apparmor_profile(
1331 const char *filename
,
1333 const char *section
,
1334 unsigned section_line
,
1341 ExecContext
*c
= data
;
1352 if (isempty(rvalue
)) {
1353 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1354 c
->apparmor_profile_ignore
= false;
1358 if (rvalue
[0] == '-') {
1364 r
= unit_full_printf(u
, rvalue
, &k
);
1366 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1367 "Failed to resolve specifiers%s: %m",
1368 ignore
? ", ignoring" : "");
1369 return ignore
? 0 : -ENOEXEC
;
1372 free(c
->apparmor_profile
);
1373 c
->apparmor_profile
= k
;
1374 c
->apparmor_profile_ignore
= ignore
;
1379 int config_parse_exec_smack_process_label(
1381 const char *filename
,
1383 const char *section
,
1384 unsigned section_line
,
1391 ExecContext
*c
= data
;
1402 if (isempty(rvalue
)) {
1403 c
->smack_process_label
= mfree(c
->smack_process_label
);
1404 c
->smack_process_label_ignore
= false;
1408 if (rvalue
[0] == '-') {
1414 r
= unit_full_printf(u
, rvalue
, &k
);
1416 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1417 "Failed to resolve specifiers%s: %m",
1418 ignore
? ", ignoring" : "");
1419 return ignore
? 0 : -ENOEXEC
;
1422 free(c
->smack_process_label
);
1423 c
->smack_process_label
= k
;
1424 c
->smack_process_label_ignore
= ignore
;
1429 int config_parse_timer(const char *unit
,
1430 const char *filename
,
1432 const char *section
,
1433 unsigned section_line
,
1444 CalendarSpec
*c
= NULL
;
1446 _cleanup_free_
char *k
= NULL
;
1454 if (isempty(rvalue
)) {
1455 /* Empty assignment resets list */
1456 timer_free_values(t
);
1460 b
= timer_base_from_string(lvalue
);
1462 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1466 r
= unit_full_printf(u
, rvalue
, &k
);
1468 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1472 if (b
== TIMER_CALENDAR
) {
1473 if (calendar_spec_from_string(k
, &c
) < 0) {
1474 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1478 if (parse_sec(k
, &usec
) < 0) {
1479 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1484 v
= new0(TimerValue
, 1);
1486 calendar_spec_free(c
);
1492 v
->calendar_spec
= c
;
1494 LIST_PREPEND(value
, t
->values
, v
);
1499 int config_parse_trigger_unit(
1501 const char *filename
,
1503 const char *section
,
1504 unsigned section_line
,
1511 _cleanup_free_
char *p
= NULL
;
1521 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1522 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1526 r
= unit_name_printf(u
, rvalue
, &p
);
1528 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1532 type
= unit_name_to_type(p
);
1534 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1538 if (type
== u
->type
) {
1539 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1543 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1545 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1552 int config_parse_path_spec(const char *unit
,
1553 const char *filename
,
1555 const char *section
,
1556 unsigned section_line
,
1566 _cleanup_free_
char *k
= NULL
;
1574 if (isempty(rvalue
)) {
1575 /* Empty assignment clears list */
1580 b
= path_type_from_string(lvalue
);
1582 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1586 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1588 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1592 if (!path_is_absolute(k
)) {
1593 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1597 s
= new0(PathSpec
, 1);
1602 s
->path
= path_kill_slashes(k
);
1607 LIST_PREPEND(spec
, p
->specs
, s
);
1612 int config_parse_socket_service(
1614 const char *filename
,
1616 const char *section
,
1617 unsigned section_line
,
1624 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1625 _cleanup_free_
char *p
= NULL
;
1635 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1637 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1641 if (!endswith(p
, ".service")) {
1642 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1646 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1648 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1652 unit_ref_set(&s
->service
, x
);
1657 int config_parse_fdname(
1659 const char *filename
,
1661 const char *section
,
1662 unsigned section_line
,
1669 _cleanup_free_
char *p
= NULL
;
1678 if (isempty(rvalue
)) {
1679 s
->fdname
= mfree(s
->fdname
);
1683 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1685 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1689 if (!fdname_is_valid(p
)) {
1690 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1694 return free_and_replace(s
->fdname
, p
);
1697 int config_parse_service_sockets(
1699 const char *filename
,
1701 const char *section
,
1702 unsigned section_line
,
1720 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1722 r
= extract_first_word(&p
, &word
, NULL
, 0);
1728 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1732 r
= unit_name_printf(UNIT(s
), word
, &k
);
1734 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1738 if (!endswith(k
, ".socket")) {
1739 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1743 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1745 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1747 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1749 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1755 int config_parse_bus_name(
1757 const char *filename
,
1759 const char *section
,
1760 unsigned section_line
,
1767 _cleanup_free_
char *k
= NULL
;
1776 r
= unit_full_printf(u
, rvalue
, &k
);
1778 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1782 if (!service_name_is_valid(k
)) {
1783 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1787 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1790 int config_parse_service_timeout(
1792 const char *filename
,
1794 const char *section
,
1795 unsigned section_line
,
1802 Service
*s
= userdata
;
1811 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1813 r
= parse_sec(rvalue
, &usec
);
1815 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1819 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1820 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1821 * all other timeouts. */
1823 usec
= USEC_INFINITY
;
1825 if (!streq(lvalue
, "TimeoutStopSec")) {
1826 s
->start_timeout_defined
= true;
1827 s
->timeout_start_usec
= usec
;
1830 if (!streq(lvalue
, "TimeoutStartSec"))
1831 s
->timeout_stop_usec
= usec
;
1836 int config_parse_sec_fix_0(
1838 const char *filename
,
1840 const char *section
,
1841 unsigned section_line
,
1848 usec_t
*usec
= data
;
1856 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1857 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1860 r
= parse_sec_fix_0(rvalue
, usec
);
1862 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1869 int config_parse_user_group(
1871 const char *filename
,
1873 const char *section
,
1874 unsigned section_line
,
1881 char **user
= data
, *n
;
1890 if (isempty(rvalue
))
1893 _cleanup_free_
char *k
= NULL
;
1895 r
= unit_full_printf(u
, rvalue
, &k
);
1897 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
1901 if (!valid_user_group_name_or_id(k
)) {
1902 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1916 int config_parse_user_group_strv(
1918 const char *filename
,
1920 const char *section
,
1921 unsigned section_line
,
1928 char ***users
= data
;
1938 if (isempty(rvalue
)) {
1941 empty
= new0(char*, 1);
1953 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1955 r
= extract_first_word(&p
, &word
, NULL
, 0);
1961 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
1965 r
= unit_full_printf(u
, word
, &k
);
1967 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
1971 if (!valid_user_group_name_or_id(k
)) {
1972 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1976 r
= strv_push(users
, k
);
1986 int config_parse_working_directory(
1988 const char *filename
,
1990 const char *section
,
1991 unsigned section_line
,
1998 ExecContext
*c
= data
;
2009 if (rvalue
[0] == '-') {
2015 if (streq(rvalue
, "~")) {
2016 c
->working_directory_home
= true;
2017 c
->working_directory
= mfree(c
->working_directory
);
2019 _cleanup_free_
char *k
= NULL
;
2021 r
= unit_full_printf(u
, rvalue
, &k
);
2023 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2024 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2025 rvalue
, missing_ok
? ", ignoring" : "");
2026 return missing_ok
? 0 : -ENOEXEC
;
2029 path_kill_slashes(k
);
2031 if (!utf8_is_valid(k
)) {
2032 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2033 return missing_ok
? 0 : -ENOEXEC
;
2036 if (!path_is_absolute(k
)) {
2037 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2038 "Working directory path '%s' is not absolute%s.",
2039 rvalue
, missing_ok
? ", ignoring" : "");
2040 return missing_ok
? 0 : -ENOEXEC
;
2043 c
->working_directory_home
= false;
2044 free_and_replace(c
->working_directory
, k
);
2047 c
->working_directory_missing_ok
= missing_ok
;
2051 int config_parse_unit_env_file(const char *unit
,
2052 const char *filename
,
2054 const char *section
,
2055 unsigned section_line
,
2064 _cleanup_free_
char *n
= NULL
;
2072 if (isempty(rvalue
)) {
2073 /* Empty assignment frees the list */
2074 *env
= strv_free(*env
);
2078 r
= unit_full_printf(u
, rvalue
, &n
);
2080 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2084 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2085 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2089 r
= strv_extend(env
, n
);
2096 int config_parse_environ(const char *unit
,
2097 const char *filename
,
2099 const char *section
,
2100 unsigned section_line
,
2117 if (isempty(rvalue
)) {
2118 /* Empty assignment resets the list */
2119 *env
= strv_free(*env
);
2123 for (p
= rvalue
;; ) {
2124 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2126 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2132 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2133 "Invalid syntax, ignoring: %s", rvalue
);
2138 r
= unit_full_printf(u
, word
, &k
);
2140 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2141 "Failed to resolve specifiers, ignoring: %s", k
);
2149 if (!env_assignment_is_valid(k
)) {
2150 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2151 "Invalid environment assignment, ignoring: %s", k
);
2155 r
= strv_env_replace(env
, k
);
2162 int config_parse_pass_environ(const char *unit
,
2163 const char *filename
,
2165 const char *section
,
2166 unsigned section_line
,
2173 const char *whole_rvalue
= rvalue
;
2174 char*** passenv
= data
;
2175 _cleanup_strv_free_
char **n
= NULL
;
2176 size_t nlen
= 0, nbufsize
= 0;
2184 if (isempty(rvalue
)) {
2185 /* Empty assignment resets the list */
2186 *passenv
= strv_free(*passenv
);
2191 _cleanup_free_
char *word
= NULL
;
2193 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2199 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2200 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2204 if (!env_name_is_valid(word
)) {
2205 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2206 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2210 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2218 r
= strv_extend_strv(passenv
, n
, true);
2226 int config_parse_ip_tos(const char *unit
,
2227 const char *filename
,
2229 const char *section
,
2230 unsigned section_line
,
2237 int *ip_tos
= data
, x
;
2244 x
= ip_tos_from_string(rvalue
);
2246 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2254 int config_parse_unit_condition_path(
2256 const char *filename
,
2258 const char *section
,
2259 unsigned section_line
,
2266 _cleanup_free_
char *p
= NULL
;
2267 Condition
**list
= data
, *c
;
2268 ConditionType t
= ltype
;
2269 bool trigger
, negate
;
2278 if (isempty(rvalue
)) {
2279 /* Empty assignment resets the list */
2280 *list
= condition_free_list(*list
);
2284 trigger
= rvalue
[0] == '|';
2288 negate
= rvalue
[0] == '!';
2292 r
= unit_full_printf(u
, rvalue
, &p
);
2294 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2298 if (!path_is_absolute(p
)) {
2299 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2303 c
= condition_new(t
, p
, trigger
, negate
);
2307 LIST_PREPEND(conditions
, *list
, c
);
2311 int config_parse_unit_condition_string(
2313 const char *filename
,
2315 const char *section
,
2316 unsigned section_line
,
2323 _cleanup_free_
char *s
= NULL
;
2324 Condition
**list
= data
, *c
;
2325 ConditionType t
= ltype
;
2326 bool trigger
, negate
;
2335 if (isempty(rvalue
)) {
2336 /* Empty assignment resets the list */
2337 *list
= condition_free_list(*list
);
2341 trigger
= rvalue
[0] == '|';
2345 negate
= rvalue
[0] == '!';
2349 r
= unit_full_printf(u
, rvalue
, &s
);
2351 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2355 c
= condition_new(t
, s
, trigger
, negate
);
2359 LIST_PREPEND(conditions
, *list
, c
);
2363 int config_parse_unit_condition_null(
2365 const char *filename
,
2367 const char *section
,
2368 unsigned section_line
,
2375 Condition
**list
= data
, *c
;
2376 bool trigger
, negate
;
2384 if (isempty(rvalue
)) {
2385 /* Empty assignment resets the list */
2386 *list
= condition_free_list(*list
);
2390 trigger
= rvalue
[0] == '|';
2394 negate
= rvalue
[0] == '!';
2398 b
= parse_boolean(rvalue
);
2400 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2407 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2411 LIST_PREPEND(conditions
, *list
, c
);
2415 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2416 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2418 int config_parse_unit_requires_mounts_for(
2420 const char *filename
,
2422 const char *section
,
2423 unsigned section_line
,
2439 for (p
= rvalue
;; ) {
2440 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2442 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2448 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2449 "Invalid syntax, ignoring: %s", rvalue
);
2453 if (!utf8_is_valid(word
)) {
2454 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2458 r
= unit_full_printf(u
, word
, &resolved
);
2460 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2464 r
= unit_require_mounts_for(u
, resolved
);
2466 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2472 int config_parse_documentation(const char *unit
,
2473 const char *filename
,
2475 const char *section
,
2476 unsigned section_line
,
2492 if (isempty(rvalue
)) {
2493 /* Empty assignment resets the list */
2494 u
->documentation
= strv_free(u
->documentation
);
2498 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2499 rvalue
, data
, userdata
);
2503 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2505 if (documentation_url_is_valid(*a
))
2508 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2520 static int syscall_filter_parse_one(
2522 const char *filename
,
2531 const SyscallFilterSet
*set
;
2534 set
= syscall_filter_set_find(t
);
2537 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2541 NULSTR_FOREACH(i
, set
->value
) {
2542 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2549 id
= seccomp_syscall_resolve_name(t
);
2550 if (id
== __NR_SCMP_ERROR
) {
2552 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2556 /* If we previously wanted to forbid a syscall and now
2557 * we want to allow it, then remove it from the list
2559 if (!invert
== c
->syscall_whitelist
) {
2560 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2566 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2572 int config_parse_syscall_filter(
2574 const char *filename
,
2576 const char *section
,
2577 unsigned section_line
,
2584 ExecContext
*c
= data
;
2586 bool invert
= false;
2595 if (isempty(rvalue
)) {
2596 /* Empty assignment resets the list */
2597 c
->syscall_filter
= set_free(c
->syscall_filter
);
2598 c
->syscall_whitelist
= false;
2602 if (rvalue
[0] == '~') {
2607 if (!c
->syscall_filter
) {
2608 c
->syscall_filter
= set_new(NULL
);
2609 if (!c
->syscall_filter
)
2613 /* Allow everything but the ones listed */
2614 c
->syscall_whitelist
= false;
2616 /* Allow nothing but the ones listed */
2617 c
->syscall_whitelist
= true;
2619 /* Accept default syscalls if we are on a whitelist */
2620 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2628 _cleanup_free_
char *word
= NULL
;
2630 r
= extract_first_word(&p
, &word
, NULL
, 0);
2636 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2640 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2648 int config_parse_syscall_archs(
2650 const char *filename
,
2652 const char *section
,
2653 unsigned section_line
,
2664 if (isempty(rvalue
)) {
2665 *archs
= set_free(*archs
);
2669 r
= set_ensure_allocated(archs
, NULL
);
2673 for (p
= rvalue
;;) {
2674 _cleanup_free_
char *word
= NULL
;
2677 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2683 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2684 "Invalid syntax, ignoring: %s", rvalue
);
2688 r
= seccomp_arch_from_string(word
, &a
);
2690 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2691 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2695 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2701 int config_parse_syscall_errno(
2703 const char *filename
,
2705 const char *section
,
2706 unsigned section_line
,
2713 ExecContext
*c
= data
;
2720 if (isempty(rvalue
)) {
2721 /* Empty assignment resets to KILL */
2722 c
->syscall_errno
= 0;
2726 e
= errno_from_name(rvalue
);
2728 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2732 c
->syscall_errno
= e
;
2736 int config_parse_address_families(
2738 const char *filename
,
2740 const char *section
,
2741 unsigned section_line
,
2748 ExecContext
*c
= data
;
2749 bool invert
= false;
2757 if (isempty(rvalue
)) {
2758 /* Empty assignment resets the list */
2759 c
->address_families
= set_free(c
->address_families
);
2760 c
->address_families_whitelist
= false;
2764 if (rvalue
[0] == '~') {
2769 if (!c
->address_families
) {
2770 c
->address_families
= set_new(NULL
);
2771 if (!c
->address_families
)
2774 c
->address_families_whitelist
= !invert
;
2777 for (p
= rvalue
;;) {
2778 _cleanup_free_
char *word
= NULL
;
2781 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2787 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2788 "Invalid syntax, ignoring: %s", rvalue
);
2792 af
= af_from_name(word
);
2794 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2795 "Failed to parse address family \"%s\", ignoring: %m", word
);
2799 /* If we previously wanted to forbid an address family and now
2800 * we want to allow it, then just remove it from the list.
2802 if (!invert
== c
->address_families_whitelist
) {
2803 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2807 set_remove(c
->address_families
, INT_TO_PTR(af
));
2811 int config_parse_restrict_namespaces(
2813 const char *filename
,
2815 const char *section
,
2816 unsigned section_line
,
2823 ExecContext
*c
= data
;
2824 bool invert
= false;
2827 if (isempty(rvalue
)) {
2828 /* Reset to the default. */
2829 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2833 if (rvalue
[0] == '~') {
2838 r
= parse_boolean(rvalue
);
2840 c
->restrict_namespaces
= 0;
2842 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2844 /* Not a boolean argument, in this case it's a list of namespace types. */
2846 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2848 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2854 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2860 int config_parse_unit_slice(
2862 const char *filename
,
2864 const char *section
,
2865 unsigned section_line
,
2872 _cleanup_free_
char *k
= NULL
;
2873 Unit
*u
= userdata
, *slice
= NULL
;
2881 r
= unit_name_printf(u
, rvalue
, &k
);
2883 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2887 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2889 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2893 r
= unit_set_slice(u
, slice
);
2895 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2902 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2904 int config_parse_cpu_weight(
2906 const char *filename
,
2908 const char *section
,
2909 unsigned section_line
,
2916 uint64_t *weight
= data
;
2923 r
= cg_weight_parse(rvalue
, weight
);
2925 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
2932 int config_parse_cpu_shares(
2934 const char *filename
,
2936 const char *section
,
2937 unsigned section_line
,
2944 uint64_t *shares
= data
;
2951 r
= cg_cpu_shares_parse(rvalue
, shares
);
2953 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2960 int config_parse_cpu_quota(
2962 const char *filename
,
2964 const char *section
,
2965 unsigned section_line
,
2972 CGroupContext
*c
= data
;
2979 if (isempty(rvalue
)) {
2980 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2984 r
= parse_percent_unbounded(rvalue
);
2986 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
2990 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
2994 int config_parse_memory_limit(
2996 const char *filename
,
2998 const char *section
,
2999 unsigned section_line
,
3006 CGroupContext
*c
= data
;
3007 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3010 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3012 r
= parse_percent(rvalue
);
3014 r
= parse_size(rvalue
, 1024, &bytes
);
3016 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3020 bytes
= physical_memory_scale(r
, 100U);
3022 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3023 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3028 if (streq(lvalue
, "MemoryLow"))
3029 c
->memory_low
= bytes
;
3030 else if (streq(lvalue
, "MemoryHigh"))
3031 c
->memory_high
= bytes
;
3032 else if (streq(lvalue
, "MemoryMax"))
3033 c
->memory_max
= bytes
;
3034 else if (streq(lvalue
, "MemorySwapMax"))
3035 c
->memory_swap_max
= bytes
;
3036 else if (streq(lvalue
, "MemoryLimit"))
3037 c
->memory_limit
= bytes
;
3044 int config_parse_tasks_max(
3046 const char *filename
,
3048 const char *section
,
3049 unsigned section_line
,
3056 uint64_t *tasks_max
= data
, v
;
3060 if (isempty(rvalue
)) {
3061 *tasks_max
= u
->manager
->default_tasks_max
;
3065 if (streq(rvalue
, "infinity")) {
3066 *tasks_max
= CGROUP_LIMIT_MAX
;
3070 r
= parse_percent(rvalue
);
3072 r
= safe_atou64(rvalue
, &v
);
3074 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3078 v
= system_tasks_max_scale(r
, 100U);
3080 if (v
<= 0 || v
>= UINT64_MAX
) {
3081 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3089 int config_parse_device_allow(
3091 const char *filename
,
3093 const char *section
,
3094 unsigned section_line
,
3101 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3102 CGroupContext
*c
= data
;
3103 CGroupDeviceAllow
*a
;
3104 const char *m
= NULL
;
3108 if (isempty(rvalue
)) {
3109 while (c
->device_allow
)
3110 cgroup_context_free_device_allow(c
, c
->device_allow
);
3115 r
= unit_full_printf(userdata
, rvalue
, &t
);
3117 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3118 "Failed to resolve specifiers in %s, ignoring: %m",
3122 n
= strcspn(t
, WHITESPACE
);
3124 path
= strndup(t
, n
);
3128 if (!is_deviceallow_pattern(path
)) {
3129 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3133 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3137 if (!in_charset(m
, "rwm")) {
3138 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3142 a
= new0(CGroupDeviceAllow
, 1);
3148 a
->r
= !!strchr(m
, 'r');
3149 a
->w
= !!strchr(m
, 'w');
3150 a
->m
= !!strchr(m
, 'm');
3152 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3156 int config_parse_io_weight(
3158 const char *filename
,
3160 const char *section
,
3161 unsigned section_line
,
3168 uint64_t *weight
= data
;
3175 r
= cg_weight_parse(rvalue
, weight
);
3177 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3184 int config_parse_io_device_weight(
3186 const char *filename
,
3188 const char *section
,
3189 unsigned section_line
,
3196 _cleanup_free_
char *path
= NULL
;
3197 CGroupIODeviceWeight
*w
;
3198 CGroupContext
*c
= data
;
3208 if (isempty(rvalue
)) {
3209 while (c
->io_device_weights
)
3210 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3215 n
= strcspn(rvalue
, WHITESPACE
);
3216 weight
= rvalue
+ n
;
3217 weight
+= strspn(weight
, WHITESPACE
);
3219 if (isempty(weight
)) {
3220 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3224 path
= strndup(rvalue
, n
);
3228 if (!path_startswith(path
, "/dev")) {
3229 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3233 r
= cg_weight_parse(weight
, &u
);
3235 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3239 assert(u
!= CGROUP_WEIGHT_INVALID
);
3241 w
= new0(CGroupIODeviceWeight
, 1);
3250 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3254 int config_parse_io_limit(
3256 const char *filename
,
3258 const char *section
,
3259 unsigned section_line
,
3266 _cleanup_free_
char *path
= NULL
;
3267 CGroupIODeviceLimit
*l
= NULL
, *t
;
3268 CGroupContext
*c
= data
;
3269 CGroupIOLimitType type
;
3279 type
= cgroup_io_limit_type_from_string(lvalue
);
3282 if (isempty(rvalue
)) {
3283 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3284 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3288 n
= strcspn(rvalue
, WHITESPACE
);
3290 limit
+= strspn(limit
, WHITESPACE
);
3293 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3297 path
= strndup(rvalue
, n
);
3301 if (!path_startswith(path
, "/dev")) {
3302 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3306 if (streq("infinity", limit
)) {
3307 num
= CGROUP_LIMIT_MAX
;
3309 r
= parse_size(limit
, 1000, &num
);
3310 if (r
< 0 || num
<= 0) {
3311 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3316 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3317 if (path_equal(path
, t
->path
)) {
3324 CGroupIOLimitType ttype
;
3326 l
= new0(CGroupIODeviceLimit
, 1);
3332 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3333 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3335 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3338 l
->limits
[type
] = num
;
3343 int config_parse_blockio_weight(
3345 const char *filename
,
3347 const char *section
,
3348 unsigned section_line
,
3355 uint64_t *weight
= data
;
3362 r
= cg_blkio_weight_parse(rvalue
, weight
);
3364 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3371 int config_parse_blockio_device_weight(
3373 const char *filename
,
3375 const char *section
,
3376 unsigned section_line
,
3383 _cleanup_free_
char *path
= NULL
;
3384 CGroupBlockIODeviceWeight
*w
;
3385 CGroupContext
*c
= data
;
3395 if (isempty(rvalue
)) {
3396 while (c
->blockio_device_weights
)
3397 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3402 n
= strcspn(rvalue
, WHITESPACE
);
3403 weight
= rvalue
+ n
;
3404 weight
+= strspn(weight
, WHITESPACE
);
3406 if (isempty(weight
)) {
3407 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3411 path
= strndup(rvalue
, n
);
3415 if (!path_startswith(path
, "/dev")) {
3416 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3420 r
= cg_blkio_weight_parse(weight
, &u
);
3422 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3426 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3428 w
= new0(CGroupBlockIODeviceWeight
, 1);
3437 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3441 int config_parse_blockio_bandwidth(
3443 const char *filename
,
3445 const char *section
,
3446 unsigned section_line
,
3453 _cleanup_free_
char *path
= NULL
;
3454 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3455 CGroupContext
*c
= data
;
3456 const char *bandwidth
;
3466 read
= streq("BlockIOReadBandwidth", lvalue
);
3468 if (isempty(rvalue
)) {
3469 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3470 b
->rbps
= CGROUP_LIMIT_MAX
;
3471 b
->wbps
= CGROUP_LIMIT_MAX
;
3476 n
= strcspn(rvalue
, WHITESPACE
);
3477 bandwidth
= rvalue
+ n
;
3478 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3481 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3485 path
= strndup(rvalue
, n
);
3489 if (!path_startswith(path
, "/dev")) {
3490 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3494 r
= parse_size(bandwidth
, 1000, &bytes
);
3495 if (r
< 0 || bytes
<= 0) {
3496 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3500 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3501 if (path_equal(path
, t
->path
)) {
3508 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3514 b
->rbps
= CGROUP_LIMIT_MAX
;
3515 b
->wbps
= CGROUP_LIMIT_MAX
;
3517 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3528 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3530 int config_parse_job_mode_isolate(
3532 const char *filename
,
3534 const char *section
,
3535 unsigned section_line
,
3549 r
= parse_boolean(rvalue
);
3551 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3555 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3559 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3561 int config_parse_exec_directories(
3563 const char *filename
,
3565 const char *section
,
3566 unsigned section_line
,
3583 if (isempty(rvalue
)) {
3584 /* Empty assignment resets the list */
3585 *rt
= strv_free(*rt
);
3589 for (p
= rvalue
;;) {
3590 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3592 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3598 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3599 "Invalid syntax, ignoring: %s", rvalue
);
3603 r
= unit_full_printf(u
, word
, &k
);
3605 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3606 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3610 if (!path_is_safe(k
) || path_is_absolute(k
)) {
3611 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3612 "%s is not valid, ignoring assignment: %s", lvalue
, rvalue
);
3616 r
= strv_push(rt
, k
);
3623 int config_parse_set_status(
3625 const char *filename
,
3627 const char *section
,
3628 unsigned section_line
,
3636 const char *word
, *state
;
3638 ExitStatusSet
*status_set
= data
;
3645 /* Empty assignment resets the list */
3646 if (isempty(rvalue
)) {
3647 exit_status_set_free(status_set
);
3651 FOREACH_WORD(word
, l
, rvalue
, state
) {
3652 _cleanup_free_
char *temp
;
3656 temp
= strndup(word
, l
);
3660 r
= safe_atoi(temp
, &val
);
3662 val
= signal_from_string_try_harder(temp
);
3665 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3668 set
= &status_set
->signal
;
3670 if (val
< 0 || val
> 255) {
3671 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3674 set
= &status_set
->status
;
3677 r
= set_ensure_allocated(set
, NULL
);
3681 r
= set_put(*set
, INT_TO_PTR(val
));
3683 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3687 if (!isempty(state
))
3688 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3693 int config_parse_namespace_path_strv(
3695 const char *filename
,
3697 const char *section
,
3698 unsigned section_line
,
3715 if (isempty(rvalue
)) {
3716 /* Empty assignment resets the list */
3717 *sv
= strv_free(*sv
);
3723 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3725 bool ignore_enoent
= false, shall_prefix
= false;
3727 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3733 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3737 if (!utf8_is_valid(word
)) {
3738 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3743 if (startswith(w
, "-")) {
3744 ignore_enoent
= true;
3747 if (startswith(w
, "+")) {
3748 shall_prefix
= true;
3752 r
= unit_full_printf(u
, w
, &resolved
);
3754 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3758 if (!path_is_absolute(resolved
)) {
3759 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3763 path_kill_slashes(resolved
);
3765 joined
= strjoin(ignore_enoent
? "-" : "",
3766 shall_prefix
? "+" : "",
3769 r
= strv_push(sv
, joined
);
3779 int config_parse_bind_paths(
3781 const char *filename
,
3783 const char *section
,
3784 unsigned section_line
,
3791 ExecContext
*c
= data
;
3801 if (isempty(rvalue
)) {
3802 /* Empty assignment resets the list */
3803 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3804 c
->bind_mounts
= NULL
;
3805 c
->n_bind_mounts
= 0;
3811 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3812 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3813 char *s
= NULL
, *d
= NULL
;
3814 bool rbind
= true, ignore_enoent
= false;
3816 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3822 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3826 r
= unit_full_printf(u
, source
, &sresolved
);
3828 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3829 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3835 ignore_enoent
= true;
3839 if (!utf8_is_valid(s
)) {
3840 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3843 if (!path_is_absolute(s
)) {
3844 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3848 path_kill_slashes(s
);
3850 /* Optionally, the destination is specified. */
3851 if (p
&& p
[-1] == ':') {
3852 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3856 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3860 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3864 r
= unit_full_printf(u
, destination
, &dresolved
);
3866 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3867 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3871 if (!utf8_is_valid(dresolved
)) {
3872 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
3875 if (!path_is_absolute(dresolved
)) {
3876 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
3880 d
= path_kill_slashes(dresolved
);
3882 /* Optionally, there's also a short option string specified */
3883 if (p
&& p
[-1] == ':') {
3884 _cleanup_free_
char *options
= NULL
;
3886 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
3890 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3894 if (isempty(options
) || streq(options
, "rbind"))
3896 else if (streq(options
, "norbind"))
3899 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
3906 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
3910 .read_only
= !!strstr(lvalue
, "ReadOnly"),
3912 .ignore_enoent
= ignore_enoent
,
3921 int config_parse_no_new_privileges(
3923 const char *filename
,
3925 const char *section
,
3926 unsigned section_line
,
3933 ExecContext
*c
= data
;
3941 k
= parse_boolean(rvalue
);
3943 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3947 c
->no_new_privileges
= k
;
3952 int config_parse_protect_home(
3954 const char *filename
,
3956 const char *section
,
3957 unsigned section_line
,
3964 ExecContext
*c
= data
;
3972 /* Our enum shall be a superset of booleans, hence first try
3973 * to parse as boolean, and then as enum */
3975 k
= parse_boolean(rvalue
);
3977 c
->protect_home
= PROTECT_HOME_YES
;
3979 c
->protect_home
= PROTECT_HOME_NO
;
3983 h
= protect_home_from_string(rvalue
);
3985 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3989 c
->protect_home
= h
;
3995 int config_parse_protect_system(
3997 const char *filename
,
3999 const char *section
,
4000 unsigned section_line
,
4007 ExecContext
*c
= data
;
4015 /* Our enum shall be a superset of booleans, hence first try
4016 * to parse as boolean, and then as enum */
4018 k
= parse_boolean(rvalue
);
4020 c
->protect_system
= PROTECT_SYSTEM_YES
;
4022 c
->protect_system
= PROTECT_SYSTEM_NO
;
4026 s
= protect_system_from_string(rvalue
);
4028 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4032 c
->protect_system
= s
;
4038 #define FOLLOW_MAX 8
4040 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4051 /* This will update the filename pointer if the loaded file is
4052 * reached by a symlink. The old string will be freed. */
4055 char *target
, *name
;
4057 if (c
++ >= FOLLOW_MAX
)
4060 path_kill_slashes(*filename
);
4062 /* Add the file name we are currently looking at to
4063 * the names of this unit, but only if it is a valid
4065 name
= basename(*filename
);
4066 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4068 id
= set_get(names
, name
);
4074 r
= set_consume(names
, id
);
4080 /* Try to open the file name, but don't if its a symlink */
4081 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4088 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4089 r
= readlink_and_make_absolute(*filename
, &target
);
4097 f
= fdopen(fd
, "re");
4109 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4117 /* Let's try to add in all symlink names we found */
4118 while ((k
= set_steal_first(names
))) {
4120 /* First try to merge in the other name into our
4122 r
= unit_merge_by_name(*u
, k
);
4126 /* Hmm, we couldn't merge the other unit into
4127 * ours? Then let's try it the other way
4130 /* If the symlink name we are looking at is unit template, then
4131 we must search for instance of this template */
4132 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4133 _cleanup_free_
char *instance
= NULL
;
4135 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4139 other
= manager_get_unit((*u
)->manager
, instance
);
4141 other
= manager_get_unit((*u
)->manager
, k
);
4146 r
= unit_merge(other
, *u
);
4149 return merge_by_names(u
, names
, NULL
);
4157 unit_choose_id(*u
, id
);
4165 static int load_from_path(Unit
*u
, const char *path
) {
4166 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4167 _cleanup_fclose_
FILE *f
= NULL
;
4168 _cleanup_free_
char *filename
= NULL
;
4177 symlink_names
= set_new(&string_hash_ops
);
4181 if (path_is_absolute(path
)) {
4183 filename
= strdup(path
);
4187 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4189 filename
= mfree(filename
);
4197 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4199 /* Instead of opening the path right away, we manually
4200 * follow all symlinks and add their name to our unit
4201 * name set while doing so */
4202 filename
= path_make_absolute(path
, *p
);
4206 if (u
->manager
->unit_path_cache
&&
4207 !set_get(u
->manager
->unit_path_cache
, filename
))
4210 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4213 filename
= mfree(filename
);
4215 /* ENOENT means that the file is missing or is a dangling symlink.
4216 * ENOTDIR means that one of paths we expect to be is a directory
4217 * is not a directory, we should just ignore that.
4218 * EACCES means that the directory or file permissions are wrong.
4221 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4222 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4225 /* Empty the symlink names for the next run */
4226 set_clear_free(symlink_names
);
4231 /* Hmm, no suitable file found? */
4234 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4235 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4240 r
= merge_by_names(&merged
, symlink_names
, id
);
4245 u
->load_state
= UNIT_MERGED
;
4249 if (fstat(fileno(f
), &st
) < 0)
4252 if (null_or_empty(&st
)) {
4253 u
->load_state
= UNIT_MASKED
;
4254 u
->fragment_mtime
= 0;
4256 u
->load_state
= UNIT_LOADED
;
4257 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4259 /* Now, parse the file contents */
4260 r
= config_parse(u
->id
, filename
, f
,
4261 UNIT_VTABLE(u
)->sections
,
4262 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4263 false, true, false, u
);
4268 free(u
->fragment_path
);
4269 u
->fragment_path
= filename
;
4272 if (u
->source_path
) {
4273 if (stat(u
->source_path
, &st
) >= 0)
4274 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4276 u
->source_mtime
= 0;
4282 int unit_load_fragment(Unit
*u
) {
4288 assert(u
->load_state
== UNIT_STUB
);
4292 u
->load_state
= UNIT_LOADED
;
4296 /* First, try to find the unit under its id. We always look
4297 * for unit files in the default directories, to make it easy
4298 * to override things by placing things in /etc/systemd/system */
4299 r
= load_from_path(u
, u
->id
);
4303 /* Try to find an alias we can load this with */
4304 if (u
->load_state
== UNIT_STUB
) {
4305 SET_FOREACH(t
, u
->names
, i
) {
4310 r
= load_from_path(u
, t
);
4314 if (u
->load_state
!= UNIT_STUB
)
4319 /* And now, try looking for it under the suggested (originally linked) path */
4320 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4322 r
= load_from_path(u
, u
->fragment_path
);
4326 if (u
->load_state
== UNIT_STUB
)
4327 /* Hmm, this didn't work? Then let's get rid
4328 * of the fragment path stored for us, so that
4329 * we don't point to an invalid location. */
4330 u
->fragment_path
= mfree(u
->fragment_path
);
4333 /* Look for a template */
4334 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4335 _cleanup_free_
char *k
= NULL
;
4337 r
= unit_name_template(u
->id
, &k
);
4341 r
= load_from_path(u
, k
);
4344 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4348 if (u
->load_state
== UNIT_STUB
) {
4349 SET_FOREACH(t
, u
->names
, i
) {
4350 _cleanup_free_
char *z
= NULL
;
4355 r
= unit_name_template(t
, &z
);
4359 r
= load_from_path(u
, z
);
4363 if (u
->load_state
!= UNIT_STUB
)
4372 void unit_dump_config_items(FILE *f
) {
4373 static const struct {
4374 const ConfigParserCallback callback
;
4377 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4378 { config_parse_warn_compat
, "NOTSUPPORTED" },
4380 { config_parse_int
, "INTEGER" },
4381 { config_parse_unsigned
, "UNSIGNED" },
4382 { config_parse_iec_size
, "SIZE" },
4383 { config_parse_iec_uint64
, "SIZE" },
4384 { config_parse_si_size
, "SIZE" },
4385 { config_parse_bool
, "BOOLEAN" },
4386 { config_parse_string
, "STRING" },
4387 { config_parse_path
, "PATH" },
4388 { config_parse_unit_path_printf
, "PATH" },
4389 { config_parse_strv
, "STRING [...]" },
4390 { config_parse_exec_nice
, "NICE" },
4391 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4392 { config_parse_exec_io_class
, "IOCLASS" },
4393 { config_parse_exec_io_priority
, "IOPRIORITY" },
4394 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4395 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4396 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4397 { config_parse_mode
, "MODE" },
4398 { config_parse_unit_env_file
, "FILE" },
4399 { config_parse_exec_output
, "OUTPUT" },
4400 { config_parse_exec_input
, "INPUT" },
4401 { config_parse_log_facility
, "FACILITY" },
4402 { config_parse_log_level
, "LEVEL" },
4403 { config_parse_exec_secure_bits
, "SECUREBITS" },
4404 { config_parse_capability_set
, "BOUNDINGSET" },
4405 { config_parse_limit
, "LIMIT" },
4406 { config_parse_unit_deps
, "UNIT [...]" },
4407 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4408 { config_parse_service_type
, "SERVICETYPE" },
4409 { config_parse_service_restart
, "SERVICERESTART" },
4410 #ifdef HAVE_SYSV_COMPAT
4411 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4413 { config_parse_kill_mode
, "KILLMODE" },
4414 { config_parse_signal
, "SIGNAL" },
4415 { config_parse_socket_listen
, "SOCKET [...]" },
4416 { config_parse_socket_bind
, "SOCKETBIND" },
4417 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4418 { config_parse_sec
, "SECONDS" },
4419 { config_parse_nsec
, "NANOSECONDS" },
4420 { config_parse_namespace_path_strv
, "PATH [...]" },
4421 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4422 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4423 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4424 { config_parse_unit_string_printf
, "STRING" },
4425 { config_parse_trigger_unit
, "UNIT" },
4426 { config_parse_timer
, "TIMER" },
4427 { config_parse_path_spec
, "PATH" },
4428 { config_parse_notify_access
, "ACCESS" },
4429 { config_parse_ip_tos
, "TOS" },
4430 { config_parse_unit_condition_path
, "CONDITION" },
4431 { config_parse_unit_condition_string
, "CONDITION" },
4432 { config_parse_unit_condition_null
, "CONDITION" },
4433 { config_parse_unit_slice
, "SLICE" },
4434 { config_parse_documentation
, "URL" },
4435 { config_parse_service_timeout
, "SECONDS" },
4436 { config_parse_emergency_action
, "ACTION" },
4437 { config_parse_set_status
, "STATUS" },
4438 { config_parse_service_sockets
, "SOCKETS" },
4439 { config_parse_environ
, "ENVIRON" },
4441 { config_parse_syscall_filter
, "SYSCALLS" },
4442 { config_parse_syscall_archs
, "ARCHS" },
4443 { config_parse_syscall_errno
, "ERRNO" },
4444 { config_parse_address_families
, "FAMILIES" },
4445 { config_parse_restrict_namespaces
, "NAMESPACES" },
4447 { config_parse_cpu_shares
, "SHARES" },
4448 { config_parse_cpu_weight
, "WEIGHT" },
4449 { config_parse_memory_limit
, "LIMIT" },
4450 { config_parse_device_allow
, "DEVICE" },
4451 { config_parse_device_policy
, "POLICY" },
4452 { config_parse_io_limit
, "LIMIT" },
4453 { config_parse_io_weight
, "WEIGHT" },
4454 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4455 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4456 { config_parse_blockio_weight
, "WEIGHT" },
4457 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4458 { config_parse_long
, "LONG" },
4459 { config_parse_socket_service
, "SERVICE" },
4461 { config_parse_exec_selinux_context
, "LABEL" },
4463 { config_parse_job_mode
, "MODE" },
4464 { config_parse_job_mode_isolate
, "BOOLEAN" },
4465 { config_parse_personality
, "PERSONALITY" },
4468 const char *prev
= NULL
;
4473 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4474 const char *rvalue
= "OTHER", *lvalue
;
4478 const ConfigPerfItem
*p
;
4480 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4482 dot
= strchr(i
, '.');
4483 lvalue
= dot
? dot
+ 1 : i
;
4487 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4491 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4494 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4495 if (p
->parse
== table
[j
].callback
) {
4496 rvalue
= table
[j
].rvalue
;
4500 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);