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 ExecCommandFlags flags
= 0;
612 bool ignore
= false, separate_argv0
= false;
613 _cleanup_free_ ExecCommand
*nce
= NULL
;
614 _cleanup_strv_free_
char **n
= NULL
;
615 size_t nlen
= 0, nbufsize
= 0;
620 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
626 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
627 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
628 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
629 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
630 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
631 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
632 * other sandboxing, with some special exceptions for changing UID.
634 * The idea is that '!!' may be used to write services that can take benefit of systemd's
635 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
636 * privilege dropping within the daemon if the kernel does not offer that. */
638 if (*f
== '-' && !(flags
& EXEC_COMMAND_IGNORE_FAILURE
)) {
639 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
641 } else if (*f
== '@' && !separate_argv0
)
642 separate_argv0
= true;
643 else if (*f
== '+' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
644 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
645 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
646 flags
|= EXEC_COMMAND_NO_SETUID
;
647 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
648 flags
&= ~EXEC_COMMAND_NO_SETUID
;
649 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
655 r
= unit_full_printf(u
, f
, &path
);
657 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
658 "Failed to resolve unit specifiers on %s%s: %m",
659 f
, ignore
? ", ignoring" : "");
660 return ignore
? 0 : -ENOEXEC
;
664 /* First word is either "-" or "@" with no command. */
665 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
666 "Empty path in command line%s: \"%s\"",
667 ignore
? ", ignoring" : "", rvalue
);
668 return ignore
? 0 : -ENOEXEC
;
670 if (!string_is_safe(path
)) {
671 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
672 "Executable path contains special characters%s: %s",
673 ignore
? ", ignoring" : "", rvalue
);
674 return ignore
? 0 : -ENOEXEC
;
676 if (!path_is_absolute(path
)) {
677 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
678 "Executable path is not absolute%s: %s",
679 ignore
? ", ignoring" : "", rvalue
);
680 return ignore
? 0 : -ENOEXEC
;
682 if (endswith(path
, "/")) {
683 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
684 "Executable path specifies a directory%s: %s",
685 ignore
? ", ignoring" : "", rvalue
);
686 return ignore
? 0 : -ENOEXEC
;
689 if (!separate_argv0
) {
692 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
702 path_kill_slashes(path
);
704 while (!isempty(p
)) {
705 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
707 /* Check explicitly for an unquoted semicolon as
708 * command separator token. */
709 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
711 p
+= strspn(p
, WHITESPACE
);
716 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
717 * extract_first_word() would return the same for all of those. */
718 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
722 p
+= strspn(p
, WHITESPACE
);
724 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
735 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
739 return ignore
? 0 : -ENOEXEC
;
741 r
= unit_full_printf(u
, word
, &resolved
);
743 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
744 "Failed to resolve unit specifiers on %s%s: %m",
745 word
, ignore
? ", ignoring" : "");
746 return ignore
? 0 : -ENOEXEC
;
749 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
751 n
[nlen
++] = resolved
;
757 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
758 "Empty executable name or zeroeth argument%s: %s",
759 ignore
? ", ignoring" : "", rvalue
);
760 return ignore
? 0 : -ENOEXEC
;
763 nce
= new0(ExecCommand
, 1);
771 exec_command_append_list(e
, nce
);
773 /* Do not _cleanup_free_ these. */
784 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
785 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
787 int config_parse_socket_bindtodevice(
789 const char *filename
,
792 unsigned section_line
,
807 if (rvalue
[0] && !streq(rvalue
, "*")) {
808 if (!ifname_valid(rvalue
)) {
809 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
819 free(s
->bind_to_device
);
820 s
->bind_to_device
= n
;
825 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
826 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
828 int config_parse_exec_input(const char *unit
,
829 const char *filename
,
832 unsigned section_line
,
838 ExecContext
*c
= data
;
847 name
= startswith(rvalue
, "fd:");
849 /* Strip prefix and validate fd name */
850 if (!fdname_is_valid(name
)) {
851 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
854 c
->std_input
= EXEC_INPUT_NAMED_FD
;
855 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
860 ExecInput ei
= exec_input_from_string(rvalue
);
861 if (ei
== _EXEC_INPUT_INVALID
)
862 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
869 int config_parse_exec_output(const char *unit
,
870 const char *filename
,
873 unsigned section_line
,
879 ExecContext
*c
= data
;
890 name
= startswith(rvalue
, "fd:");
892 /* Strip prefix and validate fd name */
893 if (!fdname_is_valid(name
)) {
894 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
897 eo
= EXEC_OUTPUT_NAMED_FD
;
899 eo
= exec_output_from_string(rvalue
);
900 if (eo
== _EXEC_OUTPUT_INVALID
) {
901 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
906 if (streq(lvalue
, "StandardOutput")) {
908 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
912 } else if (streq(lvalue
, "StandardError")) {
914 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
919 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
924 int config_parse_exec_io_class(const char *unit
,
925 const char *filename
,
928 unsigned section_line
,
935 ExecContext
*c
= data
;
943 x
= ioprio_class_from_string(rvalue
);
945 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
949 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
950 c
->ioprio_set
= true;
955 int config_parse_exec_io_priority(const char *unit
,
956 const char *filename
,
959 unsigned section_line
,
966 ExecContext
*c
= data
;
974 r
= ioprio_parse_priority(rvalue
, &i
);
976 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
980 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
981 c
->ioprio_set
= true;
986 int config_parse_exec_cpu_sched_policy(const char *unit
,
987 const char *filename
,
990 unsigned section_line
,
998 ExecContext
*c
= data
;
1006 x
= sched_policy_from_string(rvalue
);
1008 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1012 c
->cpu_sched_policy
= x
;
1013 /* Moving to or from real-time policy? We need to adjust the priority */
1014 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1015 c
->cpu_sched_set
= true;
1020 int config_parse_exec_cpu_sched_prio(const char *unit
,
1021 const char *filename
,
1023 const char *section
,
1024 unsigned section_line
,
1031 ExecContext
*c
= data
;
1039 r
= safe_atoi(rvalue
, &i
);
1041 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1045 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1046 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1047 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1049 if (i
< min
|| i
> max
) {
1050 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1054 c
->cpu_sched_priority
= i
;
1055 c
->cpu_sched_set
= true;
1060 int config_parse_exec_cpu_affinity(const char *unit
,
1061 const char *filename
,
1063 const char *section
,
1064 unsigned section_line
,
1071 ExecContext
*c
= data
;
1072 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1080 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1085 CPU_FREE(c
->cpuset
);
1088 /* An empty assignment resets the CPU list */
1094 c
->cpuset_ncpus
= ncpus
;
1099 int config_parse_exec_secure_bits(const char *unit
,
1100 const char *filename
,
1102 const char *section
,
1103 unsigned section_line
,
1110 ExecContext
*c
= data
;
1118 if (isempty(rvalue
)) {
1119 /* An empty assignment resets the field */
1124 r
= secure_bits_from_string(rvalue
);
1128 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1129 "Invalid syntax, ignoring: %s", rvalue
);
1138 int config_parse_capability_set(
1140 const char *filename
,
1142 const char *section
,
1143 unsigned section_line
,
1150 uint64_t *capability_set
= data
;
1151 uint64_t sum
= 0, initial
= 0;
1152 bool invert
= false;
1160 if (rvalue
[0] == '~') {
1165 if (streq(lvalue
, "CapabilityBoundingSet"))
1166 initial
= CAP_ALL
; /* initialized to all bits on */
1167 /* else "AmbientCapabilities" initialized to all bits off */
1169 r
= capability_set_from_string(rvalue
, &sum
);
1173 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1177 sum
= invert
? ~sum
: sum
;
1179 if (sum
== 0 || *capability_set
== initial
)
1180 /* "" or uninitialized data -> replace */
1181 *capability_set
= sum
;
1183 /* previous data -> merge */
1184 *capability_set
|= sum
;
1189 int config_parse_limit(
1191 const char *filename
,
1193 const char *section
,
1194 unsigned section_line
,
1201 struct rlimit
**rl
= data
, d
= {};
1209 r
= rlimit_parse(ltype
, rvalue
, &d
);
1211 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1215 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1222 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1230 #ifdef HAVE_SYSV_COMPAT
1231 int config_parse_sysv_priority(const char *unit
,
1232 const char *filename
,
1234 const char *section
,
1235 unsigned section_line
,
1242 int *priority
= data
;
1250 r
= safe_atoi(rvalue
, &i
);
1251 if (r
< 0 || i
< 0) {
1252 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1256 *priority
= (int) i
;
1261 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1262 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1264 int config_parse_exec_mount_flags(
1266 const char *filename
,
1268 const char *section
,
1269 unsigned section_line
,
1277 ExecContext
*c
= data
;
1285 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1287 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1292 int config_parse_exec_selinux_context(
1294 const char *filename
,
1296 const char *section
,
1297 unsigned section_line
,
1304 ExecContext
*c
= data
;
1315 if (isempty(rvalue
)) {
1316 c
->selinux_context
= mfree(c
->selinux_context
);
1317 c
->selinux_context_ignore
= false;
1321 if (rvalue
[0] == '-') {
1327 r
= unit_full_printf(u
, rvalue
, &k
);
1329 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1330 "Failed to resolve specifiers%s: %m",
1331 ignore
? ", ignoring" : "");
1332 return ignore
? 0 : -ENOEXEC
;
1335 free(c
->selinux_context
);
1336 c
->selinux_context
= k
;
1337 c
->selinux_context_ignore
= ignore
;
1342 int config_parse_exec_apparmor_profile(
1344 const char *filename
,
1346 const char *section
,
1347 unsigned section_line
,
1354 ExecContext
*c
= data
;
1365 if (isempty(rvalue
)) {
1366 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1367 c
->apparmor_profile_ignore
= false;
1371 if (rvalue
[0] == '-') {
1377 r
= unit_full_printf(u
, rvalue
, &k
);
1379 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1380 "Failed to resolve specifiers%s: %m",
1381 ignore
? ", ignoring" : "");
1382 return ignore
? 0 : -ENOEXEC
;
1385 free(c
->apparmor_profile
);
1386 c
->apparmor_profile
= k
;
1387 c
->apparmor_profile_ignore
= ignore
;
1392 int config_parse_exec_smack_process_label(
1394 const char *filename
,
1396 const char *section
,
1397 unsigned section_line
,
1404 ExecContext
*c
= data
;
1415 if (isempty(rvalue
)) {
1416 c
->smack_process_label
= mfree(c
->smack_process_label
);
1417 c
->smack_process_label_ignore
= false;
1421 if (rvalue
[0] == '-') {
1427 r
= unit_full_printf(u
, rvalue
, &k
);
1429 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1430 "Failed to resolve specifiers%s: %m",
1431 ignore
? ", ignoring" : "");
1432 return ignore
? 0 : -ENOEXEC
;
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: %s", rvalue
);
1654 if (!endswith(p
, ".service")) {
1655 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %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: %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: %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: %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: %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: %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: %s", k
);
1989 r
= strv_push(users
, k
);
1999 int config_parse_working_directory(
2001 const char *filename
,
2003 const char *section
,
2004 unsigned section_line
,
2011 ExecContext
*c
= data
;
2022 if (rvalue
[0] == '-') {
2028 if (streq(rvalue
, "~")) {
2029 c
->working_directory_home
= true;
2030 c
->working_directory
= mfree(c
->working_directory
);
2032 _cleanup_free_
char *k
= NULL
;
2034 r
= unit_full_printf(u
, rvalue
, &k
);
2036 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2037 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2038 rvalue
, missing_ok
? ", ignoring" : "");
2039 return missing_ok
? 0 : -ENOEXEC
;
2042 path_kill_slashes(k
);
2044 if (!utf8_is_valid(k
)) {
2045 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2046 return missing_ok
? 0 : -ENOEXEC
;
2049 if (!path_is_absolute(k
)) {
2050 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2051 "Working directory path '%s' is not absolute%s.",
2052 rvalue
, missing_ok
? ", ignoring" : "");
2053 return missing_ok
? 0 : -ENOEXEC
;
2056 c
->working_directory_home
= false;
2057 free_and_replace(c
->working_directory
, k
);
2060 c
->working_directory_missing_ok
= missing_ok
;
2064 int config_parse_unit_env_file(const char *unit
,
2065 const char *filename
,
2067 const char *section
,
2068 unsigned section_line
,
2077 _cleanup_free_
char *n
= NULL
;
2085 if (isempty(rvalue
)) {
2086 /* Empty assignment frees the list */
2087 *env
= strv_free(*env
);
2091 r
= unit_full_printf(u
, rvalue
, &n
);
2093 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2097 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2098 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2102 r
= strv_extend(env
, n
);
2109 int config_parse_environ(const char *unit
,
2110 const char *filename
,
2112 const char *section
,
2113 unsigned section_line
,
2130 if (isempty(rvalue
)) {
2131 /* Empty assignment resets the list */
2132 *env
= strv_free(*env
);
2136 for (p
= rvalue
;; ) {
2137 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2139 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2145 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2146 "Invalid syntax, ignoring: %s", rvalue
);
2151 r
= unit_full_printf(u
, word
, &k
);
2153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2154 "Failed to resolve specifiers, ignoring: %s", k
);
2162 if (!env_assignment_is_valid(k
)) {
2163 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2164 "Invalid environment assignment, ignoring: %s", k
);
2168 r
= strv_env_replace(env
, k
);
2175 int config_parse_pass_environ(const char *unit
,
2176 const char *filename
,
2178 const char *section
,
2179 unsigned section_line
,
2186 const char *whole_rvalue
= rvalue
;
2187 char*** passenv
= data
;
2188 _cleanup_strv_free_
char **n
= NULL
;
2189 size_t nlen
= 0, nbufsize
= 0;
2197 if (isempty(rvalue
)) {
2198 /* Empty assignment resets the list */
2199 *passenv
= strv_free(*passenv
);
2204 _cleanup_free_
char *word
= NULL
;
2206 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2212 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2213 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2217 if (!env_name_is_valid(word
)) {
2218 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2219 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2223 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2231 r
= strv_extend_strv(passenv
, n
, true);
2239 int config_parse_ip_tos(const char *unit
,
2240 const char *filename
,
2242 const char *section
,
2243 unsigned section_line
,
2250 int *ip_tos
= data
, x
;
2257 x
= ip_tos_from_string(rvalue
);
2259 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2267 int config_parse_unit_condition_path(
2269 const char *filename
,
2271 const char *section
,
2272 unsigned section_line
,
2279 _cleanup_free_
char *p
= NULL
;
2280 Condition
**list
= data
, *c
;
2281 ConditionType t
= ltype
;
2282 bool trigger
, negate
;
2291 if (isempty(rvalue
)) {
2292 /* Empty assignment resets the list */
2293 *list
= condition_free_list(*list
);
2297 trigger
= rvalue
[0] == '|';
2301 negate
= rvalue
[0] == '!';
2305 r
= unit_full_printf(u
, rvalue
, &p
);
2307 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2311 if (!path_is_absolute(p
)) {
2312 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2316 c
= condition_new(t
, p
, trigger
, negate
);
2320 LIST_PREPEND(conditions
, *list
, c
);
2324 int config_parse_unit_condition_string(
2326 const char *filename
,
2328 const char *section
,
2329 unsigned section_line
,
2336 _cleanup_free_
char *s
= NULL
;
2337 Condition
**list
= data
, *c
;
2338 ConditionType t
= ltype
;
2339 bool trigger
, negate
;
2348 if (isempty(rvalue
)) {
2349 /* Empty assignment resets the list */
2350 *list
= condition_free_list(*list
);
2354 trigger
= rvalue
[0] == '|';
2358 negate
= rvalue
[0] == '!';
2362 r
= unit_full_printf(u
, rvalue
, &s
);
2364 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2368 c
= condition_new(t
, s
, trigger
, negate
);
2372 LIST_PREPEND(conditions
, *list
, c
);
2376 int config_parse_unit_condition_null(
2378 const char *filename
,
2380 const char *section
,
2381 unsigned section_line
,
2388 Condition
**list
= data
, *c
;
2389 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 b
= parse_boolean(rvalue
);
2413 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2420 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2424 LIST_PREPEND(conditions
, *list
, c
);
2428 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2429 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2431 int config_parse_unit_requires_mounts_for(
2433 const char *filename
,
2435 const char *section
,
2436 unsigned section_line
,
2452 for (p
= rvalue
;; ) {
2453 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2455 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2461 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2462 "Invalid syntax, ignoring: %s", rvalue
);
2466 if (!utf8_is_valid(word
)) {
2467 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2471 r
= unit_full_printf(u
, word
, &resolved
);
2473 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2477 r
= unit_require_mounts_for(u
, resolved
);
2479 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2485 int config_parse_documentation(const char *unit
,
2486 const char *filename
,
2488 const char *section
,
2489 unsigned section_line
,
2505 if (isempty(rvalue
)) {
2506 /* Empty assignment resets the list */
2507 u
->documentation
= strv_free(u
->documentation
);
2511 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2512 rvalue
, data
, userdata
);
2516 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2518 if (documentation_url_is_valid(*a
))
2521 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2533 static int syscall_filter_parse_one(
2535 const char *filename
,
2544 const SyscallFilterSet
*set
;
2547 set
= syscall_filter_set_find(t
);
2550 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2554 NULSTR_FOREACH(i
, set
->value
) {
2555 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2562 id
= seccomp_syscall_resolve_name(t
);
2563 if (id
== __NR_SCMP_ERROR
) {
2565 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2569 /* If we previously wanted to forbid a syscall and now
2570 * we want to allow it, then remove it from the list
2572 if (!invert
== c
->syscall_whitelist
) {
2573 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2579 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2585 int config_parse_syscall_filter(
2587 const char *filename
,
2589 const char *section
,
2590 unsigned section_line
,
2597 ExecContext
*c
= data
;
2599 bool invert
= false;
2608 if (isempty(rvalue
)) {
2609 /* Empty assignment resets the list */
2610 c
->syscall_filter
= set_free(c
->syscall_filter
);
2611 c
->syscall_whitelist
= false;
2615 if (rvalue
[0] == '~') {
2620 if (!c
->syscall_filter
) {
2621 c
->syscall_filter
= set_new(NULL
);
2622 if (!c
->syscall_filter
)
2626 /* Allow everything but the ones listed */
2627 c
->syscall_whitelist
= false;
2629 /* Allow nothing but the ones listed */
2630 c
->syscall_whitelist
= true;
2632 /* Accept default syscalls if we are on a whitelist */
2633 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2641 _cleanup_free_
char *word
= NULL
;
2643 r
= extract_first_word(&p
, &word
, NULL
, 0);
2649 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2653 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2661 int config_parse_syscall_archs(
2663 const char *filename
,
2665 const char *section
,
2666 unsigned section_line
,
2677 if (isempty(rvalue
)) {
2678 *archs
= set_free(*archs
);
2682 r
= set_ensure_allocated(archs
, NULL
);
2686 for (p
= rvalue
;;) {
2687 _cleanup_free_
char *word
= NULL
;
2690 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2696 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2697 "Invalid syntax, ignoring: %s", rvalue
);
2701 r
= seccomp_arch_from_string(word
, &a
);
2703 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2704 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2708 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2714 int config_parse_syscall_errno(
2716 const char *filename
,
2718 const char *section
,
2719 unsigned section_line
,
2726 ExecContext
*c
= data
;
2733 if (isempty(rvalue
)) {
2734 /* Empty assignment resets to KILL */
2735 c
->syscall_errno
= 0;
2739 e
= errno_from_name(rvalue
);
2741 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2745 c
->syscall_errno
= e
;
2749 int config_parse_address_families(
2751 const char *filename
,
2753 const char *section
,
2754 unsigned section_line
,
2761 ExecContext
*c
= data
;
2762 bool invert
= false;
2770 if (isempty(rvalue
)) {
2771 /* Empty assignment resets the list */
2772 c
->address_families
= set_free(c
->address_families
);
2773 c
->address_families_whitelist
= false;
2777 if (rvalue
[0] == '~') {
2782 if (!c
->address_families
) {
2783 c
->address_families
= set_new(NULL
);
2784 if (!c
->address_families
)
2787 c
->address_families_whitelist
= !invert
;
2790 for (p
= rvalue
;;) {
2791 _cleanup_free_
char *word
= NULL
;
2794 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2800 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2801 "Invalid syntax, ignoring: %s", rvalue
);
2805 af
= af_from_name(word
);
2807 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2808 "Failed to parse address family \"%s\", ignoring: %m", word
);
2812 /* If we previously wanted to forbid an address family and now
2813 * we want to allow it, then just remove it from the list.
2815 if (!invert
== c
->address_families_whitelist
) {
2816 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2820 set_remove(c
->address_families
, INT_TO_PTR(af
));
2824 int config_parse_restrict_namespaces(
2826 const char *filename
,
2828 const char *section
,
2829 unsigned section_line
,
2836 ExecContext
*c
= data
;
2837 bool invert
= false;
2840 if (isempty(rvalue
)) {
2841 /* Reset to the default. */
2842 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2846 if (rvalue
[0] == '~') {
2851 r
= parse_boolean(rvalue
);
2853 c
->restrict_namespaces
= 0;
2855 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2857 /* Not a boolean argument, in this case it's a list of namespace types. */
2859 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2861 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2867 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2873 int config_parse_unit_slice(
2875 const char *filename
,
2877 const char *section
,
2878 unsigned section_line
,
2885 _cleanup_free_
char *k
= NULL
;
2886 Unit
*u
= userdata
, *slice
= NULL
;
2894 r
= unit_name_printf(u
, rvalue
, &k
);
2896 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2900 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2902 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2906 r
= unit_set_slice(u
, slice
);
2908 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2915 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2917 int config_parse_cpu_weight(
2919 const char *filename
,
2921 const char *section
,
2922 unsigned section_line
,
2929 uint64_t *weight
= data
;
2936 r
= cg_weight_parse(rvalue
, weight
);
2938 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
2945 int config_parse_cpu_shares(
2947 const char *filename
,
2949 const char *section
,
2950 unsigned section_line
,
2957 uint64_t *shares
= data
;
2964 r
= cg_cpu_shares_parse(rvalue
, shares
);
2966 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2973 int config_parse_cpu_quota(
2975 const char *filename
,
2977 const char *section
,
2978 unsigned section_line
,
2985 CGroupContext
*c
= data
;
2992 if (isempty(rvalue
)) {
2993 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2997 r
= parse_percent_unbounded(rvalue
);
2999 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3003 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3007 int config_parse_memory_limit(
3009 const char *filename
,
3011 const char *section
,
3012 unsigned section_line
,
3019 CGroupContext
*c
= data
;
3020 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3023 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3025 r
= parse_percent(rvalue
);
3027 r
= parse_size(rvalue
, 1024, &bytes
);
3029 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3033 bytes
= physical_memory_scale(r
, 100U);
3035 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3036 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3041 if (streq(lvalue
, "MemoryLow"))
3042 c
->memory_low
= bytes
;
3043 else if (streq(lvalue
, "MemoryHigh"))
3044 c
->memory_high
= bytes
;
3045 else if (streq(lvalue
, "MemoryMax"))
3046 c
->memory_max
= bytes
;
3047 else if (streq(lvalue
, "MemorySwapMax"))
3048 c
->memory_swap_max
= bytes
;
3049 else if (streq(lvalue
, "MemoryLimit"))
3050 c
->memory_limit
= bytes
;
3057 int config_parse_tasks_max(
3059 const char *filename
,
3061 const char *section
,
3062 unsigned section_line
,
3069 uint64_t *tasks_max
= data
, v
;
3073 if (isempty(rvalue
)) {
3074 *tasks_max
= u
->manager
->default_tasks_max
;
3078 if (streq(rvalue
, "infinity")) {
3079 *tasks_max
= CGROUP_LIMIT_MAX
;
3083 r
= parse_percent(rvalue
);
3085 r
= safe_atou64(rvalue
, &v
);
3087 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3091 v
= system_tasks_max_scale(r
, 100U);
3093 if (v
<= 0 || v
>= UINT64_MAX
) {
3094 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3102 int config_parse_device_allow(
3104 const char *filename
,
3106 const char *section
,
3107 unsigned section_line
,
3114 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3115 CGroupContext
*c
= data
;
3116 CGroupDeviceAllow
*a
;
3117 const char *m
= NULL
;
3121 if (isempty(rvalue
)) {
3122 while (c
->device_allow
)
3123 cgroup_context_free_device_allow(c
, c
->device_allow
);
3128 r
= unit_full_printf(userdata
, rvalue
, &t
);
3130 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3131 "Failed to resolve specifiers in %s, ignoring: %m",
3135 n
= strcspn(t
, WHITESPACE
);
3137 path
= strndup(t
, n
);
3141 if (!is_deviceallow_pattern(path
)) {
3142 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3146 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3150 if (!in_charset(m
, "rwm")) {
3151 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3155 a
= new0(CGroupDeviceAllow
, 1);
3161 a
->r
= !!strchr(m
, 'r');
3162 a
->w
= !!strchr(m
, 'w');
3163 a
->m
= !!strchr(m
, 'm');
3165 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3169 int config_parse_io_weight(
3171 const char *filename
,
3173 const char *section
,
3174 unsigned section_line
,
3181 uint64_t *weight
= data
;
3188 r
= cg_weight_parse(rvalue
, weight
);
3190 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3197 int config_parse_io_device_weight(
3199 const char *filename
,
3201 const char *section
,
3202 unsigned section_line
,
3209 _cleanup_free_
char *path
= NULL
;
3210 CGroupIODeviceWeight
*w
;
3211 CGroupContext
*c
= data
;
3221 if (isempty(rvalue
)) {
3222 while (c
->io_device_weights
)
3223 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3228 n
= strcspn(rvalue
, WHITESPACE
);
3229 weight
= rvalue
+ n
;
3230 weight
+= strspn(weight
, WHITESPACE
);
3232 if (isempty(weight
)) {
3233 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3237 path
= strndup(rvalue
, n
);
3241 if (!path_startswith(path
, "/dev")) {
3242 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3246 r
= cg_weight_parse(weight
, &u
);
3248 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3252 assert(u
!= CGROUP_WEIGHT_INVALID
);
3254 w
= new0(CGroupIODeviceWeight
, 1);
3263 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3267 int config_parse_io_limit(
3269 const char *filename
,
3271 const char *section
,
3272 unsigned section_line
,
3279 _cleanup_free_
char *path
= NULL
;
3280 CGroupIODeviceLimit
*l
= NULL
, *t
;
3281 CGroupContext
*c
= data
;
3282 CGroupIOLimitType type
;
3292 type
= cgroup_io_limit_type_from_string(lvalue
);
3295 if (isempty(rvalue
)) {
3296 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3297 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3301 n
= strcspn(rvalue
, WHITESPACE
);
3303 limit
+= strspn(limit
, WHITESPACE
);
3306 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3310 path
= strndup(rvalue
, n
);
3314 if (!path_startswith(path
, "/dev")) {
3315 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3319 if (streq("infinity", limit
)) {
3320 num
= CGROUP_LIMIT_MAX
;
3322 r
= parse_size(limit
, 1000, &num
);
3323 if (r
< 0 || num
<= 0) {
3324 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3329 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3330 if (path_equal(path
, t
->path
)) {
3337 CGroupIOLimitType ttype
;
3339 l
= new0(CGroupIODeviceLimit
, 1);
3345 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3346 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3348 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3351 l
->limits
[type
] = num
;
3356 int config_parse_blockio_weight(
3358 const char *filename
,
3360 const char *section
,
3361 unsigned section_line
,
3368 uint64_t *weight
= data
;
3375 r
= cg_blkio_weight_parse(rvalue
, weight
);
3377 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3384 int config_parse_blockio_device_weight(
3386 const char *filename
,
3388 const char *section
,
3389 unsigned section_line
,
3396 _cleanup_free_
char *path
= NULL
;
3397 CGroupBlockIODeviceWeight
*w
;
3398 CGroupContext
*c
= data
;
3408 if (isempty(rvalue
)) {
3409 while (c
->blockio_device_weights
)
3410 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3415 n
= strcspn(rvalue
, WHITESPACE
);
3416 weight
= rvalue
+ n
;
3417 weight
+= strspn(weight
, WHITESPACE
);
3419 if (isempty(weight
)) {
3420 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3424 path
= strndup(rvalue
, n
);
3428 if (!path_startswith(path
, "/dev")) {
3429 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3433 r
= cg_blkio_weight_parse(weight
, &u
);
3435 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3439 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3441 w
= new0(CGroupBlockIODeviceWeight
, 1);
3450 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3454 int config_parse_blockio_bandwidth(
3456 const char *filename
,
3458 const char *section
,
3459 unsigned section_line
,
3466 _cleanup_free_
char *path
= NULL
;
3467 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3468 CGroupContext
*c
= data
;
3469 const char *bandwidth
;
3479 read
= streq("BlockIOReadBandwidth", lvalue
);
3481 if (isempty(rvalue
)) {
3482 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3483 b
->rbps
= CGROUP_LIMIT_MAX
;
3484 b
->wbps
= CGROUP_LIMIT_MAX
;
3489 n
= strcspn(rvalue
, WHITESPACE
);
3490 bandwidth
= rvalue
+ n
;
3491 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3494 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3498 path
= strndup(rvalue
, n
);
3502 if (!path_startswith(path
, "/dev")) {
3503 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3507 r
= parse_size(bandwidth
, 1000, &bytes
);
3508 if (r
< 0 || bytes
<= 0) {
3509 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3513 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3514 if (path_equal(path
, t
->path
)) {
3521 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3527 b
->rbps
= CGROUP_LIMIT_MAX
;
3528 b
->wbps
= CGROUP_LIMIT_MAX
;
3530 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3541 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3543 int config_parse_job_mode_isolate(
3545 const char *filename
,
3547 const char *section
,
3548 unsigned section_line
,
3562 r
= parse_boolean(rvalue
);
3564 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3568 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3572 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3574 int config_parse_exec_directories(
3576 const char *filename
,
3578 const char *section
,
3579 unsigned section_line
,
3596 if (isempty(rvalue
)) {
3597 /* Empty assignment resets the list */
3598 *rt
= strv_free(*rt
);
3602 for (p
= rvalue
;;) {
3603 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3605 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3611 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3612 "Invalid syntax, ignoring: %s", rvalue
);
3616 r
= unit_full_printf(u
, word
, &k
);
3618 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3619 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3623 if (!path_is_safe(k
) || path_is_absolute(k
)) {
3624 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3625 "%s is not valid, ignoring assignment: %s", lvalue
, rvalue
);
3629 r
= strv_push(rt
, k
);
3636 int config_parse_set_status(
3638 const char *filename
,
3640 const char *section
,
3641 unsigned section_line
,
3649 const char *word
, *state
;
3651 ExitStatusSet
*status_set
= data
;
3658 /* Empty assignment resets the list */
3659 if (isempty(rvalue
)) {
3660 exit_status_set_free(status_set
);
3664 FOREACH_WORD(word
, l
, rvalue
, state
) {
3665 _cleanup_free_
char *temp
;
3669 temp
= strndup(word
, l
);
3673 r
= safe_atoi(temp
, &val
);
3675 val
= signal_from_string_try_harder(temp
);
3678 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3681 set
= &status_set
->signal
;
3683 if (val
< 0 || val
> 255) {
3684 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3687 set
= &status_set
->status
;
3690 r
= set_ensure_allocated(set
, NULL
);
3694 r
= set_put(*set
, INT_TO_PTR(val
));
3696 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3700 if (!isempty(state
))
3701 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3706 int config_parse_namespace_path_strv(
3708 const char *filename
,
3710 const char *section
,
3711 unsigned section_line
,
3728 if (isempty(rvalue
)) {
3729 /* Empty assignment resets the list */
3730 *sv
= strv_free(*sv
);
3736 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3738 bool ignore_enoent
= false, shall_prefix
= false;
3740 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3746 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3750 if (!utf8_is_valid(word
)) {
3751 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3756 if (startswith(w
, "-")) {
3757 ignore_enoent
= true;
3760 if (startswith(w
, "+")) {
3761 shall_prefix
= true;
3765 r
= unit_full_printf(u
, w
, &resolved
);
3767 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3771 if (!path_is_absolute(resolved
)) {
3772 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3776 path_kill_slashes(resolved
);
3778 joined
= strjoin(ignore_enoent
? "-" : "",
3779 shall_prefix
? "+" : "",
3782 r
= strv_push(sv
, joined
);
3792 int config_parse_bind_paths(
3794 const char *filename
,
3796 const char *section
,
3797 unsigned section_line
,
3804 ExecContext
*c
= data
;
3814 if (isempty(rvalue
)) {
3815 /* Empty assignment resets the list */
3816 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3817 c
->bind_mounts
= NULL
;
3818 c
->n_bind_mounts
= 0;
3824 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3825 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3826 char *s
= NULL
, *d
= NULL
;
3827 bool rbind
= true, ignore_enoent
= false;
3829 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3835 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3839 r
= unit_full_printf(u
, source
, &sresolved
);
3841 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3842 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3848 ignore_enoent
= true;
3852 if (!utf8_is_valid(s
)) {
3853 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3856 if (!path_is_absolute(s
)) {
3857 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3861 path_kill_slashes(s
);
3863 /* Optionally, the destination is specified. */
3864 if (p
&& p
[-1] == ':') {
3865 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3869 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3873 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3877 r
= unit_full_printf(u
, destination
, &dresolved
);
3879 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3880 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3884 if (!utf8_is_valid(dresolved
)) {
3885 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
3888 if (!path_is_absolute(dresolved
)) {
3889 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
3893 d
= path_kill_slashes(dresolved
);
3895 /* Optionally, there's also a short option string specified */
3896 if (p
&& p
[-1] == ':') {
3897 _cleanup_free_
char *options
= NULL
;
3899 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
3903 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3907 if (isempty(options
) || streq(options
, "rbind"))
3909 else if (streq(options
, "norbind"))
3912 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
3919 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
3923 .read_only
= !!strstr(lvalue
, "ReadOnly"),
3925 .ignore_enoent
= ignore_enoent
,
3934 int config_parse_no_new_privileges(
3936 const char *filename
,
3938 const char *section
,
3939 unsigned section_line
,
3946 ExecContext
*c
= data
;
3954 k
= parse_boolean(rvalue
);
3956 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3960 c
->no_new_privileges
= k
;
3965 int config_parse_protect_home(
3967 const char *filename
,
3969 const char *section
,
3970 unsigned section_line
,
3977 ExecContext
*c
= data
;
3985 /* Our enum shall be a superset of booleans, hence first try
3986 * to parse as boolean, and then as enum */
3988 k
= parse_boolean(rvalue
);
3990 c
->protect_home
= PROTECT_HOME_YES
;
3992 c
->protect_home
= PROTECT_HOME_NO
;
3996 h
= protect_home_from_string(rvalue
);
3998 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4002 c
->protect_home
= h
;
4008 int config_parse_protect_system(
4010 const char *filename
,
4012 const char *section
,
4013 unsigned section_line
,
4020 ExecContext
*c
= data
;
4028 /* Our enum shall be a superset of booleans, hence first try
4029 * to parse as boolean, and then as enum */
4031 k
= parse_boolean(rvalue
);
4033 c
->protect_system
= PROTECT_SYSTEM_YES
;
4035 c
->protect_system
= PROTECT_SYSTEM_NO
;
4039 s
= protect_system_from_string(rvalue
);
4041 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4045 c
->protect_system
= s
;
4051 #define FOLLOW_MAX 8
4053 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4064 /* This will update the filename pointer if the loaded file is
4065 * reached by a symlink. The old string will be freed. */
4068 char *target
, *name
;
4070 if (c
++ >= FOLLOW_MAX
)
4073 path_kill_slashes(*filename
);
4075 /* Add the file name we are currently looking at to
4076 * the names of this unit, but only if it is a valid
4078 name
= basename(*filename
);
4079 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4081 id
= set_get(names
, name
);
4087 r
= set_consume(names
, id
);
4093 /* Try to open the file name, but don't if its a symlink */
4094 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4101 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4102 r
= readlink_and_make_absolute(*filename
, &target
);
4110 f
= fdopen(fd
, "re");
4122 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4130 /* Let's try to add in all symlink names we found */
4131 while ((k
= set_steal_first(names
))) {
4133 /* First try to merge in the other name into our
4135 r
= unit_merge_by_name(*u
, k
);
4139 /* Hmm, we couldn't merge the other unit into
4140 * ours? Then let's try it the other way
4143 /* If the symlink name we are looking at is unit template, then
4144 we must search for instance of this template */
4145 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4146 _cleanup_free_
char *instance
= NULL
;
4148 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4152 other
= manager_get_unit((*u
)->manager
, instance
);
4154 other
= manager_get_unit((*u
)->manager
, k
);
4159 r
= unit_merge(other
, *u
);
4162 return merge_by_names(u
, names
, NULL
);
4170 unit_choose_id(*u
, id
);
4178 static int load_from_path(Unit
*u
, const char *path
) {
4179 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4180 _cleanup_fclose_
FILE *f
= NULL
;
4181 _cleanup_free_
char *filename
= NULL
;
4190 symlink_names
= set_new(&string_hash_ops
);
4194 if (path_is_absolute(path
)) {
4196 filename
= strdup(path
);
4200 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4202 filename
= mfree(filename
);
4210 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4212 /* Instead of opening the path right away, we manually
4213 * follow all symlinks and add their name to our unit
4214 * name set while doing so */
4215 filename
= path_make_absolute(path
, *p
);
4219 if (u
->manager
->unit_path_cache
&&
4220 !set_get(u
->manager
->unit_path_cache
, filename
))
4223 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4226 filename
= mfree(filename
);
4228 /* ENOENT means that the file is missing or is a dangling symlink.
4229 * ENOTDIR means that one of paths we expect to be is a directory
4230 * is not a directory, we should just ignore that.
4231 * EACCES means that the directory or file permissions are wrong.
4234 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4235 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4238 /* Empty the symlink names for the next run */
4239 set_clear_free(symlink_names
);
4244 /* Hmm, no suitable file found? */
4247 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4248 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4253 r
= merge_by_names(&merged
, symlink_names
, id
);
4258 u
->load_state
= UNIT_MERGED
;
4262 if (fstat(fileno(f
), &st
) < 0)
4265 if (null_or_empty(&st
)) {
4266 u
->load_state
= UNIT_MASKED
;
4267 u
->fragment_mtime
= 0;
4269 u
->load_state
= UNIT_LOADED
;
4270 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4272 /* Now, parse the file contents */
4273 r
= config_parse(u
->id
, filename
, f
,
4274 UNIT_VTABLE(u
)->sections
,
4275 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4276 false, true, false, u
);
4281 free(u
->fragment_path
);
4282 u
->fragment_path
= filename
;
4285 if (u
->source_path
) {
4286 if (stat(u
->source_path
, &st
) >= 0)
4287 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4289 u
->source_mtime
= 0;
4295 int unit_load_fragment(Unit
*u
) {
4301 assert(u
->load_state
== UNIT_STUB
);
4305 u
->load_state
= UNIT_LOADED
;
4309 /* First, try to find the unit under its id. We always look
4310 * for unit files in the default directories, to make it easy
4311 * to override things by placing things in /etc/systemd/system */
4312 r
= load_from_path(u
, u
->id
);
4316 /* Try to find an alias we can load this with */
4317 if (u
->load_state
== UNIT_STUB
) {
4318 SET_FOREACH(t
, u
->names
, i
) {
4323 r
= load_from_path(u
, t
);
4327 if (u
->load_state
!= UNIT_STUB
)
4332 /* And now, try looking for it under the suggested (originally linked) path */
4333 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4335 r
= load_from_path(u
, u
->fragment_path
);
4339 if (u
->load_state
== UNIT_STUB
)
4340 /* Hmm, this didn't work? Then let's get rid
4341 * of the fragment path stored for us, so that
4342 * we don't point to an invalid location. */
4343 u
->fragment_path
= mfree(u
->fragment_path
);
4346 /* Look for a template */
4347 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4348 _cleanup_free_
char *k
= NULL
;
4350 r
= unit_name_template(u
->id
, &k
);
4354 r
= load_from_path(u
, k
);
4357 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4361 if (u
->load_state
== UNIT_STUB
) {
4362 SET_FOREACH(t
, u
->names
, i
) {
4363 _cleanup_free_
char *z
= NULL
;
4368 r
= unit_name_template(t
, &z
);
4372 r
= load_from_path(u
, z
);
4376 if (u
->load_state
!= UNIT_STUB
)
4385 void unit_dump_config_items(FILE *f
) {
4386 static const struct {
4387 const ConfigParserCallback callback
;
4390 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4391 { config_parse_warn_compat
, "NOTSUPPORTED" },
4393 { config_parse_int
, "INTEGER" },
4394 { config_parse_unsigned
, "UNSIGNED" },
4395 { config_parse_iec_size
, "SIZE" },
4396 { config_parse_iec_uint64
, "SIZE" },
4397 { config_parse_si_size
, "SIZE" },
4398 { config_parse_bool
, "BOOLEAN" },
4399 { config_parse_string
, "STRING" },
4400 { config_parse_path
, "PATH" },
4401 { config_parse_unit_path_printf
, "PATH" },
4402 { config_parse_strv
, "STRING [...]" },
4403 { config_parse_exec_nice
, "NICE" },
4404 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4405 { config_parse_exec_io_class
, "IOCLASS" },
4406 { config_parse_exec_io_priority
, "IOPRIORITY" },
4407 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4408 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4409 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4410 { config_parse_mode
, "MODE" },
4411 { config_parse_unit_env_file
, "FILE" },
4412 { config_parse_exec_output
, "OUTPUT" },
4413 { config_parse_exec_input
, "INPUT" },
4414 { config_parse_log_facility
, "FACILITY" },
4415 { config_parse_log_level
, "LEVEL" },
4416 { config_parse_exec_secure_bits
, "SECUREBITS" },
4417 { config_parse_capability_set
, "BOUNDINGSET" },
4418 { config_parse_limit
, "LIMIT" },
4419 { config_parse_unit_deps
, "UNIT [...]" },
4420 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4421 { config_parse_service_type
, "SERVICETYPE" },
4422 { config_parse_service_restart
, "SERVICERESTART" },
4423 #ifdef HAVE_SYSV_COMPAT
4424 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4426 { config_parse_kill_mode
, "KILLMODE" },
4427 { config_parse_signal
, "SIGNAL" },
4428 { config_parse_socket_listen
, "SOCKET [...]" },
4429 { config_parse_socket_bind
, "SOCKETBIND" },
4430 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4431 { config_parse_sec
, "SECONDS" },
4432 { config_parse_nsec
, "NANOSECONDS" },
4433 { config_parse_namespace_path_strv
, "PATH [...]" },
4434 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4435 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4436 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4437 { config_parse_unit_string_printf
, "STRING" },
4438 { config_parse_trigger_unit
, "UNIT" },
4439 { config_parse_timer
, "TIMER" },
4440 { config_parse_path_spec
, "PATH" },
4441 { config_parse_notify_access
, "ACCESS" },
4442 { config_parse_ip_tos
, "TOS" },
4443 { config_parse_unit_condition_path
, "CONDITION" },
4444 { config_parse_unit_condition_string
, "CONDITION" },
4445 { config_parse_unit_condition_null
, "CONDITION" },
4446 { config_parse_unit_slice
, "SLICE" },
4447 { config_parse_documentation
, "URL" },
4448 { config_parse_service_timeout
, "SECONDS" },
4449 { config_parse_emergency_action
, "ACTION" },
4450 { config_parse_set_status
, "STATUS" },
4451 { config_parse_service_sockets
, "SOCKETS" },
4452 { config_parse_environ
, "ENVIRON" },
4454 { config_parse_syscall_filter
, "SYSCALLS" },
4455 { config_parse_syscall_archs
, "ARCHS" },
4456 { config_parse_syscall_errno
, "ERRNO" },
4457 { config_parse_address_families
, "FAMILIES" },
4458 { config_parse_restrict_namespaces
, "NAMESPACES" },
4460 { config_parse_cpu_shares
, "SHARES" },
4461 { config_parse_cpu_weight
, "WEIGHT" },
4462 { config_parse_memory_limit
, "LIMIT" },
4463 { config_parse_device_allow
, "DEVICE" },
4464 { config_parse_device_policy
, "POLICY" },
4465 { config_parse_io_limit
, "LIMIT" },
4466 { config_parse_io_weight
, "WEIGHT" },
4467 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4468 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4469 { config_parse_blockio_weight
, "WEIGHT" },
4470 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4471 { config_parse_long
, "LONG" },
4472 { config_parse_socket_service
, "SERVICE" },
4474 { config_parse_exec_selinux_context
, "LABEL" },
4476 { config_parse_job_mode
, "MODE" },
4477 { config_parse_job_mode_isolate
, "BOOLEAN" },
4478 { config_parse_personality
, "PERSONALITY" },
4481 const char *prev
= NULL
;
4486 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4487 const char *rvalue
= "OTHER", *lvalue
;
4491 const ConfigPerfItem
*p
;
4493 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4495 dot
= strchr(i
, '.');
4496 lvalue
= dot
? dot
+ 1 : i
;
4500 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4504 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4507 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4508 if (p
->parse
== table
[j
].callback
) {
4509 rvalue
= table
[j
].rvalue
;
4513 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);