2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
5 Copyright 2012 Holger Hans Peter Freyther
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/oom.h>
30 #include <sys/resource.h>
34 #include "alloc-util.h"
35 #include "bus-error.h"
36 #include "bus-internal.h"
39 #include "capability-util.h"
41 #include "conf-parser.h"
42 #include "cpu-set-util.h"
44 #include "errno-list.h"
49 #include "load-fragment.h"
52 #include "mount-util.h"
53 #include "parse-util.h"
54 #include "path-util.h"
55 #include "process-util.h"
56 #include "rlimit-util.h"
58 #include "seccomp-util.h"
60 #include "securebits.h"
61 #include "signal-util.h"
62 #include "stat-util.h"
63 #include "string-util.h"
65 #include "unit-name.h"
66 #include "unit-printf.h"
68 #include "user-util.h"
72 int config_parse_warn_compat(
77 unsigned section_line
,
83 Disabled reason
= ltype
;
86 case DISABLED_CONFIGURATION
:
87 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
88 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
91 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
92 "Support for option %s= has been removed and it is ignored", lvalue
);
94 case DISABLED_EXPERIMENTAL
:
95 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
96 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
103 int config_parse_unit_deps(
105 const char *filename
,
108 unsigned section_line
,
115 UnitDependency d
= ltype
;
125 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
128 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
134 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
138 r
= unit_name_printf(u
, word
, &k
);
140 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
144 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
146 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
152 int config_parse_obsolete_unit_deps(
154 const char *filename
,
157 unsigned section_line
,
164 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
165 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
167 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
170 int config_parse_unit_string_printf(
172 const char *filename
,
175 unsigned section_line
,
182 _cleanup_free_
char *k
= NULL
;
191 r
= unit_full_printf(u
, rvalue
, &k
);
193 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
197 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
200 int config_parse_unit_strv_printf(
202 const char *filename
,
205 unsigned section_line
,
213 _cleanup_free_
char *k
= NULL
;
221 r
= unit_full_printf(u
, rvalue
, &k
);
223 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
227 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
230 int config_parse_unit_path_printf(
232 const char *filename
,
235 unsigned section_line
,
242 _cleanup_free_
char *k
= NULL
;
252 r
= unit_full_printf(u
, rvalue
, &k
);
254 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
255 "Failed to resolve unit specifiers on %s%s: %m",
256 fatal
? "" : ", ignoring", rvalue
);
257 return fatal
? -ENOEXEC
: 0;
260 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
263 int config_parse_unit_path_strv_printf(
265 const char *filename
,
268 unsigned section_line
,
286 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
288 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
294 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
295 "Invalid syntax, ignoring: %s", rvalue
);
299 r
= unit_full_printf(u
, word
, &k
);
301 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
302 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
306 if (!utf8_is_valid(k
)) {
307 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
311 if (!path_is_absolute(k
)) {
312 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
313 "Symlink path is not absolute: %s", k
);
317 path_kill_slashes(k
);
326 int config_parse_socket_listen(const char *unit
,
327 const char *filename
,
330 unsigned section_line
,
337 _cleanup_free_ SocketPort
*p
= NULL
;
349 if (isempty(rvalue
)) {
350 /* An empty assignment removes all ports */
351 socket_free_ports(s
);
355 p
= new0(SocketPort
, 1);
359 if (ltype
!= SOCKET_SOCKET
) {
362 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
364 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
368 path_kill_slashes(p
->path
);
370 } else if (streq(lvalue
, "ListenNetlink")) {
371 _cleanup_free_
char *k
= NULL
;
373 p
->type
= SOCKET_SOCKET
;
374 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
376 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
380 r
= socket_address_parse_netlink(&p
->address
, k
);
382 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
387 _cleanup_free_
char *k
= NULL
;
389 p
->type
= SOCKET_SOCKET
;
390 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
392 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
396 r
= socket_address_parse_and_warn(&p
->address
, k
);
398 if (r
!= -EAFNOSUPPORT
)
399 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
404 if (streq(lvalue
, "ListenStream"))
405 p
->address
.type
= SOCK_STREAM
;
406 else if (streq(lvalue
, "ListenDatagram"))
407 p
->address
.type
= SOCK_DGRAM
;
409 assert(streq(lvalue
, "ListenSequentialPacket"));
410 p
->address
.type
= SOCK_SEQPACKET
;
413 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
414 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
420 p
->auxiliary_fds
= NULL
;
421 p
->n_auxiliary_fds
= 0;
425 LIST_FIND_TAIL(port
, s
->ports
, tail
);
426 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
428 LIST_PREPEND(port
, s
->ports
, p
);
434 int config_parse_socket_protocol(const char *unit
,
435 const char *filename
,
438 unsigned section_line
,
453 if (streq(rvalue
, "udplite"))
454 s
->socket_protocol
= IPPROTO_UDPLITE
;
455 else if (streq(rvalue
, "sctp"))
456 s
->socket_protocol
= IPPROTO_SCTP
;
458 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
465 int config_parse_socket_bind(const char *unit
,
466 const char *filename
,
469 unsigned section_line
,
477 SocketAddressBindIPv6Only b
;
486 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
490 r
= parse_boolean(rvalue
);
492 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
496 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
498 s
->bind_ipv6_only
= b
;
503 int config_parse_exec_nice(
505 const char *filename
,
508 unsigned section_line
,
515 ExecContext
*c
= data
;
523 r
= parse_nice(rvalue
, &priority
);
526 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
528 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
539 int config_parse_exec_oom_score_adjust(const char* unit
,
540 const char *filename
,
543 unsigned section_line
,
550 ExecContext
*c
= data
;
558 r
= safe_atoi(rvalue
, &oa
);
560 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
564 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
565 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
569 c
->oom_score_adjust
= oa
;
570 c
->oom_score_adjust_set
= true;
575 int config_parse_exec(
577 const char *filename
,
580 unsigned section_line
,
587 ExecCommand
**e
= data
;
599 rvalue
+= strspn(rvalue
, WHITESPACE
);
601 if (isempty(rvalue
)) {
602 /* An empty assignment resets the list */
603 *e
= exec_command_free_list(*e
);
609 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
610 bool separate_argv0
= false, ignore
= false, privileged
= false;
611 _cleanup_free_ ExecCommand
*nce
= NULL
;
612 _cleanup_strv_free_
char **n
= NULL
;
613 size_t nlen
= 0, nbufsize
= 0;
618 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
624 /* We accept an absolute path as first argument.
625 * If it's prefixed with - and the path doesn't exist,
626 * we ignore it instead of erroring out;
627 * if it's prefixed with @, we allow overriding of argv[0];
628 * and if it's prefixed with +, it will be run with full privileges */
629 if (*f
== '-' && !ignore
)
631 else if (*f
== '@' && !separate_argv0
)
632 separate_argv0
= true;
633 else if (*f
== '+' && !privileged
)
640 r
= unit_full_printf(u
, f
, &path
);
642 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
643 "Failed to resolve unit specifiers on %s%s: %m",
644 f
, ignore
? ", ignoring" : "");
645 return ignore
? 0 : -ENOEXEC
;
649 /* First word is either "-" or "@" with no command. */
650 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
651 "Empty path in command line%s: \"%s\"",
652 ignore
? ", ignoring" : "", rvalue
);
653 return ignore
? 0 : -ENOEXEC
;
655 if (!string_is_safe(path
)) {
656 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
657 "Executable path contains special characters%s: %s",
658 ignore
? ", ignoring" : "", rvalue
);
659 return ignore
? 0 : -ENOEXEC
;
661 if (!path_is_absolute(path
)) {
662 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
663 "Executable path is not absolute%s: %s",
664 ignore
? ", ignoring" : "", rvalue
);
665 return ignore
? 0 : -ENOEXEC
;
667 if (endswith(path
, "/")) {
668 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
669 "Executable path specifies a directory%s: %s",
670 ignore
? ", ignoring" : "", rvalue
);
671 return ignore
? 0 : -ENOEXEC
;
674 if (!separate_argv0
) {
677 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
687 path_kill_slashes(path
);
689 while (!isempty(p
)) {
690 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
692 /* Check explicitly for an unquoted semicolon as
693 * command separator token. */
694 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
696 p
+= strspn(p
, WHITESPACE
);
701 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
702 * extract_first_word() would return the same for all of those. */
703 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
707 p
+= strspn(p
, WHITESPACE
);
709 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
720 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
724 return ignore
? 0 : -ENOEXEC
;
726 r
= unit_full_printf(u
, word
, &resolved
);
728 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
729 "Failed to resolve unit specifiers on %s%s: %m",
730 word
, ignore
? ", ignoring" : "");
731 return ignore
? 0 : -ENOEXEC
;
734 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
736 n
[nlen
++] = resolved
;
742 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
743 "Empty executable name or zeroeth argument%s: %s",
744 ignore
? ", ignoring" : "", rvalue
);
745 return ignore
? 0 : -ENOEXEC
;
748 nce
= new0(ExecCommand
, 1);
754 nce
->ignore
= ignore
;
755 nce
->privileged
= privileged
;
757 exec_command_append_list(e
, nce
);
759 /* Do not _cleanup_free_ these. */
770 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
771 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
773 int config_parse_socket_bindtodevice(
775 const char *filename
,
778 unsigned section_line
,
793 if (rvalue
[0] && !streq(rvalue
, "*")) {
794 if (!ifname_valid(rvalue
)) {
795 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
805 free(s
->bind_to_device
);
806 s
->bind_to_device
= n
;
811 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
812 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
814 int config_parse_exec_input(const char *unit
,
815 const char *filename
,
818 unsigned section_line
,
824 ExecContext
*c
= data
;
833 name
= startswith(rvalue
, "fd:");
835 /* Strip prefix and validate fd name */
836 if (!fdname_is_valid(name
)) {
837 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
840 c
->std_input
= EXEC_INPUT_NAMED_FD
;
841 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
846 ExecInput ei
= exec_input_from_string(rvalue
);
847 if (ei
== _EXEC_INPUT_INVALID
)
848 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
855 int config_parse_exec_output(const char *unit
,
856 const char *filename
,
859 unsigned section_line
,
865 ExecContext
*c
= data
;
876 name
= startswith(rvalue
, "fd:");
878 /* Strip prefix and validate fd name */
879 if (!fdname_is_valid(name
)) {
880 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
883 eo
= EXEC_OUTPUT_NAMED_FD
;
885 eo
= exec_output_from_string(rvalue
);
886 if (eo
== _EXEC_OUTPUT_INVALID
) {
887 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
892 if (streq(lvalue
, "StandardOutput")) {
894 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
898 } else if (streq(lvalue
, "StandardError")) {
900 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
905 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
910 int config_parse_exec_io_class(const char *unit
,
911 const char *filename
,
914 unsigned section_line
,
921 ExecContext
*c
= data
;
929 x
= ioprio_class_from_string(rvalue
);
931 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
935 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
936 c
->ioprio_set
= true;
941 int config_parse_exec_io_priority(const char *unit
,
942 const char *filename
,
945 unsigned section_line
,
952 ExecContext
*c
= data
;
960 r
= ioprio_parse_priority(rvalue
, &i
);
962 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
966 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
967 c
->ioprio_set
= true;
972 int config_parse_exec_cpu_sched_policy(const char *unit
,
973 const char *filename
,
976 unsigned section_line
,
984 ExecContext
*c
= data
;
992 x
= sched_policy_from_string(rvalue
);
994 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
998 c
->cpu_sched_policy
= x
;
999 /* Moving to or from real-time policy? We need to adjust the priority */
1000 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1001 c
->cpu_sched_set
= true;
1006 int config_parse_exec_cpu_sched_prio(const char *unit
,
1007 const char *filename
,
1009 const char *section
,
1010 unsigned section_line
,
1017 ExecContext
*c
= data
;
1025 r
= safe_atoi(rvalue
, &i
);
1027 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1031 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1032 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1033 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1035 if (i
< min
|| i
> max
) {
1036 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1040 c
->cpu_sched_priority
= i
;
1041 c
->cpu_sched_set
= true;
1046 int config_parse_exec_cpu_affinity(const char *unit
,
1047 const char *filename
,
1049 const char *section
,
1050 unsigned section_line
,
1057 ExecContext
*c
= data
;
1058 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1066 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1071 CPU_FREE(c
->cpuset
);
1074 /* An empty assignment resets the CPU list */
1080 c
->cpuset_ncpus
= ncpus
;
1085 int config_parse_exec_secure_bits(const char *unit
,
1086 const char *filename
,
1088 const char *section
,
1089 unsigned section_line
,
1096 ExecContext
*c
= data
;
1105 if (isempty(rvalue
)) {
1106 /* An empty assignment resets the field */
1111 for (p
= rvalue
;;) {
1112 _cleanup_free_
char *word
= NULL
;
1114 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1120 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1121 "Invalid syntax, ignoring: %s", rvalue
);
1125 if (streq(word
, "keep-caps"))
1126 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
1127 else if (streq(word
, "keep-caps-locked"))
1128 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
1129 else if (streq(word
, "no-setuid-fixup"))
1130 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
1131 else if (streq(word
, "no-setuid-fixup-locked"))
1132 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
1133 else if (streq(word
, "noroot"))
1134 c
->secure_bits
|= 1<<SECURE_NOROOT
;
1135 else if (streq(word
, "noroot-locked"))
1136 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
1138 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
1139 "Failed to parse secure bit \"%s\", ignoring.", word
);
1145 int config_parse_capability_set(
1147 const char *filename
,
1149 const char *section
,
1150 unsigned section_line
,
1157 uint64_t *capability_set
= data
;
1158 uint64_t sum
= 0, initial
= 0;
1159 bool invert
= false;
1167 if (rvalue
[0] == '~') {
1172 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1173 initial
= CAP_ALL
; /* initialized to all bits on */
1174 /* else "AmbientCapabilities" initialized to all bits off */
1178 _cleanup_free_
char *word
= NULL
;
1181 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1187 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1191 cap
= capability_from_name(word
);
1193 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1197 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1200 sum
= invert
? ~sum
: sum
;
1202 if (sum
== 0 || *capability_set
== initial
)
1203 /* "" or uninitialized data -> replace */
1204 *capability_set
= sum
;
1206 /* previous data -> merge */
1207 *capability_set
|= sum
;
1212 int config_parse_limit(
1214 const char *filename
,
1216 const char *section
,
1217 unsigned section_line
,
1224 struct rlimit
**rl
= data
, d
= {};
1232 r
= rlimit_parse(ltype
, rvalue
, &d
);
1234 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1238 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1245 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1253 #ifdef HAVE_SYSV_COMPAT
1254 int config_parse_sysv_priority(const char *unit
,
1255 const char *filename
,
1257 const char *section
,
1258 unsigned section_line
,
1265 int *priority
= data
;
1273 r
= safe_atoi(rvalue
, &i
);
1274 if (r
< 0 || i
< 0) {
1275 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1279 *priority
= (int) i
;
1284 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1285 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1287 int config_parse_exec_mount_flags(
1289 const char *filename
,
1291 const char *section
,
1292 unsigned section_line
,
1300 ExecContext
*c
= data
;
1308 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1310 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1315 int config_parse_exec_selinux_context(
1317 const char *filename
,
1319 const char *section
,
1320 unsigned section_line
,
1327 ExecContext
*c
= data
;
1338 if (isempty(rvalue
)) {
1339 c
->selinux_context
= mfree(c
->selinux_context
);
1340 c
->selinux_context_ignore
= false;
1344 if (rvalue
[0] == '-') {
1350 r
= unit_full_printf(u
, rvalue
, &k
);
1352 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1353 "Failed to resolve specifiers%s: %m",
1354 ignore
? ", ignoring" : "");
1355 return ignore
? 0 : -ENOEXEC
;
1358 free(c
->selinux_context
);
1359 c
->selinux_context
= k
;
1360 c
->selinux_context_ignore
= ignore
;
1365 int config_parse_exec_apparmor_profile(
1367 const char *filename
,
1369 const char *section
,
1370 unsigned section_line
,
1377 ExecContext
*c
= data
;
1388 if (isempty(rvalue
)) {
1389 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1390 c
->apparmor_profile_ignore
= false;
1394 if (rvalue
[0] == '-') {
1400 r
= unit_full_printf(u
, rvalue
, &k
);
1402 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1403 "Failed to resolve specifiers%s: %m",
1404 ignore
? ", ignoring" : "");
1405 return ignore
? 0 : -ENOEXEC
;
1408 free(c
->apparmor_profile
);
1409 c
->apparmor_profile
= k
;
1410 c
->apparmor_profile_ignore
= ignore
;
1415 int config_parse_exec_smack_process_label(
1417 const char *filename
,
1419 const char *section
,
1420 unsigned section_line
,
1427 ExecContext
*c
= data
;
1438 if (isempty(rvalue
)) {
1439 c
->smack_process_label
= mfree(c
->smack_process_label
);
1440 c
->smack_process_label_ignore
= false;
1444 if (rvalue
[0] == '-') {
1450 r
= unit_full_printf(u
, rvalue
, &k
);
1452 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1453 "Failed to resolve specifiers%s: %m",
1454 ignore
? ", ignoring" : "");
1455 return ignore
? 0 : -ENOEXEC
;
1458 free(c
->smack_process_label
);
1459 c
->smack_process_label
= k
;
1460 c
->smack_process_label_ignore
= ignore
;
1465 int config_parse_timer(const char *unit
,
1466 const char *filename
,
1468 const char *section
,
1469 unsigned section_line
,
1480 CalendarSpec
*c
= NULL
;
1482 _cleanup_free_
char *k
= NULL
;
1490 if (isempty(rvalue
)) {
1491 /* Empty assignment resets list */
1492 timer_free_values(t
);
1496 b
= timer_base_from_string(lvalue
);
1498 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1502 r
= unit_full_printf(u
, rvalue
, &k
);
1504 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1508 if (b
== TIMER_CALENDAR
) {
1509 if (calendar_spec_from_string(k
, &c
) < 0) {
1510 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1514 if (parse_sec(k
, &usec
) < 0) {
1515 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1520 v
= new0(TimerValue
, 1);
1522 calendar_spec_free(c
);
1528 v
->calendar_spec
= c
;
1530 LIST_PREPEND(value
, t
->values
, v
);
1535 int config_parse_trigger_unit(
1537 const char *filename
,
1539 const char *section
,
1540 unsigned section_line
,
1547 _cleanup_free_
char *p
= NULL
;
1557 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1558 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1562 r
= unit_name_printf(u
, rvalue
, &p
);
1564 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1568 type
= unit_name_to_type(p
);
1570 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1574 if (type
== u
->type
) {
1575 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1579 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1581 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1588 int config_parse_path_spec(const char *unit
,
1589 const char *filename
,
1591 const char *section
,
1592 unsigned section_line
,
1602 _cleanup_free_
char *k
= NULL
;
1610 if (isempty(rvalue
)) {
1611 /* Empty assignment clears list */
1616 b
= path_type_from_string(lvalue
);
1618 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1622 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1624 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1628 if (!path_is_absolute(k
)) {
1629 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1633 s
= new0(PathSpec
, 1);
1638 s
->path
= path_kill_slashes(k
);
1643 LIST_PREPEND(spec
, p
->specs
, s
);
1648 int config_parse_socket_service(
1650 const char *filename
,
1652 const char *section
,
1653 unsigned section_line
,
1660 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1661 _cleanup_free_
char *p
= NULL
;
1671 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1673 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1677 if (!endswith(p
, ".service")) {
1678 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1682 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1684 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1688 unit_ref_set(&s
->service
, x
);
1693 int config_parse_fdname(
1695 const char *filename
,
1697 const char *section
,
1698 unsigned section_line
,
1705 _cleanup_free_
char *p
= NULL
;
1714 if (isempty(rvalue
)) {
1715 s
->fdname
= mfree(s
->fdname
);
1719 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1721 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1725 if (!fdname_is_valid(p
)) {
1726 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1730 return free_and_replace(s
->fdname
, p
);
1733 int config_parse_service_sockets(
1735 const char *filename
,
1737 const char *section
,
1738 unsigned section_line
,
1756 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1758 r
= extract_first_word(&p
, &word
, NULL
, 0);
1764 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1768 r
= unit_name_printf(UNIT(s
), word
, &k
);
1770 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1774 if (!endswith(k
, ".socket")) {
1775 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1779 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1781 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1783 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1785 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1791 int config_parse_bus_name(
1793 const char *filename
,
1795 const char *section
,
1796 unsigned section_line
,
1803 _cleanup_free_
char *k
= NULL
;
1812 r
= unit_full_printf(u
, rvalue
, &k
);
1814 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1818 if (!service_name_is_valid(k
)) {
1819 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1823 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1826 int config_parse_service_timeout(
1828 const char *filename
,
1830 const char *section
,
1831 unsigned section_line
,
1838 Service
*s
= userdata
;
1847 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1849 r
= parse_sec(rvalue
, &usec
);
1851 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1855 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1856 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1857 * all other timeouts. */
1859 usec
= USEC_INFINITY
;
1861 if (!streq(lvalue
, "TimeoutStopSec")) {
1862 s
->start_timeout_defined
= true;
1863 s
->timeout_start_usec
= usec
;
1866 if (!streq(lvalue
, "TimeoutStartSec"))
1867 s
->timeout_stop_usec
= usec
;
1872 int config_parse_sec_fix_0(
1874 const char *filename
,
1876 const char *section
,
1877 unsigned section_line
,
1884 usec_t
*usec
= data
;
1892 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1893 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1896 r
= parse_sec_fix_0(rvalue
, usec
);
1898 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1905 int config_parse_user_group(
1907 const char *filename
,
1909 const char *section
,
1910 unsigned section_line
,
1917 char **user
= data
, *n
;
1926 if (isempty(rvalue
))
1929 _cleanup_free_
char *k
= NULL
;
1931 r
= unit_full_printf(u
, rvalue
, &k
);
1933 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
1937 if (!valid_user_group_name_or_id(k
)) {
1938 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1952 int config_parse_user_group_strv(
1954 const char *filename
,
1956 const char *section
,
1957 unsigned section_line
,
1964 char ***users
= data
;
1974 if (isempty(rvalue
)) {
1977 empty
= new0(char*, 1);
1989 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1991 r
= extract_first_word(&p
, &word
, NULL
, 0);
1997 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
2001 r
= unit_full_printf(u
, word
, &k
);
2003 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
2007 if (!valid_user_group_name_or_id(k
)) {
2008 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2012 r
= strv_push(users
, k
);
2022 int config_parse_working_directory(
2024 const char *filename
,
2026 const char *section
,
2027 unsigned section_line
,
2034 ExecContext
*c
= data
;
2045 if (rvalue
[0] == '-') {
2051 if (streq(rvalue
, "~")) {
2052 c
->working_directory_home
= true;
2053 c
->working_directory
= mfree(c
->working_directory
);
2055 _cleanup_free_
char *k
= NULL
;
2057 r
= unit_full_printf(u
, rvalue
, &k
);
2059 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2060 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2061 rvalue
, missing_ok
? ", ignoring" : "");
2062 return missing_ok
? 0 : -ENOEXEC
;
2065 path_kill_slashes(k
);
2067 if (!utf8_is_valid(k
)) {
2068 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2069 return missing_ok
? 0 : -ENOEXEC
;
2072 if (!path_is_absolute(k
)) {
2073 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2074 "Working directory path '%s' is not absolute%s.",
2075 rvalue
, missing_ok
? ", ignoring" : "");
2076 return missing_ok
? 0 : -ENOEXEC
;
2079 c
->working_directory_home
= false;
2080 free_and_replace(c
->working_directory
, k
);
2083 c
->working_directory_missing_ok
= missing_ok
;
2087 int config_parse_unit_env_file(const char *unit
,
2088 const char *filename
,
2090 const char *section
,
2091 unsigned section_line
,
2100 _cleanup_free_
char *n
= NULL
;
2108 if (isempty(rvalue
)) {
2109 /* Empty assignment frees the list */
2110 *env
= strv_free(*env
);
2114 r
= unit_full_printf(u
, rvalue
, &n
);
2116 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2120 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2121 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2125 r
= strv_extend(env
, n
);
2132 int config_parse_environ(const char *unit
,
2133 const char *filename
,
2135 const char *section
,
2136 unsigned section_line
,
2153 if (isempty(rvalue
)) {
2154 /* Empty assignment resets the list */
2155 *env
= strv_free(*env
);
2159 for (p
= rvalue
;; ) {
2160 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2162 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2168 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2169 "Invalid syntax, ignoring: %s", rvalue
);
2174 r
= unit_full_printf(u
, word
, &k
);
2176 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2177 "Failed to resolve specifiers, ignoring: %s", k
);
2185 if (!env_assignment_is_valid(k
)) {
2186 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2187 "Invalid environment assignment, ignoring: %s", k
);
2191 r
= strv_env_replace(env
, k
);
2198 int config_parse_pass_environ(const char *unit
,
2199 const char *filename
,
2201 const char *section
,
2202 unsigned section_line
,
2209 const char *whole_rvalue
= rvalue
;
2210 char*** passenv
= data
;
2211 _cleanup_strv_free_
char **n
= NULL
;
2212 size_t nlen
= 0, nbufsize
= 0;
2220 if (isempty(rvalue
)) {
2221 /* Empty assignment resets the list */
2222 *passenv
= strv_free(*passenv
);
2227 _cleanup_free_
char *word
= NULL
;
2229 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2235 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2236 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2240 if (!env_name_is_valid(word
)) {
2241 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2242 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2246 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2254 r
= strv_extend_strv(passenv
, n
, true);
2262 int config_parse_ip_tos(const char *unit
,
2263 const char *filename
,
2265 const char *section
,
2266 unsigned section_line
,
2273 int *ip_tos
= data
, x
;
2280 x
= ip_tos_from_string(rvalue
);
2282 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2290 int config_parse_unit_condition_path(
2292 const char *filename
,
2294 const char *section
,
2295 unsigned section_line
,
2302 _cleanup_free_
char *p
= NULL
;
2303 Condition
**list
= data
, *c
;
2304 ConditionType t
= ltype
;
2305 bool trigger
, negate
;
2314 if (isempty(rvalue
)) {
2315 /* Empty assignment resets the list */
2316 *list
= condition_free_list(*list
);
2320 trigger
= rvalue
[0] == '|';
2324 negate
= rvalue
[0] == '!';
2328 r
= unit_full_printf(u
, rvalue
, &p
);
2330 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2334 if (!path_is_absolute(p
)) {
2335 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2339 c
= condition_new(t
, p
, trigger
, negate
);
2343 LIST_PREPEND(conditions
, *list
, c
);
2347 int config_parse_unit_condition_string(
2349 const char *filename
,
2351 const char *section
,
2352 unsigned section_line
,
2359 _cleanup_free_
char *s
= NULL
;
2360 Condition
**list
= data
, *c
;
2361 ConditionType t
= ltype
;
2362 bool trigger
, negate
;
2371 if (isempty(rvalue
)) {
2372 /* Empty assignment resets the list */
2373 *list
= condition_free_list(*list
);
2377 trigger
= rvalue
[0] == '|';
2381 negate
= rvalue
[0] == '!';
2385 r
= unit_full_printf(u
, rvalue
, &s
);
2387 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2391 c
= condition_new(t
, s
, trigger
, negate
);
2395 LIST_PREPEND(conditions
, *list
, c
);
2399 int config_parse_unit_condition_null(
2401 const char *filename
,
2403 const char *section
,
2404 unsigned section_line
,
2411 Condition
**list
= data
, *c
;
2412 bool trigger
, negate
;
2420 if (isempty(rvalue
)) {
2421 /* Empty assignment resets the list */
2422 *list
= condition_free_list(*list
);
2426 trigger
= rvalue
[0] == '|';
2430 negate
= rvalue
[0] == '!';
2434 b
= parse_boolean(rvalue
);
2436 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2443 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2447 LIST_PREPEND(conditions
, *list
, c
);
2451 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2452 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2454 int config_parse_unit_requires_mounts_for(
2456 const char *filename
,
2458 const char *section
,
2459 unsigned section_line
,
2475 for (p
= rvalue
;; ) {
2476 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2478 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2484 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2485 "Invalid syntax, ignoring: %s", rvalue
);
2489 if (!utf8_is_valid(word
)) {
2490 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2494 r
= unit_full_printf(u
, word
, &resolved
);
2496 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2500 r
= unit_require_mounts_for(u
, resolved
);
2502 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2508 int config_parse_documentation(const char *unit
,
2509 const char *filename
,
2511 const char *section
,
2512 unsigned section_line
,
2528 if (isempty(rvalue
)) {
2529 /* Empty assignment resets the list */
2530 u
->documentation
= strv_free(u
->documentation
);
2534 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2535 rvalue
, data
, userdata
);
2539 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2541 if (documentation_url_is_valid(*a
))
2544 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2556 static int syscall_filter_parse_one(
2558 const char *filename
,
2567 const SyscallFilterSet
*set
;
2570 set
= syscall_filter_set_find(t
);
2573 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2577 NULSTR_FOREACH(i
, set
->value
) {
2578 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2585 id
= seccomp_syscall_resolve_name(t
);
2586 if (id
== __NR_SCMP_ERROR
) {
2588 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2592 /* If we previously wanted to forbid a syscall and now
2593 * we want to allow it, then remove it from the list
2595 if (!invert
== c
->syscall_whitelist
) {
2596 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2602 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2608 int config_parse_syscall_filter(
2610 const char *filename
,
2612 const char *section
,
2613 unsigned section_line
,
2620 ExecContext
*c
= data
;
2622 bool invert
= false;
2631 if (isempty(rvalue
)) {
2632 /* Empty assignment resets the list */
2633 c
->syscall_filter
= set_free(c
->syscall_filter
);
2634 c
->syscall_whitelist
= false;
2638 if (rvalue
[0] == '~') {
2643 if (!c
->syscall_filter
) {
2644 c
->syscall_filter
= set_new(NULL
);
2645 if (!c
->syscall_filter
)
2649 /* Allow everything but the ones listed */
2650 c
->syscall_whitelist
= false;
2652 /* Allow nothing but the ones listed */
2653 c
->syscall_whitelist
= true;
2655 /* Accept default syscalls if we are on a whitelist */
2656 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2664 _cleanup_free_
char *word
= NULL
;
2666 r
= extract_first_word(&p
, &word
, NULL
, 0);
2672 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2676 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2684 int config_parse_syscall_archs(
2686 const char *filename
,
2688 const char *section
,
2689 unsigned section_line
,
2700 if (isempty(rvalue
)) {
2701 *archs
= set_free(*archs
);
2705 r
= set_ensure_allocated(archs
, NULL
);
2709 for (p
= rvalue
;;) {
2710 _cleanup_free_
char *word
= NULL
;
2713 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2719 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2720 "Invalid syntax, ignoring: %s", rvalue
);
2724 r
= seccomp_arch_from_string(word
, &a
);
2726 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2727 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2731 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2737 int config_parse_syscall_errno(
2739 const char *filename
,
2741 const char *section
,
2742 unsigned section_line
,
2749 ExecContext
*c
= data
;
2756 if (isempty(rvalue
)) {
2757 /* Empty assignment resets to KILL */
2758 c
->syscall_errno
= 0;
2762 e
= errno_from_name(rvalue
);
2764 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2768 c
->syscall_errno
= e
;
2772 int config_parse_address_families(
2774 const char *filename
,
2776 const char *section
,
2777 unsigned section_line
,
2784 ExecContext
*c
= data
;
2785 bool invert
= false;
2793 if (isempty(rvalue
)) {
2794 /* Empty assignment resets the list */
2795 c
->address_families
= set_free(c
->address_families
);
2796 c
->address_families_whitelist
= false;
2800 if (rvalue
[0] == '~') {
2805 if (!c
->address_families
) {
2806 c
->address_families
= set_new(NULL
);
2807 if (!c
->address_families
)
2810 c
->address_families_whitelist
= !invert
;
2813 for (p
= rvalue
;;) {
2814 _cleanup_free_
char *word
= NULL
;
2817 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2823 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2824 "Invalid syntax, ignoring: %s", rvalue
);
2828 af
= af_from_name(word
);
2830 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2831 "Failed to parse address family \"%s\", ignoring: %m", word
);
2835 /* If we previously wanted to forbid an address family and now
2836 * we want to allow it, then just remove it from the list.
2838 if (!invert
== c
->address_families_whitelist
) {
2839 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2843 set_remove(c
->address_families
, INT_TO_PTR(af
));
2847 int config_parse_restrict_namespaces(
2849 const char *filename
,
2851 const char *section
,
2852 unsigned section_line
,
2859 ExecContext
*c
= data
;
2860 bool invert
= false;
2863 if (isempty(rvalue
)) {
2864 /* Reset to the default. */
2865 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2869 if (rvalue
[0] == '~') {
2874 r
= parse_boolean(rvalue
);
2876 c
->restrict_namespaces
= 0;
2878 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2880 /* Not a boolean argument, in this case it's a list of namespace types. */
2882 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2884 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2890 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2896 int config_parse_unit_slice(
2898 const char *filename
,
2900 const char *section
,
2901 unsigned section_line
,
2908 _cleanup_free_
char *k
= NULL
;
2909 Unit
*u
= userdata
, *slice
= NULL
;
2917 r
= unit_name_printf(u
, rvalue
, &k
);
2919 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2923 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2925 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2929 r
= unit_set_slice(u
, slice
);
2931 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2938 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2940 int config_parse_cpu_weight(
2942 const char *filename
,
2944 const char *section
,
2945 unsigned section_line
,
2952 uint64_t *weight
= data
;
2959 r
= cg_weight_parse(rvalue
, weight
);
2961 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
2968 int config_parse_cpu_shares(
2970 const char *filename
,
2972 const char *section
,
2973 unsigned section_line
,
2980 uint64_t *shares
= data
;
2987 r
= cg_cpu_shares_parse(rvalue
, shares
);
2989 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2996 int config_parse_cpu_quota(
2998 const char *filename
,
3000 const char *section
,
3001 unsigned section_line
,
3008 CGroupContext
*c
= data
;
3015 if (isempty(rvalue
)) {
3016 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3020 r
= parse_percent_unbounded(rvalue
);
3022 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3026 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3030 int config_parse_memory_limit(
3032 const char *filename
,
3034 const char *section
,
3035 unsigned section_line
,
3042 CGroupContext
*c
= data
;
3043 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3046 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3048 r
= parse_percent(rvalue
);
3050 r
= parse_size(rvalue
, 1024, &bytes
);
3052 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3056 bytes
= physical_memory_scale(r
, 100U);
3058 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3059 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3064 if (streq(lvalue
, "MemoryLow"))
3065 c
->memory_low
= bytes
;
3066 else if (streq(lvalue
, "MemoryHigh"))
3067 c
->memory_high
= bytes
;
3068 else if (streq(lvalue
, "MemoryMax"))
3069 c
->memory_max
= bytes
;
3070 else if (streq(lvalue
, "MemorySwapMax"))
3071 c
->memory_swap_max
= bytes
;
3072 else if (streq(lvalue
, "MemoryLimit"))
3073 c
->memory_limit
= bytes
;
3080 int config_parse_tasks_max(
3082 const char *filename
,
3084 const char *section
,
3085 unsigned section_line
,
3092 uint64_t *tasks_max
= data
, v
;
3096 if (isempty(rvalue
)) {
3097 *tasks_max
= u
->manager
->default_tasks_max
;
3101 if (streq(rvalue
, "infinity")) {
3102 *tasks_max
= CGROUP_LIMIT_MAX
;
3106 r
= parse_percent(rvalue
);
3108 r
= safe_atou64(rvalue
, &v
);
3110 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3114 v
= system_tasks_max_scale(r
, 100U);
3116 if (v
<= 0 || v
>= UINT64_MAX
) {
3117 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3125 int config_parse_device_allow(
3127 const char *filename
,
3129 const char *section
,
3130 unsigned section_line
,
3137 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3138 CGroupContext
*c
= data
;
3139 CGroupDeviceAllow
*a
;
3140 const char *m
= NULL
;
3144 if (isempty(rvalue
)) {
3145 while (c
->device_allow
)
3146 cgroup_context_free_device_allow(c
, c
->device_allow
);
3151 r
= unit_full_printf(userdata
, rvalue
, &t
);
3153 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3154 "Failed to resolve specifiers in %s, ignoring: %m",
3158 n
= strcspn(t
, WHITESPACE
);
3160 path
= strndup(t
, n
);
3164 if (!is_deviceallow_pattern(path
)) {
3165 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3169 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3173 if (!in_charset(m
, "rwm")) {
3174 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3178 a
= new0(CGroupDeviceAllow
, 1);
3184 a
->r
= !!strchr(m
, 'r');
3185 a
->w
= !!strchr(m
, 'w');
3186 a
->m
= !!strchr(m
, 'm');
3188 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3192 int config_parse_io_weight(
3194 const char *filename
,
3196 const char *section
,
3197 unsigned section_line
,
3204 uint64_t *weight
= data
;
3211 r
= cg_weight_parse(rvalue
, weight
);
3213 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3220 int config_parse_io_device_weight(
3222 const char *filename
,
3224 const char *section
,
3225 unsigned section_line
,
3232 _cleanup_free_
char *path
= NULL
;
3233 CGroupIODeviceWeight
*w
;
3234 CGroupContext
*c
= data
;
3244 if (isempty(rvalue
)) {
3245 while (c
->io_device_weights
)
3246 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3251 n
= strcspn(rvalue
, WHITESPACE
);
3252 weight
= rvalue
+ n
;
3253 weight
+= strspn(weight
, WHITESPACE
);
3255 if (isempty(weight
)) {
3256 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3260 path
= strndup(rvalue
, n
);
3264 if (!path_startswith(path
, "/dev")) {
3265 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3269 r
= cg_weight_parse(weight
, &u
);
3271 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3275 assert(u
!= CGROUP_WEIGHT_INVALID
);
3277 w
= new0(CGroupIODeviceWeight
, 1);
3286 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3290 int config_parse_io_limit(
3292 const char *filename
,
3294 const char *section
,
3295 unsigned section_line
,
3302 _cleanup_free_
char *path
= NULL
;
3303 CGroupIODeviceLimit
*l
= NULL
, *t
;
3304 CGroupContext
*c
= data
;
3305 CGroupIOLimitType type
;
3315 type
= cgroup_io_limit_type_from_string(lvalue
);
3318 if (isempty(rvalue
)) {
3319 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3320 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3324 n
= strcspn(rvalue
, WHITESPACE
);
3326 limit
+= strspn(limit
, WHITESPACE
);
3329 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3333 path
= strndup(rvalue
, n
);
3337 if (!path_startswith(path
, "/dev")) {
3338 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3342 if (streq("infinity", limit
)) {
3343 num
= CGROUP_LIMIT_MAX
;
3345 r
= parse_size(limit
, 1000, &num
);
3346 if (r
< 0 || num
<= 0) {
3347 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3352 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3353 if (path_equal(path
, t
->path
)) {
3360 CGroupIOLimitType ttype
;
3362 l
= new0(CGroupIODeviceLimit
, 1);
3368 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3369 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3371 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3374 l
->limits
[type
] = num
;
3379 int config_parse_blockio_weight(
3381 const char *filename
,
3383 const char *section
,
3384 unsigned section_line
,
3391 uint64_t *weight
= data
;
3398 r
= cg_blkio_weight_parse(rvalue
, weight
);
3400 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3407 int config_parse_blockio_device_weight(
3409 const char *filename
,
3411 const char *section
,
3412 unsigned section_line
,
3419 _cleanup_free_
char *path
= NULL
;
3420 CGroupBlockIODeviceWeight
*w
;
3421 CGroupContext
*c
= data
;
3431 if (isempty(rvalue
)) {
3432 while (c
->blockio_device_weights
)
3433 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3438 n
= strcspn(rvalue
, WHITESPACE
);
3439 weight
= rvalue
+ n
;
3440 weight
+= strspn(weight
, WHITESPACE
);
3442 if (isempty(weight
)) {
3443 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3447 path
= strndup(rvalue
, n
);
3451 if (!path_startswith(path
, "/dev")) {
3452 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3456 r
= cg_blkio_weight_parse(weight
, &u
);
3458 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3462 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3464 w
= new0(CGroupBlockIODeviceWeight
, 1);
3473 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3477 int config_parse_blockio_bandwidth(
3479 const char *filename
,
3481 const char *section
,
3482 unsigned section_line
,
3489 _cleanup_free_
char *path
= NULL
;
3490 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3491 CGroupContext
*c
= data
;
3492 const char *bandwidth
;
3502 read
= streq("BlockIOReadBandwidth", lvalue
);
3504 if (isempty(rvalue
)) {
3505 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3506 b
->rbps
= CGROUP_LIMIT_MAX
;
3507 b
->wbps
= CGROUP_LIMIT_MAX
;
3512 n
= strcspn(rvalue
, WHITESPACE
);
3513 bandwidth
= rvalue
+ n
;
3514 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3517 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3521 path
= strndup(rvalue
, n
);
3525 if (!path_startswith(path
, "/dev")) {
3526 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3530 r
= parse_size(bandwidth
, 1000, &bytes
);
3531 if (r
< 0 || bytes
<= 0) {
3532 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3536 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3537 if (path_equal(path
, t
->path
)) {
3544 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3550 b
->rbps
= CGROUP_LIMIT_MAX
;
3551 b
->wbps
= CGROUP_LIMIT_MAX
;
3553 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3564 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3566 int config_parse_job_mode_isolate(
3568 const char *filename
,
3570 const char *section
,
3571 unsigned section_line
,
3585 r
= parse_boolean(rvalue
);
3587 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3591 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3595 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3597 int config_parse_exec_directories(
3599 const char *filename
,
3601 const char *section
,
3602 unsigned section_line
,
3619 if (isempty(rvalue
)) {
3620 /* Empty assignment resets the list */
3621 *rt
= strv_free(*rt
);
3625 for (p
= rvalue
;;) {
3626 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3628 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3634 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3635 "Invalid syntax, ignoring: %s", rvalue
);
3639 r
= unit_full_printf(u
, word
, &k
);
3641 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3642 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3646 if (!path_is_safe(k
) || path_is_absolute(k
)) {
3647 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3648 "%s is not valid, ignoring assignment: %s", lvalue
, rvalue
);
3652 r
= strv_push(rt
, k
);
3659 int config_parse_set_status(
3661 const char *filename
,
3663 const char *section
,
3664 unsigned section_line
,
3672 const char *word
, *state
;
3674 ExitStatusSet
*status_set
= data
;
3681 /* Empty assignment resets the list */
3682 if (isempty(rvalue
)) {
3683 exit_status_set_free(status_set
);
3687 FOREACH_WORD(word
, l
, rvalue
, state
) {
3688 _cleanup_free_
char *temp
;
3692 temp
= strndup(word
, l
);
3696 r
= safe_atoi(temp
, &val
);
3698 val
= signal_from_string_try_harder(temp
);
3701 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3704 set
= &status_set
->signal
;
3706 if (val
< 0 || val
> 255) {
3707 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3710 set
= &status_set
->status
;
3713 r
= set_ensure_allocated(set
, NULL
);
3717 r
= set_put(*set
, INT_TO_PTR(val
));
3719 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3723 if (!isempty(state
))
3724 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3729 int config_parse_namespace_path_strv(
3731 const char *filename
,
3733 const char *section
,
3734 unsigned section_line
,
3751 if (isempty(rvalue
)) {
3752 /* Empty assignment resets the list */
3753 *sv
= strv_free(*sv
);
3759 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3761 bool ignore_enoent
= false, shall_prefix
= false;
3763 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3769 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3773 if (!utf8_is_valid(word
)) {
3774 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3779 if (startswith(w
, "-")) {
3780 ignore_enoent
= true;
3783 if (startswith(w
, "+")) {
3784 shall_prefix
= true;
3788 r
= unit_full_printf(u
, w
, &resolved
);
3790 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3794 if (!path_is_absolute(resolved
)) {
3795 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3799 path_kill_slashes(resolved
);
3801 joined
= strjoin(ignore_enoent
? "-" : "",
3802 shall_prefix
? "+" : "",
3805 r
= strv_push(sv
, joined
);
3815 int config_parse_bind_paths(
3817 const char *filename
,
3819 const char *section
,
3820 unsigned section_line
,
3827 ExecContext
*c
= data
;
3837 if (isempty(rvalue
)) {
3838 /* Empty assignment resets the list */
3839 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3840 c
->bind_mounts
= NULL
;
3841 c
->n_bind_mounts
= 0;
3847 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3848 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3849 char *s
= NULL
, *d
= NULL
;
3850 bool rbind
= true, ignore_enoent
= false;
3852 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3858 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3862 r
= unit_full_printf(u
, source
, &sresolved
);
3864 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3865 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3871 ignore_enoent
= true;
3875 if (!utf8_is_valid(s
)) {
3876 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3879 if (!path_is_absolute(s
)) {
3880 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3884 path_kill_slashes(s
);
3886 /* Optionally, the destination is specified. */
3887 if (p
&& p
[-1] == ':') {
3888 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3892 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3896 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3900 r
= unit_full_printf(u
, destination
, &dresolved
);
3902 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3903 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3907 if (!utf8_is_valid(dresolved
)) {
3908 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
3911 if (!path_is_absolute(dresolved
)) {
3912 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
3916 d
= path_kill_slashes(dresolved
);
3918 /* Optionally, there's also a short option string specified */
3919 if (p
&& p
[-1] == ':') {
3920 _cleanup_free_
char *options
= NULL
;
3922 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
3926 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3930 if (isempty(options
) || streq(options
, "rbind"))
3932 else if (streq(options
, "norbind"))
3935 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
3942 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
3946 .read_only
= !!strstr(lvalue
, "ReadOnly"),
3948 .ignore_enoent
= ignore_enoent
,
3957 int config_parse_no_new_privileges(
3959 const char *filename
,
3961 const char *section
,
3962 unsigned section_line
,
3969 ExecContext
*c
= data
;
3977 k
= parse_boolean(rvalue
);
3979 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3983 c
->no_new_privileges
= k
;
3988 int config_parse_protect_home(
3990 const char *filename
,
3992 const char *section
,
3993 unsigned section_line
,
4000 ExecContext
*c
= data
;
4008 /* Our enum shall be a superset of booleans, hence first try
4009 * to parse as boolean, and then as enum */
4011 k
= parse_boolean(rvalue
);
4013 c
->protect_home
= PROTECT_HOME_YES
;
4015 c
->protect_home
= PROTECT_HOME_NO
;
4019 h
= protect_home_from_string(rvalue
);
4021 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4025 c
->protect_home
= h
;
4031 int config_parse_protect_system(
4033 const char *filename
,
4035 const char *section
,
4036 unsigned section_line
,
4043 ExecContext
*c
= data
;
4051 /* Our enum shall be a superset of booleans, hence first try
4052 * to parse as boolean, and then as enum */
4054 k
= parse_boolean(rvalue
);
4056 c
->protect_system
= PROTECT_SYSTEM_YES
;
4058 c
->protect_system
= PROTECT_SYSTEM_NO
;
4062 s
= protect_system_from_string(rvalue
);
4064 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4068 c
->protect_system
= s
;
4074 #define FOLLOW_MAX 8
4076 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4087 /* This will update the filename pointer if the loaded file is
4088 * reached by a symlink. The old string will be freed. */
4091 char *target
, *name
;
4093 if (c
++ >= FOLLOW_MAX
)
4096 path_kill_slashes(*filename
);
4098 /* Add the file name we are currently looking at to
4099 * the names of this unit, but only if it is a valid
4101 name
= basename(*filename
);
4102 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4104 id
= set_get(names
, name
);
4110 r
= set_consume(names
, id
);
4116 /* Try to open the file name, but don't if its a symlink */
4117 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4124 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4125 r
= readlink_and_make_absolute(*filename
, &target
);
4133 f
= fdopen(fd
, "re");
4145 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4153 /* Let's try to add in all symlink names we found */
4154 while ((k
= set_steal_first(names
))) {
4156 /* First try to merge in the other name into our
4158 r
= unit_merge_by_name(*u
, k
);
4162 /* Hmm, we couldn't merge the other unit into
4163 * ours? Then let's try it the other way
4166 /* If the symlink name we are looking at is unit template, then
4167 we must search for instance of this template */
4168 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4169 _cleanup_free_
char *instance
= NULL
;
4171 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4175 other
= manager_get_unit((*u
)->manager
, instance
);
4177 other
= manager_get_unit((*u
)->manager
, k
);
4182 r
= unit_merge(other
, *u
);
4185 return merge_by_names(u
, names
, NULL
);
4193 unit_choose_id(*u
, id
);
4201 static int load_from_path(Unit
*u
, const char *path
) {
4202 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4203 _cleanup_fclose_
FILE *f
= NULL
;
4204 _cleanup_free_
char *filename
= NULL
;
4213 symlink_names
= set_new(&string_hash_ops
);
4217 if (path_is_absolute(path
)) {
4219 filename
= strdup(path
);
4223 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4225 filename
= mfree(filename
);
4233 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4235 /* Instead of opening the path right away, we manually
4236 * follow all symlinks and add their name to our unit
4237 * name set while doing so */
4238 filename
= path_make_absolute(path
, *p
);
4242 if (u
->manager
->unit_path_cache
&&
4243 !set_get(u
->manager
->unit_path_cache
, filename
))
4246 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4249 filename
= mfree(filename
);
4251 /* ENOENT means that the file is missing or is a dangling symlink.
4252 * ENOTDIR means that one of paths we expect to be is a directory
4253 * is not a directory, we should just ignore that.
4254 * EACCES means that the directory or file permissions are wrong.
4257 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4258 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4261 /* Empty the symlink names for the next run */
4262 set_clear_free(symlink_names
);
4267 /* Hmm, no suitable file found? */
4270 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4271 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4276 r
= merge_by_names(&merged
, symlink_names
, id
);
4281 u
->load_state
= UNIT_MERGED
;
4285 if (fstat(fileno(f
), &st
) < 0)
4288 if (null_or_empty(&st
)) {
4289 u
->load_state
= UNIT_MASKED
;
4290 u
->fragment_mtime
= 0;
4292 u
->load_state
= UNIT_LOADED
;
4293 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4295 /* Now, parse the file contents */
4296 r
= config_parse(u
->id
, filename
, f
,
4297 UNIT_VTABLE(u
)->sections
,
4298 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4299 false, true, false, u
);
4304 free(u
->fragment_path
);
4305 u
->fragment_path
= filename
;
4308 if (u
->source_path
) {
4309 if (stat(u
->source_path
, &st
) >= 0)
4310 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4312 u
->source_mtime
= 0;
4318 int unit_load_fragment(Unit
*u
) {
4324 assert(u
->load_state
== UNIT_STUB
);
4328 u
->load_state
= UNIT_LOADED
;
4332 /* First, try to find the unit under its id. We always look
4333 * for unit files in the default directories, to make it easy
4334 * to override things by placing things in /etc/systemd/system */
4335 r
= load_from_path(u
, u
->id
);
4339 /* Try to find an alias we can load this with */
4340 if (u
->load_state
== UNIT_STUB
) {
4341 SET_FOREACH(t
, u
->names
, i
) {
4346 r
= load_from_path(u
, t
);
4350 if (u
->load_state
!= UNIT_STUB
)
4355 /* And now, try looking for it under the suggested (originally linked) path */
4356 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4358 r
= load_from_path(u
, u
->fragment_path
);
4362 if (u
->load_state
== UNIT_STUB
)
4363 /* Hmm, this didn't work? Then let's get rid
4364 * of the fragment path stored for us, so that
4365 * we don't point to an invalid location. */
4366 u
->fragment_path
= mfree(u
->fragment_path
);
4369 /* Look for a template */
4370 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4371 _cleanup_free_
char *k
= NULL
;
4373 r
= unit_name_template(u
->id
, &k
);
4377 r
= load_from_path(u
, k
);
4380 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4384 if (u
->load_state
== UNIT_STUB
) {
4385 SET_FOREACH(t
, u
->names
, i
) {
4386 _cleanup_free_
char *z
= NULL
;
4391 r
= unit_name_template(t
, &z
);
4395 r
= load_from_path(u
, z
);
4399 if (u
->load_state
!= UNIT_STUB
)
4408 void unit_dump_config_items(FILE *f
) {
4409 static const struct {
4410 const ConfigParserCallback callback
;
4413 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4414 { config_parse_warn_compat
, "NOTSUPPORTED" },
4416 { config_parse_int
, "INTEGER" },
4417 { config_parse_unsigned
, "UNSIGNED" },
4418 { config_parse_iec_size
, "SIZE" },
4419 { config_parse_iec_uint64
, "SIZE" },
4420 { config_parse_si_size
, "SIZE" },
4421 { config_parse_bool
, "BOOLEAN" },
4422 { config_parse_string
, "STRING" },
4423 { config_parse_path
, "PATH" },
4424 { config_parse_unit_path_printf
, "PATH" },
4425 { config_parse_strv
, "STRING [...]" },
4426 { config_parse_exec_nice
, "NICE" },
4427 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4428 { config_parse_exec_io_class
, "IOCLASS" },
4429 { config_parse_exec_io_priority
, "IOPRIORITY" },
4430 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4431 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4432 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4433 { config_parse_mode
, "MODE" },
4434 { config_parse_unit_env_file
, "FILE" },
4435 { config_parse_exec_output
, "OUTPUT" },
4436 { config_parse_exec_input
, "INPUT" },
4437 { config_parse_log_facility
, "FACILITY" },
4438 { config_parse_log_level
, "LEVEL" },
4439 { config_parse_exec_secure_bits
, "SECUREBITS" },
4440 { config_parse_capability_set
, "BOUNDINGSET" },
4441 { config_parse_limit
, "LIMIT" },
4442 { config_parse_unit_deps
, "UNIT [...]" },
4443 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4444 { config_parse_service_type
, "SERVICETYPE" },
4445 { config_parse_service_restart
, "SERVICERESTART" },
4446 #ifdef HAVE_SYSV_COMPAT
4447 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4449 { config_parse_kill_mode
, "KILLMODE" },
4450 { config_parse_signal
, "SIGNAL" },
4451 { config_parse_socket_listen
, "SOCKET [...]" },
4452 { config_parse_socket_bind
, "SOCKETBIND" },
4453 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4454 { config_parse_sec
, "SECONDS" },
4455 { config_parse_nsec
, "NANOSECONDS" },
4456 { config_parse_namespace_path_strv
, "PATH [...]" },
4457 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4458 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4459 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4460 { config_parse_unit_string_printf
, "STRING" },
4461 { config_parse_trigger_unit
, "UNIT" },
4462 { config_parse_timer
, "TIMER" },
4463 { config_parse_path_spec
, "PATH" },
4464 { config_parse_notify_access
, "ACCESS" },
4465 { config_parse_ip_tos
, "TOS" },
4466 { config_parse_unit_condition_path
, "CONDITION" },
4467 { config_parse_unit_condition_string
, "CONDITION" },
4468 { config_parse_unit_condition_null
, "CONDITION" },
4469 { config_parse_unit_slice
, "SLICE" },
4470 { config_parse_documentation
, "URL" },
4471 { config_parse_service_timeout
, "SECONDS" },
4472 { config_parse_emergency_action
, "ACTION" },
4473 { config_parse_set_status
, "STATUS" },
4474 { config_parse_service_sockets
, "SOCKETS" },
4475 { config_parse_environ
, "ENVIRON" },
4477 { config_parse_syscall_filter
, "SYSCALLS" },
4478 { config_parse_syscall_archs
, "ARCHS" },
4479 { config_parse_syscall_errno
, "ERRNO" },
4480 { config_parse_address_families
, "FAMILIES" },
4481 { config_parse_restrict_namespaces
, "NAMESPACES" },
4483 { config_parse_cpu_shares
, "SHARES" },
4484 { config_parse_cpu_weight
, "WEIGHT" },
4485 { config_parse_memory_limit
, "LIMIT" },
4486 { config_parse_device_allow
, "DEVICE" },
4487 { config_parse_device_policy
, "POLICY" },
4488 { config_parse_io_limit
, "LIMIT" },
4489 { config_parse_io_weight
, "WEIGHT" },
4490 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4491 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4492 { config_parse_blockio_weight
, "WEIGHT" },
4493 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4494 { config_parse_long
, "LONG" },
4495 { config_parse_socket_service
, "SERVICE" },
4497 { config_parse_exec_selinux_context
, "LABEL" },
4499 { config_parse_job_mode
, "MODE" },
4500 { config_parse_job_mode_isolate
, "BOOLEAN" },
4501 { config_parse_personality
, "PERSONALITY" },
4504 const char *prev
= NULL
;
4509 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4510 const char *rvalue
= "OTHER", *lvalue
;
4514 const ConfigPerfItem
*p
;
4516 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4518 dot
= strchr(i
, '.');
4519 lvalue
= dot
? dot
+ 1 : i
;
4523 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4527 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4530 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4531 if (p
->parse
== table
[j
].callback
) {
4532 rvalue
= table
[j
].rvalue
;
4536 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);