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 "parse-util.h"
53 #include "path-util.h"
54 #include "process-util.h"
55 #include "rlimit-util.h"
57 #include "seccomp-util.h"
59 #include "securebits.h"
60 #include "signal-util.h"
61 #include "stat-util.h"
62 #include "string-util.h"
64 #include "unit-name.h"
65 #include "unit-printf.h"
67 #include "user-util.h"
71 int config_parse_warn_compat(
76 unsigned section_line
,
82 Disabled reason
= ltype
;
85 case DISABLED_CONFIGURATION
:
86 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
87 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
90 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
91 "Support for option %s= has been removed and it is ignored", lvalue
);
93 case DISABLED_EXPERIMENTAL
:
94 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
95 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
102 int config_parse_unit_deps(
104 const char *filename
,
107 unsigned section_line
,
114 UnitDependency d
= ltype
;
124 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
127 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
133 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
137 r
= unit_name_printf(u
, word
, &k
);
139 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
143 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
145 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
151 int config_parse_obsolete_unit_deps(
153 const char *filename
,
156 unsigned section_line
,
163 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
164 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
166 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
169 int config_parse_unit_string_printf(
171 const char *filename
,
174 unsigned section_line
,
181 _cleanup_free_
char *k
= NULL
;
190 r
= unit_full_printf(u
, rvalue
, &k
);
192 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
196 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
199 int config_parse_unit_strv_printf(
201 const char *filename
,
204 unsigned section_line
,
212 _cleanup_free_
char *k
= NULL
;
220 r
= unit_full_printf(u
, rvalue
, &k
);
222 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
226 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
229 int config_parse_unit_path_printf(
231 const char *filename
,
234 unsigned section_line
,
241 _cleanup_free_
char *k
= NULL
;
250 r
= unit_full_printf(u
, rvalue
, &k
);
252 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
256 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
259 int config_parse_unit_path_strv_printf(
261 const char *filename
,
264 unsigned section_line
,
282 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
284 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
290 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
291 "Invalid syntax, ignoring: %s", rvalue
);
295 r
= unit_full_printf(u
, word
, &k
);
297 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
298 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
302 if (!utf8_is_valid(k
)) {
303 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
307 if (!path_is_absolute(k
)) {
308 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
309 "Symlink path is not absolute: %s", k
);
313 path_kill_slashes(k
);
322 int config_parse_socket_listen(const char *unit
,
323 const char *filename
,
326 unsigned section_line
,
333 _cleanup_free_ SocketPort
*p
= NULL
;
345 if (isempty(rvalue
)) {
346 /* An empty assignment removes all ports */
347 socket_free_ports(s
);
351 p
= new0(SocketPort
, 1);
355 if (ltype
!= SOCKET_SOCKET
) {
358 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
360 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
364 path_kill_slashes(p
->path
);
366 } else if (streq(lvalue
, "ListenNetlink")) {
367 _cleanup_free_
char *k
= NULL
;
369 p
->type
= SOCKET_SOCKET
;
370 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
372 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
376 r
= socket_address_parse_netlink(&p
->address
, k
);
378 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
383 _cleanup_free_
char *k
= NULL
;
385 p
->type
= SOCKET_SOCKET
;
386 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
388 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
392 r
= socket_address_parse_and_warn(&p
->address
, k
);
394 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
398 if (streq(lvalue
, "ListenStream"))
399 p
->address
.type
= SOCK_STREAM
;
400 else if (streq(lvalue
, "ListenDatagram"))
401 p
->address
.type
= SOCK_DGRAM
;
403 assert(streq(lvalue
, "ListenSequentialPacket"));
404 p
->address
.type
= SOCK_SEQPACKET
;
407 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
408 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
414 p
->auxiliary_fds
= NULL
;
415 p
->n_auxiliary_fds
= 0;
419 LIST_FIND_TAIL(port
, s
->ports
, tail
);
420 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
422 LIST_PREPEND(port
, s
->ports
, p
);
428 int config_parse_socket_protocol(const char *unit
,
429 const char *filename
,
432 unsigned section_line
,
447 if (streq(rvalue
, "udplite"))
448 s
->socket_protocol
= IPPROTO_UDPLITE
;
449 else if (streq(rvalue
, "sctp"))
450 s
->socket_protocol
= IPPROTO_SCTP
;
452 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
459 int config_parse_socket_bind(const char *unit
,
460 const char *filename
,
463 unsigned section_line
,
471 SocketAddressBindIPv6Only b
;
480 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
484 r
= parse_boolean(rvalue
);
486 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
490 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
492 s
->bind_ipv6_only
= b
;
497 int config_parse_exec_nice(
499 const char *filename
,
502 unsigned section_line
,
509 ExecContext
*c
= data
;
517 r
= parse_nice(rvalue
, &priority
);
520 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
522 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
533 int config_parse_exec_oom_score_adjust(const char* unit
,
534 const char *filename
,
537 unsigned section_line
,
544 ExecContext
*c
= data
;
552 r
= safe_atoi(rvalue
, &oa
);
554 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
558 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
559 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
563 c
->oom_score_adjust
= oa
;
564 c
->oom_score_adjust_set
= true;
569 int config_parse_exec(
571 const char *filename
,
574 unsigned section_line
,
581 ExecCommand
**e
= data
;
593 rvalue
+= strspn(rvalue
, WHITESPACE
);
595 if (isempty(rvalue
)) {
596 /* An empty assignment resets the list */
597 *e
= exec_command_free_list(*e
);
603 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
604 bool separate_argv0
= false, ignore
= false, privileged
= false;
605 _cleanup_free_ ExecCommand
*nce
= NULL
;
606 _cleanup_strv_free_
char **n
= NULL
;
607 size_t nlen
= 0, nbufsize
= 0;
613 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
618 for (i
= 0; i
< 3; i
++) {
619 /* We accept an absolute path as first argument.
620 * If it's prefixed with - and the path doesn't exist,
621 * we ignore it instead of erroring out;
622 * if it's prefixed with @, we allow overriding of argv[0];
623 * and if it's prefixed with !, it will be run with full privileges */
624 if (*f
== '-' && !ignore
)
626 else if (*f
== '@' && !separate_argv0
)
627 separate_argv0
= true;
628 else if (*f
== '+' && !privileged
)
635 r
= unit_full_printf(u
, f
, &path
);
637 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", f
);
642 /* First word is either "-" or "@" with no command. */
643 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty path in command line, ignoring: \"%s\"", rvalue
);
646 if (!string_is_safe(path
)) {
647 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path contains special characters, ignoring: %s", rvalue
);
650 if (!path_is_absolute(path
)) {
651 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path is not absolute, ignoring: %s", rvalue
);
654 if (endswith(path
, "/")) {
655 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path specifies a directory, ignoring: %s", rvalue
);
659 if (!separate_argv0
) {
662 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
672 path_kill_slashes(path
);
674 while (!isempty(p
)) {
675 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
677 /* Check explicitly for an unquoted semicolon as
678 * command separator token. */
679 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
681 p
+= strspn(p
, WHITESPACE
);
686 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
687 * extract_first_word() would return the same for all of those. */
688 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
692 p
+= strspn(p
, WHITESPACE
);
694 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
705 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
711 r
= unit_full_printf(u
, word
, &resolved
);
713 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to resolve unit specifiers on %s, ignoring: %m", word
);
717 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
719 n
[nlen
++] = resolved
;
725 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue
);
729 nce
= new0(ExecCommand
, 1);
735 nce
->ignore
= ignore
;
736 nce
->privileged
= privileged
;
738 exec_command_append_list(e
, nce
);
740 /* Do not _cleanup_free_ these. */
751 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
752 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
754 int config_parse_socket_bindtodevice(
756 const char *filename
,
759 unsigned section_line
,
774 if (rvalue
[0] && !streq(rvalue
, "*")) {
775 if (!ifname_valid(rvalue
)) {
776 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
786 free(s
->bind_to_device
);
787 s
->bind_to_device
= n
;
792 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
793 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
795 int config_parse_exec_input(const char *unit
,
796 const char *filename
,
799 unsigned section_line
,
805 ExecContext
*c
= data
;
814 name
= startswith(rvalue
, "fd:");
816 /* Strip prefix and validate fd name */
817 if (!fdname_is_valid(name
)) {
818 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
821 c
->std_input
= EXEC_INPUT_NAMED_FD
;
822 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
827 ExecInput ei
= exec_input_from_string(rvalue
);
828 if (ei
== _EXEC_INPUT_INVALID
)
829 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
836 int config_parse_exec_output(const char *unit
,
837 const char *filename
,
840 unsigned section_line
,
846 ExecContext
*c
= data
;
857 name
= startswith(rvalue
, "fd:");
859 /* Strip prefix and validate fd name */
860 if (!fdname_is_valid(name
)) {
861 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
864 eo
= EXEC_OUTPUT_NAMED_FD
;
866 eo
= exec_output_from_string(rvalue
);
867 if (eo
== _EXEC_OUTPUT_INVALID
) {
868 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
873 if (streq(lvalue
, "StandardOutput")) {
875 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
879 } else if (streq(lvalue
, "StandardError")) {
881 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
886 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
891 int config_parse_exec_io_class(const char *unit
,
892 const char *filename
,
895 unsigned section_line
,
902 ExecContext
*c
= data
;
910 x
= ioprio_class_from_string(rvalue
);
912 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
916 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
917 c
->ioprio_set
= true;
922 int config_parse_exec_io_priority(const char *unit
,
923 const char *filename
,
926 unsigned section_line
,
933 ExecContext
*c
= data
;
941 r
= safe_atoi(rvalue
, &i
);
942 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
943 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
947 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
948 c
->ioprio_set
= true;
953 int config_parse_exec_cpu_sched_policy(const char *unit
,
954 const char *filename
,
957 unsigned section_line
,
965 ExecContext
*c
= data
;
973 x
= sched_policy_from_string(rvalue
);
975 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
979 c
->cpu_sched_policy
= x
;
980 /* Moving to or from real-time policy? We need to adjust the priority */
981 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
982 c
->cpu_sched_set
= true;
987 int config_parse_exec_cpu_sched_prio(const char *unit
,
988 const char *filename
,
991 unsigned section_line
,
998 ExecContext
*c
= data
;
1006 r
= safe_atoi(rvalue
, &i
);
1008 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1012 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1013 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1014 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1016 if (i
< min
|| i
> max
) {
1017 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1021 c
->cpu_sched_priority
= i
;
1022 c
->cpu_sched_set
= true;
1027 int config_parse_exec_cpu_affinity(const char *unit
,
1028 const char *filename
,
1030 const char *section
,
1031 unsigned section_line
,
1038 ExecContext
*c
= data
;
1039 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1047 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1052 CPU_FREE(c
->cpuset
);
1055 /* An empty assignment resets the CPU list */
1061 c
->cpuset_ncpus
= ncpus
;
1066 int config_parse_exec_secure_bits(const char *unit
,
1067 const char *filename
,
1069 const char *section
,
1070 unsigned section_line
,
1077 ExecContext
*c
= data
;
1086 if (isempty(rvalue
)) {
1087 /* An empty assignment resets the field */
1092 for (p
= rvalue
;;) {
1093 _cleanup_free_
char *word
= NULL
;
1095 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1101 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1102 "Invalid syntax, ignoring: %s", rvalue
);
1106 if (streq(word
, "keep-caps"))
1107 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
1108 else if (streq(word
, "keep-caps-locked"))
1109 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
1110 else if (streq(word
, "no-setuid-fixup"))
1111 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
1112 else if (streq(word
, "no-setuid-fixup-locked"))
1113 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
1114 else if (streq(word
, "noroot"))
1115 c
->secure_bits
|= 1<<SECURE_NOROOT
;
1116 else if (streq(word
, "noroot-locked"))
1117 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
1119 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
1120 "Failed to parse secure bit \"%s\", ignoring.", word
);
1126 int config_parse_capability_set(
1128 const char *filename
,
1130 const char *section
,
1131 unsigned section_line
,
1138 uint64_t *capability_set
= data
;
1139 uint64_t sum
= 0, initial
= 0;
1140 bool invert
= false;
1148 if (rvalue
[0] == '~') {
1153 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1154 initial
= CAP_ALL
; /* initialized to all bits on */
1155 /* else "AmbientCapabilities" initialized to all bits off */
1159 _cleanup_free_
char *word
= NULL
;
1162 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1168 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1172 cap
= capability_from_name(word
);
1174 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1178 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1181 sum
= invert
? ~sum
: sum
;
1183 if (sum
== 0 || *capability_set
== initial
)
1184 /* "" or uninitialized data -> replace */
1185 *capability_set
= sum
;
1187 /* previous data -> merge */
1188 *capability_set
|= sum
;
1193 int config_parse_limit(
1195 const char *filename
,
1197 const char *section
,
1198 unsigned section_line
,
1205 struct rlimit
**rl
= data
, d
= {};
1213 r
= rlimit_parse(ltype
, rvalue
, &d
);
1215 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1219 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1226 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1234 #ifdef HAVE_SYSV_COMPAT
1235 int config_parse_sysv_priority(const char *unit
,
1236 const char *filename
,
1238 const char *section
,
1239 unsigned section_line
,
1246 int *priority
= data
;
1254 r
= safe_atoi(rvalue
, &i
);
1255 if (r
< 0 || i
< 0) {
1256 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1260 *priority
= (int) i
;
1265 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1266 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1268 int config_parse_exec_mount_flags(const char *unit
,
1269 const char *filename
,
1271 const char *section
,
1272 unsigned section_line
,
1280 unsigned long flags
= 0;
1281 ExecContext
*c
= data
;
1288 if (streq(rvalue
, "shared"))
1290 else if (streq(rvalue
, "slave"))
1292 else if (streq(rvalue
, "private"))
1295 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1299 c
->mount_flags
= flags
;
1304 int config_parse_exec_selinux_context(
1306 const char *filename
,
1308 const char *section
,
1309 unsigned section_line
,
1316 ExecContext
*c
= data
;
1327 if (isempty(rvalue
)) {
1328 c
->selinux_context
= mfree(c
->selinux_context
);
1329 c
->selinux_context_ignore
= false;
1333 if (rvalue
[0] == '-') {
1339 r
= unit_full_printf(u
, rvalue
, &k
);
1341 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1345 free(c
->selinux_context
);
1346 c
->selinux_context
= k
;
1347 c
->selinux_context_ignore
= ignore
;
1352 int config_parse_exec_apparmor_profile(
1354 const char *filename
,
1356 const char *section
,
1357 unsigned section_line
,
1364 ExecContext
*c
= data
;
1375 if (isempty(rvalue
)) {
1376 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1377 c
->apparmor_profile_ignore
= false;
1381 if (rvalue
[0] == '-') {
1387 r
= unit_full_printf(u
, rvalue
, &k
);
1389 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1393 free(c
->apparmor_profile
);
1394 c
->apparmor_profile
= k
;
1395 c
->apparmor_profile_ignore
= ignore
;
1400 int config_parse_exec_smack_process_label(
1402 const char *filename
,
1404 const char *section
,
1405 unsigned section_line
,
1412 ExecContext
*c
= data
;
1423 if (isempty(rvalue
)) {
1424 c
->smack_process_label
= mfree(c
->smack_process_label
);
1425 c
->smack_process_label_ignore
= false;
1429 if (rvalue
[0] == '-') {
1435 r
= unit_full_printf(u
, rvalue
, &k
);
1437 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1441 free(c
->smack_process_label
);
1442 c
->smack_process_label
= k
;
1443 c
->smack_process_label_ignore
= ignore
;
1448 int config_parse_timer(const char *unit
,
1449 const char *filename
,
1451 const char *section
,
1452 unsigned section_line
,
1463 CalendarSpec
*c
= NULL
;
1465 _cleanup_free_
char *k
= NULL
;
1473 if (isempty(rvalue
)) {
1474 /* Empty assignment resets list */
1475 timer_free_values(t
);
1479 b
= timer_base_from_string(lvalue
);
1481 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1485 r
= unit_full_printf(u
, rvalue
, &k
);
1487 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1491 if (b
== TIMER_CALENDAR
) {
1492 if (calendar_spec_from_string(k
, &c
) < 0) {
1493 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1497 if (parse_sec(k
, &usec
) < 0) {
1498 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1503 v
= new0(TimerValue
, 1);
1505 calendar_spec_free(c
);
1511 v
->calendar_spec
= c
;
1513 LIST_PREPEND(value
, t
->values
, v
);
1518 int config_parse_trigger_unit(
1520 const char *filename
,
1522 const char *section
,
1523 unsigned section_line
,
1530 _cleanup_free_
char *p
= NULL
;
1540 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1541 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1545 r
= unit_name_printf(u
, rvalue
, &p
);
1547 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1551 type
= unit_name_to_type(p
);
1553 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1557 if (type
== u
->type
) {
1558 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1562 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1564 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1571 int config_parse_path_spec(const char *unit
,
1572 const char *filename
,
1574 const char *section
,
1575 unsigned section_line
,
1585 _cleanup_free_
char *k
= NULL
;
1593 if (isempty(rvalue
)) {
1594 /* Empty assignment clears list */
1599 b
= path_type_from_string(lvalue
);
1601 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1605 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1607 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1611 if (!path_is_absolute(k
)) {
1612 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1616 s
= new0(PathSpec
, 1);
1621 s
->path
= path_kill_slashes(k
);
1626 LIST_PREPEND(spec
, p
->specs
, s
);
1631 int config_parse_socket_service(
1633 const char *filename
,
1635 const char *section
,
1636 unsigned section_line
,
1643 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1644 _cleanup_free_
char *p
= NULL
;
1654 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1656 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1660 if (!endswith(p
, ".service")) {
1661 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1665 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1667 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1671 unit_ref_set(&s
->service
, x
);
1676 int config_parse_fdname(
1678 const char *filename
,
1680 const char *section
,
1681 unsigned section_line
,
1688 _cleanup_free_
char *p
= NULL
;
1697 if (isempty(rvalue
)) {
1698 s
->fdname
= mfree(s
->fdname
);
1702 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1704 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1708 if (!fdname_is_valid(p
)) {
1709 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1713 return free_and_replace(s
->fdname
, p
);
1716 int config_parse_service_sockets(
1718 const char *filename
,
1720 const char *section
,
1721 unsigned section_line
,
1739 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1741 r
= extract_first_word(&p
, &word
, NULL
, 0);
1747 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1751 r
= unit_name_printf(UNIT(s
), word
, &k
);
1753 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1757 if (!endswith(k
, ".socket")) {
1758 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1762 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1764 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1766 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1768 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1774 int config_parse_bus_name(
1776 const char *filename
,
1778 const char *section
,
1779 unsigned section_line
,
1786 _cleanup_free_
char *k
= NULL
;
1795 r
= unit_full_printf(u
, rvalue
, &k
);
1797 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1801 if (!service_name_is_valid(k
)) {
1802 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1806 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1809 int config_parse_service_timeout(
1811 const char *filename
,
1813 const char *section
,
1814 unsigned section_line
,
1821 Service
*s
= userdata
;
1830 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1832 r
= parse_sec(rvalue
, &usec
);
1834 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1838 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1839 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1840 * all other timeouts. */
1842 usec
= USEC_INFINITY
;
1844 if (!streq(lvalue
, "TimeoutStopSec")) {
1845 s
->start_timeout_defined
= true;
1846 s
->timeout_start_usec
= usec
;
1849 if (!streq(lvalue
, "TimeoutStartSec"))
1850 s
->timeout_stop_usec
= usec
;
1855 int config_parse_sec_fix_0(
1857 const char *filename
,
1859 const char *section
,
1860 unsigned section_line
,
1867 usec_t
*usec
= data
;
1875 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1876 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1879 r
= parse_sec(rvalue
, usec
);
1881 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1886 *usec
= USEC_INFINITY
;
1891 int config_parse_user_group(
1893 const char *filename
,
1895 const char *section
,
1896 unsigned section_line
,
1903 char **user
= data
, *n
;
1912 if (isempty(rvalue
))
1915 _cleanup_free_
char *k
= NULL
;
1917 r
= unit_full_printf(u
, rvalue
, &k
);
1919 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1923 if (!valid_user_group_name_or_id(k
)) {
1924 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1938 int config_parse_user_group_strv(
1940 const char *filename
,
1942 const char *section
,
1943 unsigned section_line
,
1950 char ***users
= data
;
1960 if (isempty(rvalue
)) {
1963 empty
= new0(char*, 1);
1975 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1977 r
= extract_first_word(&p
, &word
, NULL
, 0);
1983 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1987 r
= unit_full_printf(u
, word
, &k
);
1989 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", word
);
1993 if (!valid_user_group_name_or_id(k
)) {
1994 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1998 r
= strv_push(users
, k
);
2008 int config_parse_busname_service(
2010 const char *filename
,
2012 const char *section
,
2013 unsigned section_line
,
2020 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2024 _cleanup_free_
char *p
= NULL
;
2031 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
2033 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2037 if (!endswith(p
, ".service")) {
2038 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
2042 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
2044 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
2048 unit_ref_set(&n
->service
, x
);
2053 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
2055 int config_parse_bus_policy(
2057 const char *filename
,
2059 const char *section
,
2060 unsigned section_line
,
2067 _cleanup_free_ BusNamePolicy
*p
= NULL
;
2068 _cleanup_free_
char *id_str
= NULL
;
2069 BusName
*busname
= data
;
2077 p
= new0(BusNamePolicy
, 1);
2081 if (streq(lvalue
, "AllowUser"))
2082 p
->type
= BUSNAME_POLICY_TYPE_USER
;
2083 else if (streq(lvalue
, "AllowGroup"))
2084 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
2086 assert_not_reached("Unknown lvalue");
2088 id_str
= strdup(rvalue
);
2092 access_str
= strpbrk(id_str
, WHITESPACE
);
2094 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
2100 access_str
+= strspn(access_str
, WHITESPACE
);
2102 p
->access
= bus_policy_access_from_string(access_str
);
2103 if (p
->access
< 0) {
2104 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
2111 LIST_PREPEND(policy
, busname
->policy
, p
);
2117 int config_parse_working_directory(
2119 const char *filename
,
2121 const char *section
,
2122 unsigned section_line
,
2129 ExecContext
*c
= data
;
2140 if (rvalue
[0] == '-') {
2146 if (streq(rvalue
, "~")) {
2147 c
->working_directory_home
= true;
2148 c
->working_directory
= mfree(c
->working_directory
);
2150 _cleanup_free_
char *k
= NULL
;
2152 r
= unit_full_printf(u
, rvalue
, &k
);
2154 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2158 path_kill_slashes(k
);
2160 if (!utf8_is_valid(k
)) {
2161 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2165 if (!path_is_absolute(k
)) {
2166 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2170 free_and_replace(c
->working_directory
, k
);
2172 c
->working_directory_home
= false;
2175 c
->working_directory_missing_ok
= missing_ok
;
2179 int config_parse_unit_env_file(const char *unit
,
2180 const char *filename
,
2182 const char *section
,
2183 unsigned section_line
,
2192 _cleanup_free_
char *n
= NULL
;
2200 if (isempty(rvalue
)) {
2201 /* Empty assignment frees the list */
2202 *env
= strv_free(*env
);
2206 r
= unit_full_printf(u
, rvalue
, &n
);
2208 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2212 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2213 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2217 r
= strv_extend(env
, n
);
2224 int config_parse_environ(const char *unit
,
2225 const char *filename
,
2227 const char *section
,
2228 unsigned section_line
,
2245 if (isempty(rvalue
)) {
2246 /* Empty assignment resets the list */
2247 *env
= strv_free(*env
);
2251 for (p
= rvalue
;; ) {
2252 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2254 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2260 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2261 "Invalid syntax, ignoring: %s", rvalue
);
2266 r
= unit_full_printf(u
, word
, &k
);
2268 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2269 "Failed to resolve specifiers, ignoring: %s", k
);
2277 if (!env_assignment_is_valid(k
)) {
2278 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2279 "Invalid environment assignment, ignoring: %s", k
);
2283 r
= strv_env_replace(env
, k
);
2290 int config_parse_pass_environ(const char *unit
,
2291 const char *filename
,
2293 const char *section
,
2294 unsigned section_line
,
2301 const char *whole_rvalue
= rvalue
;
2302 char*** passenv
= data
;
2303 _cleanup_strv_free_
char **n
= NULL
;
2304 size_t nlen
= 0, nbufsize
= 0;
2312 if (isempty(rvalue
)) {
2313 /* Empty assignment resets the list */
2314 *passenv
= strv_free(*passenv
);
2319 _cleanup_free_
char *word
= NULL
;
2321 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2327 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2328 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2332 if (!env_name_is_valid(word
)) {
2333 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2334 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2338 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2346 r
= strv_extend_strv(passenv
, n
, true);
2354 int config_parse_ip_tos(const char *unit
,
2355 const char *filename
,
2357 const char *section
,
2358 unsigned section_line
,
2365 int *ip_tos
= data
, x
;
2372 x
= ip_tos_from_string(rvalue
);
2374 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2382 int config_parse_unit_condition_path(
2384 const char *filename
,
2386 const char *section
,
2387 unsigned section_line
,
2394 _cleanup_free_
char *p
= NULL
;
2395 Condition
**list
= data
, *c
;
2396 ConditionType t
= ltype
;
2397 bool trigger
, negate
;
2406 if (isempty(rvalue
)) {
2407 /* Empty assignment resets the list */
2408 *list
= condition_free_list(*list
);
2412 trigger
= rvalue
[0] == '|';
2416 negate
= rvalue
[0] == '!';
2420 r
= unit_full_printf(u
, rvalue
, &p
);
2422 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2426 if (!path_is_absolute(p
)) {
2427 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2431 c
= condition_new(t
, p
, trigger
, negate
);
2435 LIST_PREPEND(conditions
, *list
, c
);
2439 int config_parse_unit_condition_string(
2441 const char *filename
,
2443 const char *section
,
2444 unsigned section_line
,
2451 _cleanup_free_
char *s
= NULL
;
2452 Condition
**list
= data
, *c
;
2453 ConditionType t
= ltype
;
2454 bool trigger
, negate
;
2463 if (isempty(rvalue
)) {
2464 /* Empty assignment resets the list */
2465 *list
= condition_free_list(*list
);
2469 trigger
= rvalue
[0] == '|';
2473 negate
= rvalue
[0] == '!';
2477 r
= unit_full_printf(u
, rvalue
, &s
);
2479 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2483 c
= condition_new(t
, s
, trigger
, negate
);
2487 LIST_PREPEND(conditions
, *list
, c
);
2491 int config_parse_unit_condition_null(
2493 const char *filename
,
2495 const char *section
,
2496 unsigned section_line
,
2503 Condition
**list
= data
, *c
;
2504 bool trigger
, negate
;
2512 if (isempty(rvalue
)) {
2513 /* Empty assignment resets the list */
2514 *list
= condition_free_list(*list
);
2518 trigger
= rvalue
[0] == '|';
2522 negate
= rvalue
[0] == '!';
2526 b
= parse_boolean(rvalue
);
2528 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2535 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2539 LIST_PREPEND(conditions
, *list
, c
);
2543 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2544 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2546 int config_parse_unit_requires_mounts_for(
2548 const char *filename
,
2550 const char *section
,
2551 unsigned section_line
,
2567 for (p
= rvalue
;; ) {
2568 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2570 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2576 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2577 "Invalid syntax, ignoring: %s", rvalue
);
2581 if (!utf8_is_valid(word
)) {
2582 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2586 r
= unit_full_printf(u
, word
, &resolved
);
2588 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2592 r
= unit_require_mounts_for(u
, resolved
);
2594 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2600 int config_parse_documentation(const char *unit
,
2601 const char *filename
,
2603 const char *section
,
2604 unsigned section_line
,
2620 if (isempty(rvalue
)) {
2621 /* Empty assignment resets the list */
2622 u
->documentation
= strv_free(u
->documentation
);
2626 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2627 rvalue
, data
, userdata
);
2631 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2633 if (documentation_url_is_valid(*a
))
2636 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2648 static int syscall_filter_parse_one(
2650 const char *filename
,
2659 const SyscallFilterSet
*set
;
2662 set
= syscall_filter_set_find(t
);
2665 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2669 NULSTR_FOREACH(i
, set
->value
) {
2670 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2677 id
= seccomp_syscall_resolve_name(t
);
2678 if (id
== __NR_SCMP_ERROR
) {
2680 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2684 /* If we previously wanted to forbid a syscall and now
2685 * we want to allow it, then remove it from the list
2687 if (!invert
== c
->syscall_whitelist
) {
2688 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2694 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2700 int config_parse_syscall_filter(
2702 const char *filename
,
2704 const char *section
,
2705 unsigned section_line
,
2712 ExecContext
*c
= data
;
2714 bool invert
= false;
2723 if (isempty(rvalue
)) {
2724 /* Empty assignment resets the list */
2725 c
->syscall_filter
= set_free(c
->syscall_filter
);
2726 c
->syscall_whitelist
= false;
2730 if (rvalue
[0] == '~') {
2735 if (!c
->syscall_filter
) {
2736 c
->syscall_filter
= set_new(NULL
);
2737 if (!c
->syscall_filter
)
2741 /* Allow everything but the ones listed */
2742 c
->syscall_whitelist
= false;
2744 /* Allow nothing but the ones listed */
2745 c
->syscall_whitelist
= true;
2747 /* Accept default syscalls if we are on a whitelist */
2748 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2756 _cleanup_free_
char *word
= NULL
;
2758 r
= extract_first_word(&p
, &word
, NULL
, 0);
2764 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2768 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2776 int config_parse_syscall_archs(
2778 const char *filename
,
2780 const char *section
,
2781 unsigned section_line
,
2792 if (isempty(rvalue
)) {
2793 *archs
= set_free(*archs
);
2797 r
= set_ensure_allocated(archs
, NULL
);
2801 for (p
= rvalue
;;) {
2802 _cleanup_free_
char *word
= NULL
;
2805 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2811 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2812 "Invalid syntax, ignoring: %s", rvalue
);
2816 r
= seccomp_arch_from_string(word
, &a
);
2818 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2819 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2823 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2829 int config_parse_syscall_errno(
2831 const char *filename
,
2833 const char *section
,
2834 unsigned section_line
,
2841 ExecContext
*c
= data
;
2848 if (isempty(rvalue
)) {
2849 /* Empty assignment resets to KILL */
2850 c
->syscall_errno
= 0;
2854 e
= errno_from_name(rvalue
);
2856 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2860 c
->syscall_errno
= e
;
2864 int config_parse_address_families(
2866 const char *filename
,
2868 const char *section
,
2869 unsigned section_line
,
2876 ExecContext
*c
= data
;
2877 bool invert
= false;
2885 if (isempty(rvalue
)) {
2886 /* Empty assignment resets the list */
2887 c
->address_families
= set_free(c
->address_families
);
2888 c
->address_families_whitelist
= false;
2892 if (rvalue
[0] == '~') {
2897 if (!c
->address_families
) {
2898 c
->address_families
= set_new(NULL
);
2899 if (!c
->address_families
)
2902 c
->address_families_whitelist
= !invert
;
2905 for (p
= rvalue
;;) {
2906 _cleanup_free_
char *word
= NULL
;
2909 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2915 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2916 "Invalid syntax, ignoring: %s", rvalue
);
2920 af
= af_from_name(word
);
2922 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2923 "Failed to parse address family \"%s\", ignoring: %m", word
);
2927 /* If we previously wanted to forbid an address family and now
2928 * we want to allow it, then just remove it from the list.
2930 if (!invert
== c
->address_families_whitelist
) {
2931 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2935 set_remove(c
->address_families
, INT_TO_PTR(af
));
2939 int config_parse_restrict_namespaces(
2941 const char *filename
,
2943 const char *section
,
2944 unsigned section_line
,
2951 ExecContext
*c
= data
;
2952 bool invert
= false;
2955 if (isempty(rvalue
)) {
2956 /* Reset to the default. */
2957 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2961 if (rvalue
[0] == '~') {
2966 r
= parse_boolean(rvalue
);
2968 c
->restrict_namespaces
= 0;
2970 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
2972 /* Not a boolean argument, in this case it's a list of namespace types. */
2974 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
2976 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
2982 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
2988 int config_parse_unit_slice(
2990 const char *filename
,
2992 const char *section
,
2993 unsigned section_line
,
3000 _cleanup_free_
char *k
= NULL
;
3001 Unit
*u
= userdata
, *slice
= NULL
;
3009 r
= unit_name_printf(u
, rvalue
, &k
);
3011 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3015 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3017 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3021 r
= unit_set_slice(u
, slice
);
3023 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3030 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3032 int config_parse_cpu_weight(
3034 const char *filename
,
3036 const char *section
,
3037 unsigned section_line
,
3044 uint64_t *weight
= data
;
3051 r
= cg_weight_parse(rvalue
, weight
);
3053 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3060 int config_parse_cpu_shares(
3062 const char *filename
,
3064 const char *section
,
3065 unsigned section_line
,
3072 uint64_t *shares
= data
;
3079 r
= cg_cpu_shares_parse(rvalue
, shares
);
3081 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3088 int config_parse_cpu_quota(
3090 const char *filename
,
3092 const char *section
,
3093 unsigned section_line
,
3100 CGroupContext
*c
= data
;
3107 if (isempty(rvalue
)) {
3108 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3112 r
= parse_percent_unbounded(rvalue
);
3114 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3118 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3122 int config_parse_memory_limit(
3124 const char *filename
,
3126 const char *section
,
3127 unsigned section_line
,
3134 CGroupContext
*c
= data
;
3135 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3138 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3140 r
= parse_percent(rvalue
);
3142 r
= parse_size(rvalue
, 1024, &bytes
);
3144 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3148 bytes
= physical_memory_scale(r
, 100U);
3150 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3151 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3156 if (streq(lvalue
, "MemoryLow"))
3157 c
->memory_low
= bytes
;
3158 else if (streq(lvalue
, "MemoryHigh"))
3159 c
->memory_high
= bytes
;
3160 else if (streq(lvalue
, "MemoryMax"))
3161 c
->memory_max
= bytes
;
3162 else if (streq(lvalue
, "MemorySwapMax"))
3163 c
->memory_swap_max
= bytes
;
3164 else if (streq(lvalue
, "MemoryLimit"))
3165 c
->memory_limit
= bytes
;
3172 int config_parse_tasks_max(
3174 const char *filename
,
3176 const char *section
,
3177 unsigned section_line
,
3184 uint64_t *tasks_max
= data
, v
;
3188 if (isempty(rvalue
)) {
3189 *tasks_max
= u
->manager
->default_tasks_max
;
3193 if (streq(rvalue
, "infinity")) {
3194 *tasks_max
= CGROUP_LIMIT_MAX
;
3198 r
= parse_percent(rvalue
);
3200 r
= safe_atou64(rvalue
, &v
);
3202 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3206 v
= system_tasks_max_scale(r
, 100U);
3208 if (v
<= 0 || v
>= UINT64_MAX
) {
3209 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3217 int config_parse_device_allow(
3219 const char *filename
,
3221 const char *section
,
3222 unsigned section_line
,
3229 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3230 CGroupContext
*c
= data
;
3231 CGroupDeviceAllow
*a
;
3232 const char *m
= NULL
;
3236 if (isempty(rvalue
)) {
3237 while (c
->device_allow
)
3238 cgroup_context_free_device_allow(c
, c
->device_allow
);
3243 r
= unit_full_printf(userdata
, rvalue
, &t
);
3245 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3246 "Failed to resolve specifiers in %s, ignoring: %m",
3250 n
= strcspn(t
, WHITESPACE
);
3252 path
= strndup(t
, n
);
3256 if (!is_deviceallow_pattern(path
)) {
3257 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3261 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3265 if (!in_charset(m
, "rwm")) {
3266 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3270 a
= new0(CGroupDeviceAllow
, 1);
3276 a
->r
= !!strchr(m
, 'r');
3277 a
->w
= !!strchr(m
, 'w');
3278 a
->m
= !!strchr(m
, 'm');
3280 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3284 int config_parse_io_weight(
3286 const char *filename
,
3288 const char *section
,
3289 unsigned section_line
,
3296 uint64_t *weight
= data
;
3303 r
= cg_weight_parse(rvalue
, weight
);
3305 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3312 int config_parse_io_device_weight(
3314 const char *filename
,
3316 const char *section
,
3317 unsigned section_line
,
3324 _cleanup_free_
char *path
= NULL
;
3325 CGroupIODeviceWeight
*w
;
3326 CGroupContext
*c
= data
;
3336 if (isempty(rvalue
)) {
3337 while (c
->io_device_weights
)
3338 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3343 n
= strcspn(rvalue
, WHITESPACE
);
3344 weight
= rvalue
+ n
;
3345 weight
+= strspn(weight
, WHITESPACE
);
3347 if (isempty(weight
)) {
3348 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3352 path
= strndup(rvalue
, n
);
3356 if (!path_startswith(path
, "/dev")) {
3357 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3361 r
= cg_weight_parse(weight
, &u
);
3363 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3367 assert(u
!= CGROUP_WEIGHT_INVALID
);
3369 w
= new0(CGroupIODeviceWeight
, 1);
3378 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3382 int config_parse_io_limit(
3384 const char *filename
,
3386 const char *section
,
3387 unsigned section_line
,
3394 _cleanup_free_
char *path
= NULL
;
3395 CGroupIODeviceLimit
*l
= NULL
, *t
;
3396 CGroupContext
*c
= data
;
3397 CGroupIOLimitType type
;
3407 type
= cgroup_io_limit_type_from_string(lvalue
);
3410 if (isempty(rvalue
)) {
3411 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3412 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3416 n
= strcspn(rvalue
, WHITESPACE
);
3418 limit
+= strspn(limit
, WHITESPACE
);
3421 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3425 path
= strndup(rvalue
, n
);
3429 if (!path_startswith(path
, "/dev")) {
3430 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3434 if (streq("infinity", limit
)) {
3435 num
= CGROUP_LIMIT_MAX
;
3437 r
= parse_size(limit
, 1000, &num
);
3438 if (r
< 0 || num
<= 0) {
3439 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3444 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3445 if (path_equal(path
, t
->path
)) {
3452 CGroupIOLimitType ttype
;
3454 l
= new0(CGroupIODeviceLimit
, 1);
3460 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3461 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3463 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3466 l
->limits
[type
] = num
;
3471 int config_parse_blockio_weight(
3473 const char *filename
,
3475 const char *section
,
3476 unsigned section_line
,
3483 uint64_t *weight
= data
;
3490 r
= cg_blkio_weight_parse(rvalue
, weight
);
3492 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3499 int config_parse_blockio_device_weight(
3501 const char *filename
,
3503 const char *section
,
3504 unsigned section_line
,
3511 _cleanup_free_
char *path
= NULL
;
3512 CGroupBlockIODeviceWeight
*w
;
3513 CGroupContext
*c
= data
;
3523 if (isempty(rvalue
)) {
3524 while (c
->blockio_device_weights
)
3525 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3530 n
= strcspn(rvalue
, WHITESPACE
);
3531 weight
= rvalue
+ n
;
3532 weight
+= strspn(weight
, WHITESPACE
);
3534 if (isempty(weight
)) {
3535 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3539 path
= strndup(rvalue
, n
);
3543 if (!path_startswith(path
, "/dev")) {
3544 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3548 r
= cg_blkio_weight_parse(weight
, &u
);
3550 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3554 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3556 w
= new0(CGroupBlockIODeviceWeight
, 1);
3565 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3569 int config_parse_blockio_bandwidth(
3571 const char *filename
,
3573 const char *section
,
3574 unsigned section_line
,
3581 _cleanup_free_
char *path
= NULL
;
3582 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3583 CGroupContext
*c
= data
;
3584 const char *bandwidth
;
3594 read
= streq("BlockIOReadBandwidth", lvalue
);
3596 if (isempty(rvalue
)) {
3597 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3598 b
->rbps
= CGROUP_LIMIT_MAX
;
3599 b
->wbps
= CGROUP_LIMIT_MAX
;
3604 n
= strcspn(rvalue
, WHITESPACE
);
3605 bandwidth
= rvalue
+ n
;
3606 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3609 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3613 path
= strndup(rvalue
, n
);
3617 if (!path_startswith(path
, "/dev")) {
3618 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3622 r
= parse_size(bandwidth
, 1000, &bytes
);
3623 if (r
< 0 || bytes
<= 0) {
3624 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3628 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3629 if (path_equal(path
, t
->path
)) {
3636 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3642 b
->rbps
= CGROUP_LIMIT_MAX
;
3643 b
->wbps
= CGROUP_LIMIT_MAX
;
3645 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3656 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3658 int config_parse_job_mode_isolate(
3660 const char *filename
,
3662 const char *section
,
3663 unsigned section_line
,
3677 r
= parse_boolean(rvalue
);
3679 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3683 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3687 int config_parse_runtime_directory(
3689 const char *filename
,
3691 const char *section
,
3692 unsigned section_line
,
3709 if (isempty(rvalue
)) {
3710 /* Empty assignment resets the list */
3711 *rt
= strv_free(*rt
);
3715 for (p
= rvalue
;;) {
3716 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3718 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3724 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3725 "Invalid syntax, ignoring: %s", rvalue
);
3729 r
= unit_full_printf(u
, word
, &k
);
3731 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3732 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3736 if (!filename_is_valid(k
)) {
3737 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3738 "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3742 r
= strv_push(rt
, k
);
3749 int config_parse_set_status(
3751 const char *filename
,
3753 const char *section
,
3754 unsigned section_line
,
3762 const char *word
, *state
;
3764 ExitStatusSet
*status_set
= data
;
3771 /* Empty assignment resets the list */
3772 if (isempty(rvalue
)) {
3773 exit_status_set_free(status_set
);
3777 FOREACH_WORD(word
, l
, rvalue
, state
) {
3778 _cleanup_free_
char *temp
;
3782 temp
= strndup(word
, l
);
3786 r
= safe_atoi(temp
, &val
);
3788 val
= signal_from_string_try_harder(temp
);
3791 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3794 set
= &status_set
->signal
;
3796 if (val
< 0 || val
> 255) {
3797 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3800 set
= &status_set
->status
;
3803 r
= set_ensure_allocated(set
, NULL
);
3807 r
= set_put(*set
, INT_TO_PTR(val
));
3809 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3813 if (!isempty(state
))
3814 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3819 int config_parse_namespace_path_strv(
3821 const char *filename
,
3823 const char *section
,
3824 unsigned section_line
,
3841 if (isempty(rvalue
)) {
3842 /* Empty assignment resets the list */
3843 *sv
= strv_free(*sv
);
3849 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
3852 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3858 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
3862 if (!utf8_is_valid(word
)) {
3863 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3867 ignore_enoent
= word
[0] == '-';
3869 r
= unit_full_printf(u
, word
+ ignore_enoent
, &resolved
);
3871 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
3875 if (!path_is_absolute(resolved
)) {
3876 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
3880 path_kill_slashes(resolved
);
3882 joined
= strjoin(ignore_enoent
? "-" : "", resolved
);
3884 r
= strv_push(sv
, joined
);
3894 int config_parse_no_new_privileges(
3896 const char *filename
,
3898 const char *section
,
3899 unsigned section_line
,
3906 ExecContext
*c
= data
;
3914 k
= parse_boolean(rvalue
);
3916 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3920 c
->no_new_privileges
= k
;
3925 int config_parse_protect_home(
3927 const char *filename
,
3929 const char *section
,
3930 unsigned section_line
,
3937 ExecContext
*c
= data
;
3945 /* Our enum shall be a superset of booleans, hence first try
3946 * to parse as boolean, and then as enum */
3948 k
= parse_boolean(rvalue
);
3950 c
->protect_home
= PROTECT_HOME_YES
;
3952 c
->protect_home
= PROTECT_HOME_NO
;
3956 h
= protect_home_from_string(rvalue
);
3958 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3962 c
->protect_home
= h
;
3968 int config_parse_protect_system(
3970 const char *filename
,
3972 const char *section
,
3973 unsigned section_line
,
3980 ExecContext
*c
= data
;
3988 /* Our enum shall be a superset of booleans, hence first try
3989 * to parse as boolean, and then as enum */
3991 k
= parse_boolean(rvalue
);
3993 c
->protect_system
= PROTECT_SYSTEM_YES
;
3995 c
->protect_system
= PROTECT_SYSTEM_NO
;
3999 s
= protect_system_from_string(rvalue
);
4001 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4005 c
->protect_system
= s
;
4011 #define FOLLOW_MAX 8
4013 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4024 /* This will update the filename pointer if the loaded file is
4025 * reached by a symlink. The old string will be freed. */
4028 char *target
, *name
;
4030 if (c
++ >= FOLLOW_MAX
)
4033 path_kill_slashes(*filename
);
4035 /* Add the file name we are currently looking at to
4036 * the names of this unit, but only if it is a valid
4038 name
= basename(*filename
);
4039 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4041 id
= set_get(names
, name
);
4047 r
= set_consume(names
, id
);
4053 /* Try to open the file name, but don't if its a symlink */
4054 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4061 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4062 r
= readlink_and_make_absolute(*filename
, &target
);
4070 f
= fdopen(fd
, "re");
4082 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4090 /* Let's try to add in all symlink names we found */
4091 while ((k
= set_steal_first(names
))) {
4093 /* First try to merge in the other name into our
4095 r
= unit_merge_by_name(*u
, k
);
4099 /* Hmm, we couldn't merge the other unit into
4100 * ours? Then let's try it the other way
4103 /* If the symlink name we are looking at is unit template, then
4104 we must search for instance of this template */
4105 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4106 _cleanup_free_
char *instance
= NULL
;
4108 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4112 other
= manager_get_unit((*u
)->manager
, instance
);
4114 other
= manager_get_unit((*u
)->manager
, k
);
4119 r
= unit_merge(other
, *u
);
4122 return merge_by_names(u
, names
, NULL
);
4130 unit_choose_id(*u
, id
);
4138 static int load_from_path(Unit
*u
, const char *path
) {
4139 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4140 _cleanup_fclose_
FILE *f
= NULL
;
4141 _cleanup_free_
char *filename
= NULL
;
4150 symlink_names
= set_new(&string_hash_ops
);
4154 if (path_is_absolute(path
)) {
4156 filename
= strdup(path
);
4160 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4162 filename
= mfree(filename
);
4170 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4172 /* Instead of opening the path right away, we manually
4173 * follow all symlinks and add their name to our unit
4174 * name set while doing so */
4175 filename
= path_make_absolute(path
, *p
);
4179 if (u
->manager
->unit_path_cache
&&
4180 !set_get(u
->manager
->unit_path_cache
, filename
))
4183 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4186 filename
= mfree(filename
);
4188 /* ENOENT means that the file is missing or is a dangling symlink.
4189 * ENOTDIR means that one of paths we expect to be is a directory
4190 * is not a directory, we should just ignore that.
4191 * EACCES means that the directory or file permissions are wrong.
4194 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4195 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4198 /* Empty the symlink names for the next run */
4199 set_clear_free(symlink_names
);
4204 /* Hmm, no suitable file found? */
4207 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4208 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4213 r
= merge_by_names(&merged
, symlink_names
, id
);
4218 u
->load_state
= UNIT_MERGED
;
4222 if (fstat(fileno(f
), &st
) < 0)
4225 if (null_or_empty(&st
)) {
4226 u
->load_state
= UNIT_MASKED
;
4227 u
->fragment_mtime
= 0;
4229 u
->load_state
= UNIT_LOADED
;
4230 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4232 /* Now, parse the file contents */
4233 r
= config_parse(u
->id
, filename
, f
,
4234 UNIT_VTABLE(u
)->sections
,
4235 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4236 false, true, false, u
);
4241 free(u
->fragment_path
);
4242 u
->fragment_path
= filename
;
4245 if (u
->source_path
) {
4246 if (stat(u
->source_path
, &st
) >= 0)
4247 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4249 u
->source_mtime
= 0;
4255 int unit_load_fragment(Unit
*u
) {
4261 assert(u
->load_state
== UNIT_STUB
);
4265 u
->load_state
= UNIT_LOADED
;
4269 /* First, try to find the unit under its id. We always look
4270 * for unit files in the default directories, to make it easy
4271 * to override things by placing things in /etc/systemd/system */
4272 r
= load_from_path(u
, u
->id
);
4276 /* Try to find an alias we can load this with */
4277 if (u
->load_state
== UNIT_STUB
) {
4278 SET_FOREACH(t
, u
->names
, i
) {
4283 r
= load_from_path(u
, t
);
4287 if (u
->load_state
!= UNIT_STUB
)
4292 /* And now, try looking for it under the suggested (originally linked) path */
4293 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4295 r
= load_from_path(u
, u
->fragment_path
);
4299 if (u
->load_state
== UNIT_STUB
)
4300 /* Hmm, this didn't work? Then let's get rid
4301 * of the fragment path stored for us, so that
4302 * we don't point to an invalid location. */
4303 u
->fragment_path
= mfree(u
->fragment_path
);
4306 /* Look for a template */
4307 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4308 _cleanup_free_
char *k
= NULL
;
4310 r
= unit_name_template(u
->id
, &k
);
4314 r
= load_from_path(u
, k
);
4318 if (u
->load_state
== UNIT_STUB
) {
4319 SET_FOREACH(t
, u
->names
, i
) {
4320 _cleanup_free_
char *z
= NULL
;
4325 r
= unit_name_template(t
, &z
);
4329 r
= load_from_path(u
, z
);
4333 if (u
->load_state
!= UNIT_STUB
)
4342 void unit_dump_config_items(FILE *f
) {
4343 static const struct {
4344 const ConfigParserCallback callback
;
4347 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4348 { config_parse_warn_compat
, "NOTSUPPORTED" },
4350 { config_parse_int
, "INTEGER" },
4351 { config_parse_unsigned
, "UNSIGNED" },
4352 { config_parse_iec_size
, "SIZE" },
4353 { config_parse_iec_uint64
, "SIZE" },
4354 { config_parse_si_size
, "SIZE" },
4355 { config_parse_bool
, "BOOLEAN" },
4356 { config_parse_string
, "STRING" },
4357 { config_parse_path
, "PATH" },
4358 { config_parse_unit_path_printf
, "PATH" },
4359 { config_parse_strv
, "STRING [...]" },
4360 { config_parse_exec_nice
, "NICE" },
4361 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4362 { config_parse_exec_io_class
, "IOCLASS" },
4363 { config_parse_exec_io_priority
, "IOPRIORITY" },
4364 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4365 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4366 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4367 { config_parse_mode
, "MODE" },
4368 { config_parse_unit_env_file
, "FILE" },
4369 { config_parse_exec_output
, "OUTPUT" },
4370 { config_parse_exec_input
, "INPUT" },
4371 { config_parse_log_facility
, "FACILITY" },
4372 { config_parse_log_level
, "LEVEL" },
4373 { config_parse_exec_secure_bits
, "SECUREBITS" },
4374 { config_parse_capability_set
, "BOUNDINGSET" },
4375 { config_parse_limit
, "LIMIT" },
4376 { config_parse_unit_deps
, "UNIT [...]" },
4377 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4378 { config_parse_service_type
, "SERVICETYPE" },
4379 { config_parse_service_restart
, "SERVICERESTART" },
4380 #ifdef HAVE_SYSV_COMPAT
4381 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4383 { config_parse_kill_mode
, "KILLMODE" },
4384 { config_parse_signal
, "SIGNAL" },
4385 { config_parse_socket_listen
, "SOCKET [...]" },
4386 { config_parse_socket_bind
, "SOCKETBIND" },
4387 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4388 { config_parse_sec
, "SECONDS" },
4389 { config_parse_nsec
, "NANOSECONDS" },
4390 { config_parse_namespace_path_strv
, "PATH [...]" },
4391 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4392 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4393 { config_parse_unit_string_printf
, "STRING" },
4394 { config_parse_trigger_unit
, "UNIT" },
4395 { config_parse_timer
, "TIMER" },
4396 { config_parse_path_spec
, "PATH" },
4397 { config_parse_notify_access
, "ACCESS" },
4398 { config_parse_ip_tos
, "TOS" },
4399 { config_parse_unit_condition_path
, "CONDITION" },
4400 { config_parse_unit_condition_string
, "CONDITION" },
4401 { config_parse_unit_condition_null
, "CONDITION" },
4402 { config_parse_unit_slice
, "SLICE" },
4403 { config_parse_documentation
, "URL" },
4404 { config_parse_service_timeout
, "SECONDS" },
4405 { config_parse_emergency_action
, "ACTION" },
4406 { config_parse_set_status
, "STATUS" },
4407 { config_parse_service_sockets
, "SOCKETS" },
4408 { config_parse_environ
, "ENVIRON" },
4410 { config_parse_syscall_filter
, "SYSCALLS" },
4411 { config_parse_syscall_archs
, "ARCHS" },
4412 { config_parse_syscall_errno
, "ERRNO" },
4413 { config_parse_address_families
, "FAMILIES" },
4414 { config_parse_restrict_namespaces
, "NAMESPACES" },
4416 { config_parse_cpu_shares
, "SHARES" },
4417 { config_parse_cpu_weight
, "WEIGHT" },
4418 { config_parse_memory_limit
, "LIMIT" },
4419 { config_parse_device_allow
, "DEVICE" },
4420 { config_parse_device_policy
, "POLICY" },
4421 { config_parse_io_limit
, "LIMIT" },
4422 { config_parse_io_weight
, "WEIGHT" },
4423 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4424 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4425 { config_parse_blockio_weight
, "WEIGHT" },
4426 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4427 { config_parse_long
, "LONG" },
4428 { config_parse_socket_service
, "SERVICE" },
4430 { config_parse_exec_selinux_context
, "LABEL" },
4432 { config_parse_job_mode
, "MODE" },
4433 { config_parse_job_mode_isolate
, "BOOLEAN" },
4434 { config_parse_personality
, "PERSONALITY" },
4437 const char *prev
= NULL
;
4442 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4443 const char *rvalue
= "OTHER", *lvalue
;
4447 const ConfigPerfItem
*p
;
4449 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4451 dot
= strchr(i
, '.');
4452 lvalue
= dot
? dot
+ 1 : i
;
4456 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4460 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4463 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4464 if (p
->parse
== table
[j
].callback
) {
4465 rvalue
= table
[j
].rvalue
;
4469 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);