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 (streq(lvalue
, "CapabilityBoundingSet"))
1173 initial
= CAP_ALL
; /* initialized to all bits on */
1174 /* else "AmbientCapabilities" initialized to all bits off */
1176 r
= capability_set_from_string(rvalue
, &sum
);
1180 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1184 sum
= invert
? ~sum
: sum
;
1186 if (sum
== 0 || *capability_set
== initial
)
1187 /* "" or uninitialized data -> replace */
1188 *capability_set
= sum
;
1190 /* previous data -> merge */
1191 *capability_set
|= sum
;
1196 int config_parse_limit(
1198 const char *filename
,
1200 const char *section
,
1201 unsigned section_line
,
1208 struct rlimit
**rl
= data
, d
= {};
1216 r
= rlimit_parse(ltype
, rvalue
, &d
);
1218 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1222 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1229 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1237 #ifdef HAVE_SYSV_COMPAT
1238 int config_parse_sysv_priority(const char *unit
,
1239 const char *filename
,
1241 const char *section
,
1242 unsigned section_line
,
1249 int *priority
= data
;
1257 r
= safe_atoi(rvalue
, &i
);
1258 if (r
< 0 || i
< 0) {
1259 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1263 *priority
= (int) i
;
1268 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1269 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1271 int config_parse_exec_mount_flags(
1273 const char *filename
,
1275 const char *section
,
1276 unsigned section_line
,
1284 ExecContext
*c
= data
;
1292 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1294 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1299 int config_parse_exec_selinux_context(
1301 const char *filename
,
1303 const char *section
,
1304 unsigned section_line
,
1311 ExecContext
*c
= data
;
1322 if (isempty(rvalue
)) {
1323 c
->selinux_context
= mfree(c
->selinux_context
);
1324 c
->selinux_context_ignore
= false;
1328 if (rvalue
[0] == '-') {
1334 r
= unit_full_printf(u
, rvalue
, &k
);
1336 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1337 "Failed to resolve specifiers%s: %m",
1338 ignore
? ", ignoring" : "");
1339 return ignore
? 0 : -ENOEXEC
;
1342 free(c
->selinux_context
);
1343 c
->selinux_context
= k
;
1344 c
->selinux_context_ignore
= ignore
;
1349 int config_parse_exec_apparmor_profile(
1351 const char *filename
,
1353 const char *section
,
1354 unsigned section_line
,
1361 ExecContext
*c
= data
;
1372 if (isempty(rvalue
)) {
1373 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1374 c
->apparmor_profile_ignore
= false;
1378 if (rvalue
[0] == '-') {
1384 r
= unit_full_printf(u
, rvalue
, &k
);
1386 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1387 "Failed to resolve specifiers%s: %m",
1388 ignore
? ", ignoring" : "");
1389 return ignore
? 0 : -ENOEXEC
;
1392 free(c
->apparmor_profile
);
1393 c
->apparmor_profile
= k
;
1394 c
->apparmor_profile_ignore
= ignore
;
1399 int config_parse_exec_smack_process_label(
1401 const char *filename
,
1403 const char *section
,
1404 unsigned section_line
,
1411 ExecContext
*c
= data
;
1422 if (isempty(rvalue
)) {
1423 c
->smack_process_label
= mfree(c
->smack_process_label
);
1424 c
->smack_process_label_ignore
= false;
1428 if (rvalue
[0] == '-') {
1434 r
= unit_full_printf(u
, rvalue
, &k
);
1436 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1437 "Failed to resolve specifiers%s: %m",
1438 ignore
? ", ignoring" : "");
1439 return ignore
? 0 : -ENOEXEC
;
1442 free(c
->smack_process_label
);
1443 c
->smack_process_label
= k
;
1444 c
->smack_process_label_ignore
= ignore
;
1449 int config_parse_timer(const char *unit
,
1450 const char *filename
,
1452 const char *section
,
1453 unsigned section_line
,
1464 CalendarSpec
*c
= NULL
;
1466 _cleanup_free_
char *k
= NULL
;
1474 if (isempty(rvalue
)) {
1475 /* Empty assignment resets list */
1476 timer_free_values(t
);
1480 b
= timer_base_from_string(lvalue
);
1482 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1486 r
= unit_full_printf(u
, rvalue
, &k
);
1488 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1492 if (b
== TIMER_CALENDAR
) {
1493 if (calendar_spec_from_string(k
, &c
) < 0) {
1494 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1498 if (parse_sec(k
, &usec
) < 0) {
1499 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1504 v
= new0(TimerValue
, 1);
1506 calendar_spec_free(c
);
1512 v
->calendar_spec
= c
;
1514 LIST_PREPEND(value
, t
->values
, v
);
1519 int config_parse_trigger_unit(
1521 const char *filename
,
1523 const char *section
,
1524 unsigned section_line
,
1531 _cleanup_free_
char *p
= NULL
;
1541 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1542 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1546 r
= unit_name_printf(u
, rvalue
, &p
);
1548 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1552 type
= unit_name_to_type(p
);
1554 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1558 if (type
== u
->type
) {
1559 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1563 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1565 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1572 int config_parse_path_spec(const char *unit
,
1573 const char *filename
,
1575 const char *section
,
1576 unsigned section_line
,
1586 _cleanup_free_
char *k
= NULL
;
1594 if (isempty(rvalue
)) {
1595 /* Empty assignment clears list */
1600 b
= path_type_from_string(lvalue
);
1602 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1606 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1608 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1612 if (!path_is_absolute(k
)) {
1613 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1617 s
= new0(PathSpec
, 1);
1622 s
->path
= path_kill_slashes(k
);
1627 LIST_PREPEND(spec
, p
->specs
, s
);
1632 int config_parse_socket_service(
1634 const char *filename
,
1636 const char *section
,
1637 unsigned section_line
,
1644 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1645 _cleanup_free_
char *p
= NULL
;
1655 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1657 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1661 if (!endswith(p
, ".service")) {
1662 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1666 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1668 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1672 unit_ref_set(&s
->service
, x
);
1677 int config_parse_fdname(
1679 const char *filename
,
1681 const char *section
,
1682 unsigned section_line
,
1689 _cleanup_free_
char *p
= NULL
;
1698 if (isempty(rvalue
)) {
1699 s
->fdname
= mfree(s
->fdname
);
1703 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1705 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1709 if (!fdname_is_valid(p
)) {
1710 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1714 return free_and_replace(s
->fdname
, p
);
1717 int config_parse_service_sockets(
1719 const char *filename
,
1721 const char *section
,
1722 unsigned section_line
,
1740 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1742 r
= extract_first_word(&p
, &word
, NULL
, 0);
1748 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1752 r
= unit_name_printf(UNIT(s
), word
, &k
);
1754 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1758 if (!endswith(k
, ".socket")) {
1759 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1763 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1765 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1767 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1769 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1775 int config_parse_bus_name(
1777 const char *filename
,
1779 const char *section
,
1780 unsigned section_line
,
1787 _cleanup_free_
char *k
= NULL
;
1796 r
= unit_full_printf(u
, rvalue
, &k
);
1798 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1802 if (!service_name_is_valid(k
)) {
1803 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1807 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1810 int config_parse_service_timeout(
1812 const char *filename
,
1814 const char *section
,
1815 unsigned section_line
,
1822 Service
*s
= userdata
;
1831 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1833 r
= parse_sec(rvalue
, &usec
);
1835 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1839 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1840 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1841 * all other timeouts. */
1843 usec
= USEC_INFINITY
;
1845 if (!streq(lvalue
, "TimeoutStopSec")) {
1846 s
->start_timeout_defined
= true;
1847 s
->timeout_start_usec
= usec
;
1850 if (!streq(lvalue
, "TimeoutStartSec"))
1851 s
->timeout_stop_usec
= usec
;
1856 int config_parse_sec_fix_0(
1858 const char *filename
,
1860 const char *section
,
1861 unsigned section_line
,
1868 usec_t
*usec
= data
;
1876 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1877 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1880 r
= parse_sec_fix_0(rvalue
, usec
);
1882 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1889 int config_parse_user_group(
1891 const char *filename
,
1893 const char *section
,
1894 unsigned section_line
,
1901 char **user
= data
, *n
;
1910 if (isempty(rvalue
))
1913 _cleanup_free_
char *k
= NULL
;
1915 r
= unit_full_printf(u
, rvalue
, &k
);
1917 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
1921 if (!valid_user_group_name_or_id(k
)) {
1922 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1936 int config_parse_user_group_strv(
1938 const char *filename
,
1940 const char *section
,
1941 unsigned section_line
,
1948 char ***users
= data
;
1958 if (isempty(rvalue
)) {
1961 empty
= new0(char*, 1);
1973 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1975 r
= extract_first_word(&p
, &word
, NULL
, 0);
1981 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
1985 r
= unit_full_printf(u
, word
, &k
);
1987 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
1991 if (!valid_user_group_name_or_id(k
)) {
1992 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
1996 r
= strv_push(users
, k
);
2006 int config_parse_working_directory(
2008 const char *filename
,
2010 const char *section
,
2011 unsigned section_line
,
2018 ExecContext
*c
= data
;
2029 if (rvalue
[0] == '-') {
2035 if (streq(rvalue
, "~")) {
2036 c
->working_directory_home
= true;
2037 c
->working_directory
= mfree(c
->working_directory
);
2039 _cleanup_free_
char *k
= NULL
;
2041 r
= unit_full_printf(u
, rvalue
, &k
);
2043 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2044 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2045 rvalue
, missing_ok
? ", ignoring" : "");
2046 return missing_ok
? 0 : -ENOEXEC
;
2049 path_kill_slashes(k
);
2051 if (!utf8_is_valid(k
)) {
2052 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2053 return missing_ok
? 0 : -ENOEXEC
;
2056 if (!path_is_absolute(k
)) {
2057 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2058 "Working directory path '%s' is not absolute%s.",
2059 rvalue
, missing_ok
? ", ignoring" : "");
2060 return missing_ok
? 0 : -ENOEXEC
;
2063 c
->working_directory_home
= false;
2064 free_and_replace(c
->working_directory
, k
);
2067 c
->working_directory_missing_ok
= missing_ok
;
2071 int config_parse_unit_env_file(const char *unit
,
2072 const char *filename
,
2074 const char *section
,
2075 unsigned section_line
,
2084 _cleanup_free_
char *n
= NULL
;
2092 if (isempty(rvalue
)) {
2093 /* Empty assignment frees the list */
2094 *env
= strv_free(*env
);
2098 r
= unit_full_printf(u
, rvalue
, &n
);
2100 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2104 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2105 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2109 r
= strv_extend(env
, n
);
2116 int config_parse_environ(const char *unit
,
2117 const char *filename
,
2119 const char *section
,
2120 unsigned section_line
,
2137 if (isempty(rvalue
)) {
2138 /* Empty assignment resets the list */
2139 *env
= strv_free(*env
);
2143 for (p
= rvalue
;; ) {
2144 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2146 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2152 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2153 "Invalid syntax, ignoring: %s", rvalue
);
2158 r
= unit_full_printf(u
, word
, &k
);
2160 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2161 "Failed to resolve specifiers, ignoring: %s", k
);
2169 if (!env_assignment_is_valid(k
)) {
2170 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2171 "Invalid environment assignment, ignoring: %s", k
);
2175 r
= strv_env_replace(env
, k
);
2182 int config_parse_pass_environ(const char *unit
,
2183 const char *filename
,
2185 const char *section
,
2186 unsigned section_line
,
2193 const char *whole_rvalue
= rvalue
;
2194 char*** passenv
= data
;
2195 _cleanup_strv_free_
char **n
= NULL
;
2196 size_t nlen
= 0, nbufsize
= 0;
2204 if (isempty(rvalue
)) {
2205 /* Empty assignment resets the list */
2206 *passenv
= strv_free(*passenv
);
2211 _cleanup_free_
char *word
= NULL
;
2213 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2219 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2220 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2224 if (!env_name_is_valid(word
)) {
2225 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2226 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2230 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2238 r
= strv_extend_strv(passenv
, n
, true);
2246 int config_parse_ip_tos(const char *unit
,
2247 const char *filename
,
2249 const char *section
,
2250 unsigned section_line
,
2257 int *ip_tos
= data
, x
;
2264 x
= ip_tos_from_string(rvalue
);
2266 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2274 int config_parse_unit_condition_path(
2276 const char *filename
,
2278 const char *section
,
2279 unsigned section_line
,
2286 _cleanup_free_
char *p
= NULL
;
2287 Condition
**list
= data
, *c
;
2288 ConditionType t
= ltype
;
2289 bool trigger
, negate
;
2298 if (isempty(rvalue
)) {
2299 /* Empty assignment resets the list */
2300 *list
= condition_free_list(*list
);
2304 trigger
= rvalue
[0] == '|';
2308 negate
= rvalue
[0] == '!';
2312 r
= unit_full_printf(u
, rvalue
, &p
);
2314 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2318 if (!path_is_absolute(p
)) {
2319 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2323 c
= condition_new(t
, p
, trigger
, negate
);
2327 LIST_PREPEND(conditions
, *list
, c
);
2331 int config_parse_unit_condition_string(
2333 const char *filename
,
2335 const char *section
,
2336 unsigned section_line
,
2343 _cleanup_free_
char *s
= NULL
;
2344 Condition
**list
= data
, *c
;
2345 ConditionType t
= ltype
;
2346 bool trigger
, negate
;
2355 if (isempty(rvalue
)) {
2356 /* Empty assignment resets the list */
2357 *list
= condition_free_list(*list
);
2361 trigger
= rvalue
[0] == '|';
2365 negate
= rvalue
[0] == '!';
2369 r
= unit_full_printf(u
, rvalue
, &s
);
2371 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2375 c
= condition_new(t
, s
, trigger
, negate
);
2379 LIST_PREPEND(conditions
, *list
, c
);
2383 int config_parse_unit_condition_null(
2385 const char *filename
,
2387 const char *section
,
2388 unsigned section_line
,
2395 Condition
**list
= data
, *c
;
2396 bool trigger
, negate
;
2404 if (isempty(rvalue
)) {
2405 /* Empty assignment resets the list */
2406 *list
= condition_free_list(*list
);
2410 trigger
= rvalue
[0] == '|';
2414 negate
= rvalue
[0] == '!';
2418 b
= parse_boolean(rvalue
);
2420 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2427 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2431 LIST_PREPEND(conditions
, *list
, c
);
2435 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2436 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2438 int config_parse_unit_requires_mounts_for(
2440 const char *filename
,
2442 const char *section
,
2443 unsigned section_line
,
2459 for (p
= rvalue
;; ) {
2460 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2462 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2468 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2469 "Invalid syntax, ignoring: %s", rvalue
);
2473 if (!utf8_is_valid(word
)) {
2474 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2478 r
= unit_full_printf(u
, word
, &resolved
);
2480 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2484 r
= unit_require_mounts_for(u
, resolved
);
2486 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2492 int config_parse_documentation(const char *unit
,
2493 const char *filename
,
2495 const char *section
,
2496 unsigned section_line
,
2512 if (isempty(rvalue
)) {
2513 /* Empty assignment resets the list */
2514 u
->documentation
= strv_free(u
->documentation
);
2518 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2519 rvalue
, data
, userdata
);
2523 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2525 if (documentation_url_is_valid(*a
))
2528 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2540 static int syscall_filter_parse_one(
2542 const char *filename
,
2551 const SyscallFilterSet
*set
;
2554 set
= syscall_filter_set_find(t
);
2557 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2561 NULSTR_FOREACH(i
, set
->value
) {
2562 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2569 id
= seccomp_syscall_resolve_name(t
);
2570 if (id
== __NR_SCMP_ERROR
) {
2572 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2576 /* If we previously wanted to forbid a syscall and now
2577 * we want to allow it, then remove it from the list
2579 if (!invert
== c
->syscall_whitelist
) {
2580 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2586 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2592 int config_parse_syscall_filter(
2594 const char *filename
,
2596 const char *section
,
2597 unsigned section_line
,
2604 ExecContext
*c
= data
;
2606 bool invert
= false;
2615 if (isempty(rvalue
)) {
2616 /* Empty assignment resets the list */
2617 c
->syscall_filter
= set_free(c
->syscall_filter
);
2618 c
->syscall_whitelist
= false;
2622 if (rvalue
[0] == '~') {
2627 if (!c
->syscall_filter
) {
2628 c
->syscall_filter
= set_new(NULL
);
2629 if (!c
->syscall_filter
)
2633 /* Allow everything but the ones listed */
2634 c
->syscall_whitelist
= false;
2636 /* Allow nothing but the ones listed */
2637 c
->syscall_whitelist
= true;
2639 /* Accept default syscalls if we are on a whitelist */
2640 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2648 _cleanup_free_
char *word
= NULL
;
2650 r
= extract_first_word(&p
, &word
, NULL
, 0);
2656 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2660 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2668 int config_parse_syscall_archs(
2670 const char *filename
,
2672 const char *section
,
2673 unsigned section_line
,
2684 if (isempty(rvalue
)) {
2685 *archs
= set_free(*archs
);
2689 r
= set_ensure_allocated(archs
, NULL
);
2693 for (p
= rvalue
;;) {
2694 _cleanup_free_
char *word
= NULL
;
2697 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2703 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2704 "Invalid syntax, ignoring: %s", rvalue
);
2708 r
= seccomp_arch_from_string(word
, &a
);
2710 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2711 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2715 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2721 int config_parse_syscall_errno(
2723 const char *filename
,
2725 const char *section
,
2726 unsigned section_line
,
2733 ExecContext
*c
= data
;
2740 if (isempty(rvalue
)) {
2741 /* Empty assignment resets to KILL */
2742 c
->syscall_errno
= 0;
2746 e
= errno_from_name(rvalue
);
2748 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2752 c
->syscall_errno
= e
;
2756 int config_parse_address_families(
2758 const char *filename
,
2760 const char *section
,
2761 unsigned section_line
,
2768 ExecContext
*c
= data
;
2769 bool invert
= false;
2777 if (isempty(rvalue
)) {
2778 /* Empty assignment resets the list */
2779 c
->address_families
= set_free(c
->address_families
);
2780 c
->address_families_whitelist
= false;
2784 if (rvalue
[0] == '~') {
2789 if (!c
->address_families
) {
2790 c
->address_families
= set_new(NULL
);
2791 if (!c
->address_families
)
2794 c
->address_families_whitelist
= !invert
;
2797 for (p
= rvalue
;;) {
2798 _cleanup_free_
char *word
= NULL
;
2801 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2807 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2808 "Invalid syntax, ignoring: %s", rvalue
);
2812 af
= af_from_name(word
);
2814 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2815 "Failed to parse address family \"%s\", ignoring: %m", word
);
2819 /* If we previously wanted to forbid an address family and now
2820 * we want to allow it, then just remove it from the list.
2822 if (!invert
== c
->address_families_whitelist
) {
2823 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2827 set_remove(c
->address_families
, INT_TO_PTR(af
));
2831 int config_parse_restrict_namespaces(
2833 const char *filename
,
2835 const char *section
,
2836 unsigned section_line
,
2843 ExecContext
*c
= data
;
2844 bool invert
= false;
2847 if (isempty(rvalue
)) {
2848 /* Reset to the default. */
2849 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2853 if (rvalue
[0] == '~') {
2858 r
= parse_boolean(rvalue
);
2860 c
->restrict_namespaces
= 0;
2862 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2864 /* Not a boolean argument, in this case it's a list of namespace types. */
2866 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2868 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2874 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2880 int config_parse_unit_slice(
2882 const char *filename
,
2884 const char *section
,
2885 unsigned section_line
,
2892 _cleanup_free_
char *k
= NULL
;
2893 Unit
*u
= userdata
, *slice
= NULL
;
2901 r
= unit_name_printf(u
, rvalue
, &k
);
2903 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2907 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2909 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2913 r
= unit_set_slice(u
, slice
);
2915 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2922 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2924 int config_parse_cpu_weight(
2926 const char *filename
,
2928 const char *section
,
2929 unsigned section_line
,
2936 uint64_t *weight
= data
;
2943 r
= cg_weight_parse(rvalue
, weight
);
2945 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
2952 int config_parse_cpu_shares(
2954 const char *filename
,
2956 const char *section
,
2957 unsigned section_line
,
2964 uint64_t *shares
= data
;
2971 r
= cg_cpu_shares_parse(rvalue
, shares
);
2973 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2980 int config_parse_cpu_quota(
2982 const char *filename
,
2984 const char *section
,
2985 unsigned section_line
,
2992 CGroupContext
*c
= data
;
2999 if (isempty(rvalue
)) {
3000 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3004 r
= parse_percent_unbounded(rvalue
);
3006 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3010 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3014 int config_parse_memory_limit(
3016 const char *filename
,
3018 const char *section
,
3019 unsigned section_line
,
3026 CGroupContext
*c
= data
;
3027 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3030 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3032 r
= parse_percent(rvalue
);
3034 r
= parse_size(rvalue
, 1024, &bytes
);
3036 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3040 bytes
= physical_memory_scale(r
, 100U);
3042 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3043 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3048 if (streq(lvalue
, "MemoryLow"))
3049 c
->memory_low
= bytes
;
3050 else if (streq(lvalue
, "MemoryHigh"))
3051 c
->memory_high
= bytes
;
3052 else if (streq(lvalue
, "MemoryMax"))
3053 c
->memory_max
= bytes
;
3054 else if (streq(lvalue
, "MemorySwapMax"))
3055 c
->memory_swap_max
= bytes
;
3056 else if (streq(lvalue
, "MemoryLimit"))
3057 c
->memory_limit
= bytes
;
3064 int config_parse_tasks_max(
3066 const char *filename
,
3068 const char *section
,
3069 unsigned section_line
,
3076 uint64_t *tasks_max
= data
, v
;
3080 if (isempty(rvalue
)) {
3081 *tasks_max
= u
->manager
->default_tasks_max
;
3085 if (streq(rvalue
, "infinity")) {
3086 *tasks_max
= CGROUP_LIMIT_MAX
;
3090 r
= parse_percent(rvalue
);
3092 r
= safe_atou64(rvalue
, &v
);
3094 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3098 v
= system_tasks_max_scale(r
, 100U);
3100 if (v
<= 0 || v
>= UINT64_MAX
) {
3101 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3109 int config_parse_device_allow(
3111 const char *filename
,
3113 const char *section
,
3114 unsigned section_line
,
3121 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3122 CGroupContext
*c
= data
;
3123 CGroupDeviceAllow
*a
;
3124 const char *m
= NULL
;
3128 if (isempty(rvalue
)) {
3129 while (c
->device_allow
)
3130 cgroup_context_free_device_allow(c
, c
->device_allow
);
3135 r
= unit_full_printf(userdata
, rvalue
, &t
);
3137 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3138 "Failed to resolve specifiers in %s, ignoring: %m",
3142 n
= strcspn(t
, WHITESPACE
);
3144 path
= strndup(t
, n
);
3148 if (!is_deviceallow_pattern(path
)) {
3149 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3153 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3157 if (!in_charset(m
, "rwm")) {
3158 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3162 a
= new0(CGroupDeviceAllow
, 1);
3168 a
->r
= !!strchr(m
, 'r');
3169 a
->w
= !!strchr(m
, 'w');
3170 a
->m
= !!strchr(m
, 'm');
3172 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3176 int config_parse_io_weight(
3178 const char *filename
,
3180 const char *section
,
3181 unsigned section_line
,
3188 uint64_t *weight
= data
;
3195 r
= cg_weight_parse(rvalue
, weight
);
3197 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3204 int config_parse_io_device_weight(
3206 const char *filename
,
3208 const char *section
,
3209 unsigned section_line
,
3216 _cleanup_free_
char *path
= NULL
;
3217 CGroupIODeviceWeight
*w
;
3218 CGroupContext
*c
= data
;
3228 if (isempty(rvalue
)) {
3229 while (c
->io_device_weights
)
3230 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3235 n
= strcspn(rvalue
, WHITESPACE
);
3236 weight
= rvalue
+ n
;
3237 weight
+= strspn(weight
, WHITESPACE
);
3239 if (isempty(weight
)) {
3240 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3244 path
= strndup(rvalue
, n
);
3248 if (!path_startswith(path
, "/dev")) {
3249 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3253 r
= cg_weight_parse(weight
, &u
);
3255 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3259 assert(u
!= CGROUP_WEIGHT_INVALID
);
3261 w
= new0(CGroupIODeviceWeight
, 1);
3270 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3274 int config_parse_io_limit(
3276 const char *filename
,
3278 const char *section
,
3279 unsigned section_line
,
3286 _cleanup_free_
char *path
= NULL
;
3287 CGroupIODeviceLimit
*l
= NULL
, *t
;
3288 CGroupContext
*c
= data
;
3289 CGroupIOLimitType type
;
3299 type
= cgroup_io_limit_type_from_string(lvalue
);
3302 if (isempty(rvalue
)) {
3303 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3304 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3308 n
= strcspn(rvalue
, WHITESPACE
);
3310 limit
+= strspn(limit
, WHITESPACE
);
3313 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3317 path
= strndup(rvalue
, n
);
3321 if (!path_startswith(path
, "/dev")) {
3322 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3326 if (streq("infinity", limit
)) {
3327 num
= CGROUP_LIMIT_MAX
;
3329 r
= parse_size(limit
, 1000, &num
);
3330 if (r
< 0 || num
<= 0) {
3331 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3336 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3337 if (path_equal(path
, t
->path
)) {
3344 CGroupIOLimitType ttype
;
3346 l
= new0(CGroupIODeviceLimit
, 1);
3352 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3353 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3355 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3358 l
->limits
[type
] = num
;
3363 int config_parse_blockio_weight(
3365 const char *filename
,
3367 const char *section
,
3368 unsigned section_line
,
3375 uint64_t *weight
= data
;
3382 r
= cg_blkio_weight_parse(rvalue
, weight
);
3384 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3391 int config_parse_blockio_device_weight(
3393 const char *filename
,
3395 const char *section
,
3396 unsigned section_line
,
3403 _cleanup_free_
char *path
= NULL
;
3404 CGroupBlockIODeviceWeight
*w
;
3405 CGroupContext
*c
= data
;
3415 if (isempty(rvalue
)) {
3416 while (c
->blockio_device_weights
)
3417 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3422 n
= strcspn(rvalue
, WHITESPACE
);
3423 weight
= rvalue
+ n
;
3424 weight
+= strspn(weight
, WHITESPACE
);
3426 if (isempty(weight
)) {
3427 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3431 path
= strndup(rvalue
, n
);
3435 if (!path_startswith(path
, "/dev")) {
3436 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3440 r
= cg_blkio_weight_parse(weight
, &u
);
3442 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3446 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3448 w
= new0(CGroupBlockIODeviceWeight
, 1);
3457 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3461 int config_parse_blockio_bandwidth(
3463 const char *filename
,
3465 const char *section
,
3466 unsigned section_line
,
3473 _cleanup_free_
char *path
= NULL
;
3474 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3475 CGroupContext
*c
= data
;
3476 const char *bandwidth
;
3486 read
= streq("BlockIOReadBandwidth", lvalue
);
3488 if (isempty(rvalue
)) {
3489 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3490 b
->rbps
= CGROUP_LIMIT_MAX
;
3491 b
->wbps
= CGROUP_LIMIT_MAX
;
3496 n
= strcspn(rvalue
, WHITESPACE
);
3497 bandwidth
= rvalue
+ n
;
3498 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3501 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3505 path
= strndup(rvalue
, n
);
3509 if (!path_startswith(path
, "/dev")) {
3510 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3514 r
= parse_size(bandwidth
, 1000, &bytes
);
3515 if (r
< 0 || bytes
<= 0) {
3516 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3520 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3521 if (path_equal(path
, t
->path
)) {
3528 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3534 b
->rbps
= CGROUP_LIMIT_MAX
;
3535 b
->wbps
= CGROUP_LIMIT_MAX
;
3537 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3548 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3550 int config_parse_job_mode_isolate(
3552 const char *filename
,
3554 const char *section
,
3555 unsigned section_line
,
3569 r
= parse_boolean(rvalue
);
3571 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3575 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3579 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3581 int config_parse_exec_directories(
3583 const char *filename
,
3585 const char *section
,
3586 unsigned section_line
,
3603 if (isempty(rvalue
)) {
3604 /* Empty assignment resets the list */
3605 *rt
= strv_free(*rt
);
3609 for (p
= rvalue
;;) {
3610 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3612 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3618 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3619 "Invalid syntax, ignoring: %s", rvalue
);
3623 r
= unit_full_printf(u
, word
, &k
);
3625 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3626 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3630 if (!path_is_safe(k
) || path_is_absolute(k
)) {
3631 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3632 "%s is not valid, ignoring assignment: %s", lvalue
, rvalue
);
3636 r
= strv_push(rt
, k
);
3643 int config_parse_set_status(
3645 const char *filename
,
3647 const char *section
,
3648 unsigned section_line
,
3656 const char *word
, *state
;
3658 ExitStatusSet
*status_set
= data
;
3665 /* Empty assignment resets the list */
3666 if (isempty(rvalue
)) {
3667 exit_status_set_free(status_set
);
3671 FOREACH_WORD(word
, l
, rvalue
, state
) {
3672 _cleanup_free_
char *temp
;
3676 temp
= strndup(word
, l
);
3680 r
= safe_atoi(temp
, &val
);
3682 val
= signal_from_string_try_harder(temp
);
3685 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3688 set
= &status_set
->signal
;
3690 if (val
< 0 || val
> 255) {
3691 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3694 set
= &status_set
->status
;
3697 r
= set_ensure_allocated(set
, NULL
);
3701 r
= set_put(*set
, INT_TO_PTR(val
));
3703 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3707 if (!isempty(state
))
3708 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3713 int config_parse_namespace_path_strv(
3715 const char *filename
,
3717 const char *section
,
3718 unsigned section_line
,
3735 if (isempty(rvalue
)) {
3736 /* Empty assignment resets the list */
3737 *sv
= strv_free(*sv
);
3743 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3745 bool ignore_enoent
= false, shall_prefix
= false;
3747 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3753 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3757 if (!utf8_is_valid(word
)) {
3758 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3763 if (startswith(w
, "-")) {
3764 ignore_enoent
= true;
3767 if (startswith(w
, "+")) {
3768 shall_prefix
= true;
3772 r
= unit_full_printf(u
, w
, &resolved
);
3774 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3778 if (!path_is_absolute(resolved
)) {
3779 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3783 path_kill_slashes(resolved
);
3785 joined
= strjoin(ignore_enoent
? "-" : "",
3786 shall_prefix
? "+" : "",
3789 r
= strv_push(sv
, joined
);
3799 int config_parse_bind_paths(
3801 const char *filename
,
3803 const char *section
,
3804 unsigned section_line
,
3811 ExecContext
*c
= data
;
3821 if (isempty(rvalue
)) {
3822 /* Empty assignment resets the list */
3823 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
3824 c
->bind_mounts
= NULL
;
3825 c
->n_bind_mounts
= 0;
3831 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
3832 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
3833 char *s
= NULL
, *d
= NULL
;
3834 bool rbind
= true, ignore_enoent
= false;
3836 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3842 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3846 r
= unit_full_printf(u
, source
, &sresolved
);
3848 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3849 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
3855 ignore_enoent
= true;
3859 if (!utf8_is_valid(s
)) {
3860 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
3863 if (!path_is_absolute(s
)) {
3864 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
3868 path_kill_slashes(s
);
3870 /* Optionally, the destination is specified. */
3871 if (p
&& p
[-1] == ':') {
3872 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
3876 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3880 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
3884 r
= unit_full_printf(u
, destination
, &dresolved
);
3886 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3887 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
3891 if (!utf8_is_valid(dresolved
)) {
3892 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
3895 if (!path_is_absolute(dresolved
)) {
3896 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
3900 d
= path_kill_slashes(dresolved
);
3902 /* Optionally, there's also a short option string specified */
3903 if (p
&& p
[-1] == ':') {
3904 _cleanup_free_
char *options
= NULL
;
3906 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
3910 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
3914 if (isempty(options
) || streq(options
, "rbind"))
3916 else if (streq(options
, "norbind"))
3919 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
3926 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
3930 .read_only
= !!strstr(lvalue
, "ReadOnly"),
3932 .ignore_enoent
= ignore_enoent
,
3941 int config_parse_no_new_privileges(
3943 const char *filename
,
3945 const char *section
,
3946 unsigned section_line
,
3953 ExecContext
*c
= data
;
3961 k
= parse_boolean(rvalue
);
3963 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3967 c
->no_new_privileges
= k
;
3972 int config_parse_protect_home(
3974 const char *filename
,
3976 const char *section
,
3977 unsigned section_line
,
3984 ExecContext
*c
= data
;
3992 /* Our enum shall be a superset of booleans, hence first try
3993 * to parse as boolean, and then as enum */
3995 k
= parse_boolean(rvalue
);
3997 c
->protect_home
= PROTECT_HOME_YES
;
3999 c
->protect_home
= PROTECT_HOME_NO
;
4003 h
= protect_home_from_string(rvalue
);
4005 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4009 c
->protect_home
= h
;
4015 int config_parse_protect_system(
4017 const char *filename
,
4019 const char *section
,
4020 unsigned section_line
,
4027 ExecContext
*c
= data
;
4035 /* Our enum shall be a superset of booleans, hence first try
4036 * to parse as boolean, and then as enum */
4038 k
= parse_boolean(rvalue
);
4040 c
->protect_system
= PROTECT_SYSTEM_YES
;
4042 c
->protect_system
= PROTECT_SYSTEM_NO
;
4046 s
= protect_system_from_string(rvalue
);
4048 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4052 c
->protect_system
= s
;
4058 #define FOLLOW_MAX 8
4060 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4071 /* This will update the filename pointer if the loaded file is
4072 * reached by a symlink. The old string will be freed. */
4075 char *target
, *name
;
4077 if (c
++ >= FOLLOW_MAX
)
4080 path_kill_slashes(*filename
);
4082 /* Add the file name we are currently looking at to
4083 * the names of this unit, but only if it is a valid
4085 name
= basename(*filename
);
4086 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4088 id
= set_get(names
, name
);
4094 r
= set_consume(names
, id
);
4100 /* Try to open the file name, but don't if its a symlink */
4101 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4108 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4109 r
= readlink_and_make_absolute(*filename
, &target
);
4117 f
= fdopen(fd
, "re");
4129 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4137 /* Let's try to add in all symlink names we found */
4138 while ((k
= set_steal_first(names
))) {
4140 /* First try to merge in the other name into our
4142 r
= unit_merge_by_name(*u
, k
);
4146 /* Hmm, we couldn't merge the other unit into
4147 * ours? Then let's try it the other way
4150 /* If the symlink name we are looking at is unit template, then
4151 we must search for instance of this template */
4152 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4153 _cleanup_free_
char *instance
= NULL
;
4155 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4159 other
= manager_get_unit((*u
)->manager
, instance
);
4161 other
= manager_get_unit((*u
)->manager
, k
);
4166 r
= unit_merge(other
, *u
);
4169 return merge_by_names(u
, names
, NULL
);
4177 unit_choose_id(*u
, id
);
4185 static int load_from_path(Unit
*u
, const char *path
) {
4186 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4187 _cleanup_fclose_
FILE *f
= NULL
;
4188 _cleanup_free_
char *filename
= NULL
;
4197 symlink_names
= set_new(&string_hash_ops
);
4201 if (path_is_absolute(path
)) {
4203 filename
= strdup(path
);
4207 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4209 filename
= mfree(filename
);
4217 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4219 /* Instead of opening the path right away, we manually
4220 * follow all symlinks and add their name to our unit
4221 * name set while doing so */
4222 filename
= path_make_absolute(path
, *p
);
4226 if (u
->manager
->unit_path_cache
&&
4227 !set_get(u
->manager
->unit_path_cache
, filename
))
4230 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4233 filename
= mfree(filename
);
4235 /* ENOENT means that the file is missing or is a dangling symlink.
4236 * ENOTDIR means that one of paths we expect to be is a directory
4237 * is not a directory, we should just ignore that.
4238 * EACCES means that the directory or file permissions are wrong.
4241 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4242 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4245 /* Empty the symlink names for the next run */
4246 set_clear_free(symlink_names
);
4251 /* Hmm, no suitable file found? */
4254 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4255 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4260 r
= merge_by_names(&merged
, symlink_names
, id
);
4265 u
->load_state
= UNIT_MERGED
;
4269 if (fstat(fileno(f
), &st
) < 0)
4272 if (null_or_empty(&st
)) {
4273 u
->load_state
= UNIT_MASKED
;
4274 u
->fragment_mtime
= 0;
4276 u
->load_state
= UNIT_LOADED
;
4277 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4279 /* Now, parse the file contents */
4280 r
= config_parse(u
->id
, filename
, f
,
4281 UNIT_VTABLE(u
)->sections
,
4282 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4283 false, true, false, u
);
4288 free(u
->fragment_path
);
4289 u
->fragment_path
= filename
;
4292 if (u
->source_path
) {
4293 if (stat(u
->source_path
, &st
) >= 0)
4294 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4296 u
->source_mtime
= 0;
4302 int unit_load_fragment(Unit
*u
) {
4308 assert(u
->load_state
== UNIT_STUB
);
4312 u
->load_state
= UNIT_LOADED
;
4316 /* First, try to find the unit under its id. We always look
4317 * for unit files in the default directories, to make it easy
4318 * to override things by placing things in /etc/systemd/system */
4319 r
= load_from_path(u
, u
->id
);
4323 /* Try to find an alias we can load this with */
4324 if (u
->load_state
== UNIT_STUB
) {
4325 SET_FOREACH(t
, u
->names
, i
) {
4330 r
= load_from_path(u
, t
);
4334 if (u
->load_state
!= UNIT_STUB
)
4339 /* And now, try looking for it under the suggested (originally linked) path */
4340 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4342 r
= load_from_path(u
, u
->fragment_path
);
4346 if (u
->load_state
== UNIT_STUB
)
4347 /* Hmm, this didn't work? Then let's get rid
4348 * of the fragment path stored for us, so that
4349 * we don't point to an invalid location. */
4350 u
->fragment_path
= mfree(u
->fragment_path
);
4353 /* Look for a template */
4354 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4355 _cleanup_free_
char *k
= NULL
;
4357 r
= unit_name_template(u
->id
, &k
);
4361 r
= load_from_path(u
, k
);
4364 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4368 if (u
->load_state
== UNIT_STUB
) {
4369 SET_FOREACH(t
, u
->names
, i
) {
4370 _cleanup_free_
char *z
= NULL
;
4375 r
= unit_name_template(t
, &z
);
4379 r
= load_from_path(u
, z
);
4383 if (u
->load_state
!= UNIT_STUB
)
4392 void unit_dump_config_items(FILE *f
) {
4393 static const struct {
4394 const ConfigParserCallback callback
;
4397 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4398 { config_parse_warn_compat
, "NOTSUPPORTED" },
4400 { config_parse_int
, "INTEGER" },
4401 { config_parse_unsigned
, "UNSIGNED" },
4402 { config_parse_iec_size
, "SIZE" },
4403 { config_parse_iec_uint64
, "SIZE" },
4404 { config_parse_si_size
, "SIZE" },
4405 { config_parse_bool
, "BOOLEAN" },
4406 { config_parse_string
, "STRING" },
4407 { config_parse_path
, "PATH" },
4408 { config_parse_unit_path_printf
, "PATH" },
4409 { config_parse_strv
, "STRING [...]" },
4410 { config_parse_exec_nice
, "NICE" },
4411 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4412 { config_parse_exec_io_class
, "IOCLASS" },
4413 { config_parse_exec_io_priority
, "IOPRIORITY" },
4414 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4415 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4416 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4417 { config_parse_mode
, "MODE" },
4418 { config_parse_unit_env_file
, "FILE" },
4419 { config_parse_exec_output
, "OUTPUT" },
4420 { config_parse_exec_input
, "INPUT" },
4421 { config_parse_log_facility
, "FACILITY" },
4422 { config_parse_log_level
, "LEVEL" },
4423 { config_parse_exec_secure_bits
, "SECUREBITS" },
4424 { config_parse_capability_set
, "BOUNDINGSET" },
4425 { config_parse_limit
, "LIMIT" },
4426 { config_parse_unit_deps
, "UNIT [...]" },
4427 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4428 { config_parse_service_type
, "SERVICETYPE" },
4429 { config_parse_service_restart
, "SERVICERESTART" },
4430 #ifdef HAVE_SYSV_COMPAT
4431 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4433 { config_parse_kill_mode
, "KILLMODE" },
4434 { config_parse_signal
, "SIGNAL" },
4435 { config_parse_socket_listen
, "SOCKET [...]" },
4436 { config_parse_socket_bind
, "SOCKETBIND" },
4437 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4438 { config_parse_sec
, "SECONDS" },
4439 { config_parse_nsec
, "NANOSECONDS" },
4440 { config_parse_namespace_path_strv
, "PATH [...]" },
4441 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4442 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4443 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4444 { config_parse_unit_string_printf
, "STRING" },
4445 { config_parse_trigger_unit
, "UNIT" },
4446 { config_parse_timer
, "TIMER" },
4447 { config_parse_path_spec
, "PATH" },
4448 { config_parse_notify_access
, "ACCESS" },
4449 { config_parse_ip_tos
, "TOS" },
4450 { config_parse_unit_condition_path
, "CONDITION" },
4451 { config_parse_unit_condition_string
, "CONDITION" },
4452 { config_parse_unit_condition_null
, "CONDITION" },
4453 { config_parse_unit_slice
, "SLICE" },
4454 { config_parse_documentation
, "URL" },
4455 { config_parse_service_timeout
, "SECONDS" },
4456 { config_parse_emergency_action
, "ACTION" },
4457 { config_parse_set_status
, "STATUS" },
4458 { config_parse_service_sockets
, "SOCKETS" },
4459 { config_parse_environ
, "ENVIRON" },
4461 { config_parse_syscall_filter
, "SYSCALLS" },
4462 { config_parse_syscall_archs
, "ARCHS" },
4463 { config_parse_syscall_errno
, "ERRNO" },
4464 { config_parse_address_families
, "FAMILIES" },
4465 { config_parse_restrict_namespaces
, "NAMESPACES" },
4467 { config_parse_cpu_shares
, "SHARES" },
4468 { config_parse_cpu_weight
, "WEIGHT" },
4469 { config_parse_memory_limit
, "LIMIT" },
4470 { config_parse_device_allow
, "DEVICE" },
4471 { config_parse_device_policy
, "POLICY" },
4472 { config_parse_io_limit
, "LIMIT" },
4473 { config_parse_io_weight
, "WEIGHT" },
4474 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4475 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4476 { config_parse_blockio_weight
, "WEIGHT" },
4477 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4478 { config_parse_long
, "LONG" },
4479 { config_parse_socket_service
, "SERVICE" },
4481 { config_parse_exec_selinux_context
, "LABEL" },
4483 { config_parse_job_mode
, "MODE" },
4484 { config_parse_job_mode_isolate
, "BOOLEAN" },
4485 { config_parse_personality
, "PERSONALITY" },
4488 const char *prev
= NULL
;
4493 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4494 const char *rvalue
= "OTHER", *lvalue
;
4498 const ConfigPerfItem
*p
;
4500 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4502 dot
= strchr(i
, '.');
4503 lvalue
= dot
? dot
+ 1 : i
;
4507 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4511 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4514 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4515 if (p
->parse
== table
[j
].callback
) {
4516 rvalue
= table
[j
].rvalue
;
4520 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);