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
,
272 const char *word
, *state
;
282 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
283 _cleanup_free_
char *k
= NULL
;
289 r
= unit_full_printf(u
, t
, &k
);
291 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", t
);
295 if (!utf8_is_valid(k
)) {
296 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
300 if (!path_is_absolute(k
)) {
301 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Symlink path %s is not absolute, ignoring: %m", k
);
305 path_kill_slashes(k
);
314 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, ignoring.");
319 int config_parse_socket_listen(const char *unit
,
320 const char *filename
,
323 unsigned section_line
,
330 _cleanup_free_ SocketPort
*p
= NULL
;
342 if (isempty(rvalue
)) {
343 /* An empty assignment removes all ports */
344 socket_free_ports(s
);
348 p
= new0(SocketPort
, 1);
352 if (ltype
!= SOCKET_SOCKET
) {
355 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
357 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
361 path_kill_slashes(p
->path
);
363 } else if (streq(lvalue
, "ListenNetlink")) {
364 _cleanup_free_
char *k
= NULL
;
366 p
->type
= SOCKET_SOCKET
;
367 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
369 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
373 r
= socket_address_parse_netlink(&p
->address
, k
);
375 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
380 _cleanup_free_
char *k
= NULL
;
382 p
->type
= SOCKET_SOCKET
;
383 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
385 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
389 r
= socket_address_parse_and_warn(&p
->address
, k
);
391 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
395 if (streq(lvalue
, "ListenStream"))
396 p
->address
.type
= SOCK_STREAM
;
397 else if (streq(lvalue
, "ListenDatagram"))
398 p
->address
.type
= SOCK_DGRAM
;
400 assert(streq(lvalue
, "ListenSequentialPacket"));
401 p
->address
.type
= SOCK_SEQPACKET
;
404 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
405 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
411 p
->auxiliary_fds
= NULL
;
412 p
->n_auxiliary_fds
= 0;
416 LIST_FIND_TAIL(port
, s
->ports
, tail
);
417 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
419 LIST_PREPEND(port
, s
->ports
, p
);
425 int config_parse_socket_protocol(const char *unit
,
426 const char *filename
,
429 unsigned section_line
,
444 if (streq(rvalue
, "udplite"))
445 s
->socket_protocol
= IPPROTO_UDPLITE
;
446 else if (streq(rvalue
, "sctp"))
447 s
->socket_protocol
= IPPROTO_SCTP
;
449 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
456 int config_parse_socket_bind(const char *unit
,
457 const char *filename
,
460 unsigned section_line
,
468 SocketAddressBindIPv6Only b
;
477 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
481 r
= parse_boolean(rvalue
);
483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
487 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
489 s
->bind_ipv6_only
= b
;
494 int config_parse_exec_nice(
496 const char *filename
,
499 unsigned section_line
,
506 ExecContext
*c
= data
;
514 r
= parse_nice(rvalue
, &priority
);
517 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
519 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
530 int config_parse_exec_oom_score_adjust(const char* unit
,
531 const char *filename
,
534 unsigned section_line
,
541 ExecContext
*c
= data
;
549 r
= safe_atoi(rvalue
, &oa
);
551 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
555 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
556 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
560 c
->oom_score_adjust
= oa
;
561 c
->oom_score_adjust_set
= true;
566 int config_parse_exec(
568 const char *filename
,
571 unsigned section_line
,
578 ExecCommand
**e
= data
;
589 rvalue
+= strspn(rvalue
, WHITESPACE
);
591 if (isempty(rvalue
)) {
592 /* An empty assignment resets the list */
593 *e
= exec_command_free_list(*e
);
599 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
600 bool separate_argv0
= false, ignore
= false, privileged
= false;
601 _cleanup_free_ ExecCommand
*nce
= NULL
;
602 _cleanup_strv_free_
char **n
= NULL
;
603 size_t nlen
= 0, nbufsize
= 0;
609 r
= extract_first_word_and_warn(&p
, &firstword
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
614 for (i
= 0; i
< 3; i
++) {
615 /* We accept an absolute path as first argument.
616 * If it's prefixed with - and the path doesn't exist,
617 * we ignore it instead of erroring out;
618 * if it's prefixed with @, we allow overriding of argv[0];
619 * and if it's prefixed with !, it will be run with full privileges */
620 if (*f
== '-' && !ignore
)
622 else if (*f
== '@' && !separate_argv0
)
623 separate_argv0
= true;
624 else if (*f
== '+' && !privileged
)
632 /* First word is either "-" or "@" with no command. */
633 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty path in command line, ignoring: \"%s\"", rvalue
);
636 if (!string_is_safe(f
)) {
637 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path contains special characters, ignoring: %s", rvalue
);
640 if (!path_is_absolute(f
)) {
641 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path is not absolute, ignoring: %s", rvalue
);
644 if (endswith(f
, "/")) {
645 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path specifies a directory, ignoring: %s", rvalue
);
649 if (f
== firstword
) {
658 if (!separate_argv0
) {
659 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
668 path_kill_slashes(path
);
670 while (!isempty(p
)) {
671 _cleanup_free_
char *word
= NULL
;
673 /* Check explicitly for an unquoted semicolon as
674 * command separator token. */
675 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
677 p
+= strspn(p
, WHITESPACE
);
682 /* Check for \; explicitly, to not confuse it with \\;
683 * or "\;" or "\\;" etc. extract_first_word would
684 * return the same for all of those. */
685 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
687 p
+= strspn(p
, WHITESPACE
);
688 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
698 r
= extract_first_word_and_warn(&p
, &word
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
704 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
712 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue
);
716 nce
= new0(ExecCommand
, 1);
722 nce
->ignore
= ignore
;
723 nce
->privileged
= privileged
;
725 exec_command_append_list(e
, nce
);
727 /* Do not _cleanup_free_ these. */
738 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
739 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
741 int config_parse_socket_bindtodevice(
743 const char *filename
,
746 unsigned section_line
,
761 if (rvalue
[0] && !streq(rvalue
, "*")) {
762 if (!ifname_valid(rvalue
)) {
763 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
773 free(s
->bind_to_device
);
774 s
->bind_to_device
= n
;
779 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
780 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
782 int config_parse_exec_io_class(const char *unit
,
783 const char *filename
,
786 unsigned section_line
,
793 ExecContext
*c
= data
;
801 x
= ioprio_class_from_string(rvalue
);
803 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
807 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
808 c
->ioprio_set
= true;
813 int config_parse_exec_io_priority(const char *unit
,
814 const char *filename
,
817 unsigned section_line
,
824 ExecContext
*c
= data
;
832 r
= safe_atoi(rvalue
, &i
);
833 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
834 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
838 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
839 c
->ioprio_set
= true;
844 int config_parse_exec_cpu_sched_policy(const char *unit
,
845 const char *filename
,
848 unsigned section_line
,
856 ExecContext
*c
= data
;
864 x
= sched_policy_from_string(rvalue
);
866 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
870 c
->cpu_sched_policy
= x
;
871 /* Moving to or from real-time policy? We need to adjust the priority */
872 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
873 c
->cpu_sched_set
= true;
878 int config_parse_exec_cpu_sched_prio(const char *unit
,
879 const char *filename
,
882 unsigned section_line
,
889 ExecContext
*c
= data
;
897 r
= safe_atoi(rvalue
, &i
);
899 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
903 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
904 min
= sched_get_priority_min(c
->cpu_sched_policy
);
905 max
= sched_get_priority_max(c
->cpu_sched_policy
);
907 if (i
< min
|| i
> max
) {
908 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
912 c
->cpu_sched_priority
= i
;
913 c
->cpu_sched_set
= true;
918 int config_parse_exec_cpu_affinity(const char *unit
,
919 const char *filename
,
922 unsigned section_line
,
929 ExecContext
*c
= data
;
930 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
938 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
946 /* An empty assignment resets the CPU list */
952 c
->cpuset_ncpus
= ncpus
;
957 int config_parse_exec_secure_bits(const char *unit
,
958 const char *filename
,
961 unsigned section_line
,
968 ExecContext
*c
= data
;
970 const char *word
, *state
;
977 if (isempty(rvalue
)) {
978 /* An empty assignment resets the field */
983 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
984 if (first_word(word
, "keep-caps"))
985 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
986 else if (first_word(word
, "keep-caps-locked"))
987 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
988 else if (first_word(word
, "no-setuid-fixup"))
989 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
990 else if (first_word(word
, "no-setuid-fixup-locked"))
991 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
992 else if (first_word(word
, "noroot"))
993 c
->secure_bits
|= 1<<SECURE_NOROOT
;
994 else if (first_word(word
, "noroot-locked"))
995 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
997 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse secure bits, ignoring: %s", rvalue
);
1001 if (!isempty(state
))
1002 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, garbage at the end, ignoring.");
1007 int config_parse_capability_set(
1009 const char *filename
,
1011 const char *section
,
1012 unsigned section_line
,
1019 uint64_t *capability_set
= data
;
1020 uint64_t sum
= 0, initial
= 0;
1021 bool invert
= false;
1029 if (rvalue
[0] == '~') {
1034 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1035 initial
= CAP_ALL
; /* initialized to all bits on */
1036 /* else "AmbientCapabilities" initialized to all bits off */
1040 _cleanup_free_
char *word
= NULL
;
1043 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1049 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1053 cap
= capability_from_name(word
);
1055 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1059 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1062 sum
= invert
? ~sum
: sum
;
1064 if (sum
== 0 || *capability_set
== initial
)
1065 /* "" or uninitialized data -> replace */
1066 *capability_set
= sum
;
1068 /* previous data -> merge */
1069 *capability_set
|= sum
;
1074 int config_parse_limit(
1076 const char *filename
,
1078 const char *section
,
1079 unsigned section_line
,
1086 struct rlimit
**rl
= data
, d
= {};
1094 r
= rlimit_parse(ltype
, rvalue
, &d
);
1096 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1100 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1107 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1115 #ifdef HAVE_SYSV_COMPAT
1116 int config_parse_sysv_priority(const char *unit
,
1117 const char *filename
,
1119 const char *section
,
1120 unsigned section_line
,
1127 int *priority
= data
;
1135 r
= safe_atoi(rvalue
, &i
);
1136 if (r
< 0 || i
< 0) {
1137 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1141 *priority
= (int) i
;
1146 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1147 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1149 int config_parse_exec_mount_flags(const char *unit
,
1150 const char *filename
,
1152 const char *section
,
1153 unsigned section_line
,
1161 unsigned long flags
= 0;
1162 ExecContext
*c
= data
;
1169 if (streq(rvalue
, "shared"))
1171 else if (streq(rvalue
, "slave"))
1173 else if (streq(rvalue
, "private"))
1176 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1180 c
->mount_flags
= flags
;
1185 int config_parse_exec_selinux_context(
1187 const char *filename
,
1189 const char *section
,
1190 unsigned section_line
,
1197 ExecContext
*c
= data
;
1208 if (isempty(rvalue
)) {
1209 c
->selinux_context
= mfree(c
->selinux_context
);
1210 c
->selinux_context_ignore
= false;
1214 if (rvalue
[0] == '-') {
1220 r
= unit_name_printf(u
, rvalue
, &k
);
1222 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1226 free(c
->selinux_context
);
1227 c
->selinux_context
= k
;
1228 c
->selinux_context_ignore
= ignore
;
1233 int config_parse_exec_apparmor_profile(
1235 const char *filename
,
1237 const char *section
,
1238 unsigned section_line
,
1245 ExecContext
*c
= data
;
1256 if (isempty(rvalue
)) {
1257 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1258 c
->apparmor_profile_ignore
= false;
1262 if (rvalue
[0] == '-') {
1268 r
= unit_name_printf(u
, rvalue
, &k
);
1270 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1274 free(c
->apparmor_profile
);
1275 c
->apparmor_profile
= k
;
1276 c
->apparmor_profile_ignore
= ignore
;
1281 int config_parse_exec_smack_process_label(
1283 const char *filename
,
1285 const char *section
,
1286 unsigned section_line
,
1293 ExecContext
*c
= data
;
1304 if (isempty(rvalue
)) {
1305 c
->smack_process_label
= mfree(c
->smack_process_label
);
1306 c
->smack_process_label_ignore
= false;
1310 if (rvalue
[0] == '-') {
1316 r
= unit_name_printf(u
, rvalue
, &k
);
1318 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1322 free(c
->smack_process_label
);
1323 c
->smack_process_label
= k
;
1324 c
->smack_process_label_ignore
= ignore
;
1329 int config_parse_timer(const char *unit
,
1330 const char *filename
,
1332 const char *section
,
1333 unsigned section_line
,
1344 CalendarSpec
*c
= NULL
;
1351 if (isempty(rvalue
)) {
1352 /* Empty assignment resets list */
1353 timer_free_values(t
);
1357 b
= timer_base_from_string(lvalue
);
1359 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1363 if (b
== TIMER_CALENDAR
) {
1364 if (calendar_spec_from_string(rvalue
, &c
) < 0) {
1365 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", rvalue
);
1369 if (parse_sec(rvalue
, &u
) < 0) {
1370 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", rvalue
);
1375 v
= new0(TimerValue
, 1);
1377 calendar_spec_free(c
);
1383 v
->calendar_spec
= c
;
1385 LIST_PREPEND(value
, t
->values
, v
);
1390 int config_parse_trigger_unit(
1392 const char *filename
,
1394 const char *section
,
1395 unsigned section_line
,
1402 _cleanup_free_
char *p
= NULL
;
1412 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1413 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1417 r
= unit_name_printf(u
, rvalue
, &p
);
1419 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1423 type
= unit_name_to_type(p
);
1425 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1429 if (type
== u
->type
) {
1430 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1434 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1436 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1443 int config_parse_path_spec(const char *unit
,
1444 const char *filename
,
1446 const char *section
,
1447 unsigned section_line
,
1457 _cleanup_free_
char *k
= NULL
;
1465 if (isempty(rvalue
)) {
1466 /* Empty assignment clears list */
1471 b
= path_type_from_string(lvalue
);
1473 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1477 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1479 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1483 if (!path_is_absolute(k
)) {
1484 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1488 s
= new0(PathSpec
, 1);
1493 s
->path
= path_kill_slashes(k
);
1498 LIST_PREPEND(spec
, p
->specs
, s
);
1503 int config_parse_socket_service(
1505 const char *filename
,
1507 const char *section
,
1508 unsigned section_line
,
1515 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1516 _cleanup_free_
char *p
= NULL
;
1526 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1528 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1532 if (!endswith(p
, ".service")) {
1533 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1537 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1539 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1543 unit_ref_set(&s
->service
, x
);
1548 int config_parse_fdname(
1550 const char *filename
,
1552 const char *section
,
1553 unsigned section_line
,
1560 _cleanup_free_
char *p
= NULL
;
1569 if (isempty(rvalue
)) {
1570 s
->fdname
= mfree(s
->fdname
);
1574 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1576 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1580 if (!fdname_is_valid(p
)) {
1581 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1592 int config_parse_service_sockets(
1594 const char *filename
,
1596 const char *section
,
1597 unsigned section_line
,
1615 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1617 r
= extract_first_word(&p
, &word
, NULL
, 0);
1623 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1627 r
= unit_name_printf(UNIT(s
), word
, &k
);
1629 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1633 if (!endswith(k
, ".socket")) {
1634 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1638 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1640 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1642 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1644 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1650 int config_parse_bus_name(
1652 const char *filename
,
1654 const char *section
,
1655 unsigned section_line
,
1662 _cleanup_free_
char *k
= NULL
;
1671 r
= unit_full_printf(u
, rvalue
, &k
);
1673 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1677 if (!service_name_is_valid(k
)) {
1678 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1682 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1685 int config_parse_service_timeout(
1687 const char *filename
,
1689 const char *section
,
1690 unsigned section_line
,
1697 Service
*s
= userdata
;
1706 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1708 r
= parse_sec(rvalue
, &usec
);
1710 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1714 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1715 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1716 * all other timeouts. */
1718 usec
= USEC_INFINITY
;
1720 if (!streq(lvalue
, "TimeoutStopSec")) {
1721 s
->start_timeout_defined
= true;
1722 s
->timeout_start_usec
= usec
;
1725 if (!streq(lvalue
, "TimeoutStartSec"))
1726 s
->timeout_stop_usec
= usec
;
1731 int config_parse_sec_fix_0(
1733 const char *filename
,
1735 const char *section
,
1736 unsigned section_line
,
1743 usec_t
*usec
= data
;
1751 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1752 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1755 r
= parse_sec(rvalue
, usec
);
1757 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1762 *usec
= USEC_INFINITY
;
1767 int config_parse_user_group(
1769 const char *filename
,
1771 const char *section
,
1772 unsigned section_line
,
1779 char **user
= data
, *n
;
1788 if (isempty(rvalue
))
1791 _cleanup_free_
char *k
= NULL
;
1793 r
= unit_full_printf(u
, rvalue
, &k
);
1795 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1799 if (!valid_user_group_name_or_id(k
)) {
1800 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1814 int config_parse_user_group_strv(
1816 const char *filename
,
1818 const char *section
,
1819 unsigned section_line
,
1826 char ***users
= data
;
1836 if (isempty(rvalue
)) {
1839 empty
= new0(char*, 1);
1851 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1853 r
= extract_first_word(&p
, &word
, WHITESPACE
, 0);
1859 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1863 r
= unit_full_printf(u
, word
, &k
);
1865 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", word
);
1869 if (!valid_user_group_name_or_id(k
)) {
1870 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1874 r
= strv_push(users
, k
);
1884 int config_parse_busname_service(
1886 const char *filename
,
1888 const char *section
,
1889 unsigned section_line
,
1896 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1900 _cleanup_free_
char *p
= NULL
;
1907 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
1909 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1913 if (!endswith(p
, ".service")) {
1914 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1918 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
1920 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1924 unit_ref_set(&n
->service
, x
);
1929 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
1931 int config_parse_bus_policy(
1933 const char *filename
,
1935 const char *section
,
1936 unsigned section_line
,
1943 _cleanup_free_ BusNamePolicy
*p
= NULL
;
1944 _cleanup_free_
char *id_str
= NULL
;
1945 BusName
*busname
= data
;
1953 p
= new0(BusNamePolicy
, 1);
1957 if (streq(lvalue
, "AllowUser"))
1958 p
->type
= BUSNAME_POLICY_TYPE_USER
;
1959 else if (streq(lvalue
, "AllowGroup"))
1960 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
1962 assert_not_reached("Unknown lvalue");
1964 id_str
= strdup(rvalue
);
1968 access_str
= strpbrk(id_str
, WHITESPACE
);
1970 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
1976 access_str
+= strspn(access_str
, WHITESPACE
);
1978 p
->access
= bus_policy_access_from_string(access_str
);
1979 if (p
->access
< 0) {
1980 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
1987 LIST_PREPEND(policy
, busname
->policy
, p
);
1993 int config_parse_working_directory(
1995 const char *filename
,
1997 const char *section
,
1998 unsigned section_line
,
2005 ExecContext
*c
= data
;
2016 if (rvalue
[0] == '-') {
2022 if (streq(rvalue
, "~")) {
2023 c
->working_directory_home
= true;
2024 c
->working_directory
= mfree(c
->working_directory
);
2026 _cleanup_free_
char *k
= NULL
;
2028 r
= unit_full_printf(u
, rvalue
, &k
);
2030 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2034 path_kill_slashes(k
);
2036 if (!utf8_is_valid(k
)) {
2037 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2041 if (!path_is_absolute(k
)) {
2042 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2046 free(c
->working_directory
);
2047 c
->working_directory
= k
;
2050 c
->working_directory_home
= false;
2053 c
->working_directory_missing_ok
= missing_ok
;
2057 int config_parse_unit_env_file(const char *unit
,
2058 const char *filename
,
2060 const char *section
,
2061 unsigned section_line
,
2070 _cleanup_free_
char *n
= NULL
;
2078 if (isempty(rvalue
)) {
2079 /* Empty assignment frees the list */
2080 *env
= strv_free(*env
);
2084 r
= unit_full_printf(u
, rvalue
, &n
);
2086 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2090 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2091 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2095 r
= strv_extend(env
, n
);
2102 int config_parse_environ(const char *unit
,
2103 const char *filename
,
2105 const char *section
,
2106 unsigned section_line
,
2115 const char *word
, *state
;
2117 _cleanup_free_
char *k
= NULL
;
2125 if (isempty(rvalue
)) {
2126 /* Empty assignment resets the list */
2127 *env
= strv_free(*env
);
2132 r
= unit_full_printf(u
, rvalue
, &k
);
2134 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2145 FOREACH_WORD_QUOTED(word
, l
, k
, state
) {
2146 _cleanup_free_
char *n
= NULL
;
2149 r
= cunescape_length(word
, l
, 0, &n
);
2151 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Couldn't unescape assignment, ignoring: %s", rvalue
);
2155 if (!env_assignment_is_valid(n
)) {
2156 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid environment assignment, ignoring: %s", rvalue
);
2160 x
= strv_env_set(*env
, n
);
2167 if (!isempty(state
))
2168 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2173 int config_parse_pass_environ(const char *unit
,
2174 const char *filename
,
2176 const char *section
,
2177 unsigned section_line
,
2184 const char *whole_rvalue
= rvalue
;
2185 char*** passenv
= data
;
2186 _cleanup_strv_free_
char **n
= NULL
;
2187 size_t nlen
= 0, nbufsize
= 0;
2195 if (isempty(rvalue
)) {
2196 /* Empty assignment resets the list */
2197 *passenv
= strv_free(*passenv
);
2202 _cleanup_free_
char *word
= NULL
;
2204 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
);
2210 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2211 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2215 if (!env_name_is_valid(word
)) {
2216 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2217 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2221 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2229 r
= strv_extend_strv(passenv
, n
, true);
2237 int config_parse_ip_tos(const char *unit
,
2238 const char *filename
,
2240 const char *section
,
2241 unsigned section_line
,
2248 int *ip_tos
= data
, x
;
2255 x
= ip_tos_from_string(rvalue
);
2257 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2265 int config_parse_unit_condition_path(
2267 const char *filename
,
2269 const char *section
,
2270 unsigned section_line
,
2277 _cleanup_free_
char *p
= NULL
;
2278 Condition
**list
= data
, *c
;
2279 ConditionType t
= ltype
;
2280 bool trigger
, negate
;
2289 if (isempty(rvalue
)) {
2290 /* Empty assignment resets the list */
2291 *list
= condition_free_list(*list
);
2295 trigger
= rvalue
[0] == '|';
2299 negate
= rvalue
[0] == '!';
2303 r
= unit_full_printf(u
, rvalue
, &p
);
2305 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2309 if (!path_is_absolute(p
)) {
2310 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2314 c
= condition_new(t
, p
, trigger
, negate
);
2318 LIST_PREPEND(conditions
, *list
, c
);
2322 int config_parse_unit_condition_string(
2324 const char *filename
,
2326 const char *section
,
2327 unsigned section_line
,
2334 _cleanup_free_
char *s
= NULL
;
2335 Condition
**list
= data
, *c
;
2336 ConditionType t
= ltype
;
2337 bool trigger
, negate
;
2346 if (isempty(rvalue
)) {
2347 /* Empty assignment resets the list */
2348 *list
= condition_free_list(*list
);
2352 trigger
= rvalue
[0] == '|';
2356 negate
= rvalue
[0] == '!';
2360 r
= unit_full_printf(u
, rvalue
, &s
);
2362 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2366 c
= condition_new(t
, s
, trigger
, negate
);
2370 LIST_PREPEND(conditions
, *list
, c
);
2374 int config_parse_unit_condition_null(
2376 const char *filename
,
2378 const char *section
,
2379 unsigned section_line
,
2386 Condition
**list
= data
, *c
;
2387 bool trigger
, negate
;
2395 if (isempty(rvalue
)) {
2396 /* Empty assignment resets the list */
2397 *list
= condition_free_list(*list
);
2401 trigger
= rvalue
[0] == '|';
2405 negate
= rvalue
[0] == '!';
2409 b
= parse_boolean(rvalue
);
2411 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2418 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2422 LIST_PREPEND(conditions
, *list
, c
);
2426 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2427 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action
, failure_action
, FailureAction
, "Failed to parse failure action specifier");
2429 int config_parse_unit_requires_mounts_for(
2431 const char *filename
,
2433 const char *section
,
2434 unsigned section_line
,
2442 const char *word
, *state
;
2450 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2452 _cleanup_free_
char *n
;
2454 n
= strndup(word
, l
);
2458 if (!utf8_is_valid(n
)) {
2459 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2463 r
= unit_require_mounts_for(u
, n
);
2465 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount for, ignoring: %s", rvalue
);
2469 if (!isempty(state
))
2470 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2475 int config_parse_documentation(const char *unit
,
2476 const char *filename
,
2478 const char *section
,
2479 unsigned section_line
,
2495 if (isempty(rvalue
)) {
2496 /* Empty assignment resets the list */
2497 u
->documentation
= strv_free(u
->documentation
);
2501 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2502 rvalue
, data
, userdata
);
2506 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2508 if (documentation_url_is_valid(*a
))
2511 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2522 static int syscall_filter_parse_one(
2524 const char *filename
,
2533 const SystemCallFilterSet
*set
;
2535 for (set
= syscall_filter_sets
; set
->set_name
; set
++)
2536 if (streq(set
->set_name
, t
)) {
2539 NULSTR_FOREACH(sys
, set
->value
) {
2540 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, sys
, false);
2549 id
= seccomp_syscall_resolve_name(t
);
2550 if (id
== __NR_SCMP_ERROR
) {
2552 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2556 /* If we previously wanted to forbid a syscall and now
2557 * we want to allow it, then remove it from the list
2559 if (!invert
== c
->syscall_whitelist
) {
2560 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2566 set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2571 int config_parse_syscall_filter(
2573 const char *filename
,
2575 const char *section
,
2576 unsigned section_line
,
2583 ExecContext
*c
= data
;
2585 bool invert
= false;
2586 const char *word
, *state
;
2595 if (isempty(rvalue
)) {
2596 /* Empty assignment resets the list */
2597 c
->syscall_filter
= set_free(c
->syscall_filter
);
2598 c
->syscall_whitelist
= false;
2602 if (rvalue
[0] == '~') {
2607 if (!c
->syscall_filter
) {
2608 c
->syscall_filter
= set_new(NULL
);
2609 if (!c
->syscall_filter
)
2613 /* Allow everything but the ones listed */
2614 c
->syscall_whitelist
= false;
2616 /* Allow nothing but the ones listed */
2617 c
->syscall_whitelist
= true;
2619 /* Accept default syscalls if we are on a whitelist */
2620 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2626 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2627 _cleanup_free_
char *t
= NULL
;
2629 t
= strndup(word
, l
);
2633 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, t
, true);
2637 if (!isempty(state
))
2638 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2640 /* Turn on NNP, but only if it wasn't configured explicitly
2641 * before, and only if we are in user mode. */
2642 if (!c
->no_new_privileges_set
&& MANAGER_IS_USER(u
->manager
))
2643 c
->no_new_privileges
= true;
2648 int config_parse_syscall_archs(
2650 const char *filename
,
2652 const char *section
,
2653 unsigned section_line
,
2661 const char *word
, *state
;
2665 if (isempty(rvalue
)) {
2666 *archs
= set_free(*archs
);
2670 r
= set_ensure_allocated(archs
, NULL
);
2674 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2675 _cleanup_free_
char *t
= NULL
;
2678 t
= strndup(word
, l
);
2682 r
= seccomp_arch_from_string(t
, &a
);
2684 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call architecture, ignoring: %s", t
);
2688 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2694 if (!isempty(state
))
2695 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2700 int config_parse_syscall_errno(
2702 const char *filename
,
2704 const char *section
,
2705 unsigned section_line
,
2712 ExecContext
*c
= data
;
2719 if (isempty(rvalue
)) {
2720 /* Empty assignment resets to KILL */
2721 c
->syscall_errno
= 0;
2725 e
= errno_from_name(rvalue
);
2727 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2731 c
->syscall_errno
= e
;
2735 int config_parse_address_families(
2737 const char *filename
,
2739 const char *section
,
2740 unsigned section_line
,
2747 ExecContext
*c
= data
;
2748 bool invert
= false;
2749 const char *word
, *state
;
2757 if (isempty(rvalue
)) {
2758 /* Empty assignment resets the list */
2759 c
->address_families
= set_free(c
->address_families
);
2760 c
->address_families_whitelist
= false;
2764 if (rvalue
[0] == '~') {
2769 if (!c
->address_families
) {
2770 c
->address_families
= set_new(NULL
);
2771 if (!c
->address_families
)
2774 c
->address_families_whitelist
= !invert
;
2777 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2778 _cleanup_free_
char *t
= NULL
;
2781 t
= strndup(word
, l
);
2785 af
= af_from_name(t
);
2787 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse address family, ignoring: %s", t
);
2791 /* If we previously wanted to forbid an address family and now
2792 * we want to allow it, then remove it from the list
2794 if (!invert
== c
->address_families_whitelist
) {
2795 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2801 set_remove(c
->address_families
, INT_TO_PTR(af
));
2803 if (!isempty(state
))
2804 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2810 int config_parse_unit_slice(
2812 const char *filename
,
2814 const char *section
,
2815 unsigned section_line
,
2822 _cleanup_free_
char *k
= NULL
;
2823 Unit
*u
= userdata
, *slice
= NULL
;
2831 r
= unit_name_printf(u
, rvalue
, &k
);
2833 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2837 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2839 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2843 r
= unit_set_slice(u
, slice
);
2845 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2852 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2854 int config_parse_cpu_weight(
2856 const char *filename
,
2858 const char *section
,
2859 unsigned section_line
,
2866 uint64_t *weight
= data
;
2873 r
= cg_weight_parse(rvalue
, weight
);
2875 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
2882 int config_parse_cpu_shares(
2884 const char *filename
,
2886 const char *section
,
2887 unsigned section_line
,
2894 uint64_t *shares
= data
;
2901 r
= cg_cpu_shares_parse(rvalue
, shares
);
2903 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2910 int config_parse_cpu_quota(
2912 const char *filename
,
2914 const char *section
,
2915 unsigned section_line
,
2922 CGroupContext
*c
= data
;
2929 if (isempty(rvalue
)) {
2930 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2934 r
= parse_percent_unbounded(rvalue
);
2936 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
2940 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
2944 int config_parse_memory_limit(
2946 const char *filename
,
2948 const char *section
,
2949 unsigned section_line
,
2956 CGroupContext
*c
= data
;
2957 uint64_t bytes
= CGROUP_LIMIT_MAX
;
2960 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
2962 r
= parse_percent(rvalue
);
2964 r
= parse_size(rvalue
, 1024, &bytes
);
2966 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
2970 bytes
= physical_memory_scale(r
, 100U);
2972 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
2973 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
2978 if (streq(lvalue
, "MemoryLow"))
2979 c
->memory_low
= bytes
;
2980 else if (streq(lvalue
, "MemoryHigh"))
2981 c
->memory_high
= bytes
;
2982 else if (streq(lvalue
, "MemoryMax"))
2983 c
->memory_max
= bytes
;
2985 c
->memory_limit
= bytes
;
2990 int config_parse_tasks_max(
2992 const char *filename
,
2994 const char *section
,
2995 unsigned section_line
,
3002 uint64_t *tasks_max
= data
, v
;
3006 if (isempty(rvalue
)) {
3007 *tasks_max
= u
->manager
->default_tasks_max
;
3011 if (streq(rvalue
, "infinity")) {
3012 *tasks_max
= CGROUP_LIMIT_MAX
;
3016 r
= parse_percent(rvalue
);
3018 r
= safe_atou64(rvalue
, &v
);
3020 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3024 v
= system_tasks_max_scale(r
, 100U);
3026 if (v
<= 0 || v
>= UINT64_MAX
) {
3027 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3035 int config_parse_device_allow(
3037 const char *filename
,
3039 const char *section
,
3040 unsigned section_line
,
3047 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3048 CGroupContext
*c
= data
;
3049 CGroupDeviceAllow
*a
;
3050 const char *m
= NULL
;
3054 if (isempty(rvalue
)) {
3055 while (c
->device_allow
)
3056 cgroup_context_free_device_allow(c
, c
->device_allow
);
3061 r
= unit_full_printf(userdata
, rvalue
, &t
);
3063 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3064 "Failed to resolve specifiers in %s, ignoring: %m",
3068 n
= strcspn(t
, WHITESPACE
);
3070 path
= strndup(t
, n
);
3074 if (!startswith(path
, "/dev/") &&
3075 !startswith(path
, "block-") &&
3076 !startswith(path
, "char-")) {
3077 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3081 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3085 if (!in_charset(m
, "rwm")) {
3086 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3090 a
= new0(CGroupDeviceAllow
, 1);
3096 a
->r
= !!strchr(m
, 'r');
3097 a
->w
= !!strchr(m
, 'w');
3098 a
->m
= !!strchr(m
, 'm');
3100 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3104 int config_parse_io_weight(
3106 const char *filename
,
3108 const char *section
,
3109 unsigned section_line
,
3116 uint64_t *weight
= data
;
3123 r
= cg_weight_parse(rvalue
, weight
);
3125 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3132 int config_parse_io_device_weight(
3134 const char *filename
,
3136 const char *section
,
3137 unsigned section_line
,
3144 _cleanup_free_
char *path
= NULL
;
3145 CGroupIODeviceWeight
*w
;
3146 CGroupContext
*c
= data
;
3156 if (isempty(rvalue
)) {
3157 while (c
->io_device_weights
)
3158 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3163 n
= strcspn(rvalue
, WHITESPACE
);
3164 weight
= rvalue
+ n
;
3165 weight
+= strspn(weight
, WHITESPACE
);
3167 if (isempty(weight
)) {
3168 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3172 path
= strndup(rvalue
, n
);
3176 if (!path_startswith(path
, "/dev")) {
3177 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3181 r
= cg_weight_parse(weight
, &u
);
3183 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3187 assert(u
!= CGROUP_WEIGHT_INVALID
);
3189 w
= new0(CGroupIODeviceWeight
, 1);
3198 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3202 int config_parse_io_limit(
3204 const char *filename
,
3206 const char *section
,
3207 unsigned section_line
,
3214 _cleanup_free_
char *path
= NULL
;
3215 CGroupIODeviceLimit
*l
= NULL
, *t
;
3216 CGroupContext
*c
= data
;
3217 CGroupIOLimitType type
;
3227 type
= cgroup_io_limit_type_from_string(lvalue
);
3230 if (isempty(rvalue
)) {
3231 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3232 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3236 n
= strcspn(rvalue
, WHITESPACE
);
3238 limit
+= strspn(limit
, WHITESPACE
);
3241 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3245 path
= strndup(rvalue
, n
);
3249 if (!path_startswith(path
, "/dev")) {
3250 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3254 if (streq("infinity", limit
)) {
3255 num
= CGROUP_LIMIT_MAX
;
3257 r
= parse_size(limit
, 1000, &num
);
3258 if (r
< 0 || num
<= 0) {
3259 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3264 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3265 if (path_equal(path
, t
->path
)) {
3272 CGroupIOLimitType ttype
;
3274 l
= new0(CGroupIODeviceLimit
, 1);
3280 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3281 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3283 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3286 l
->limits
[type
] = num
;
3291 int config_parse_blockio_weight(
3293 const char *filename
,
3295 const char *section
,
3296 unsigned section_line
,
3303 uint64_t *weight
= data
;
3310 r
= cg_blkio_weight_parse(rvalue
, weight
);
3312 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3319 int config_parse_blockio_device_weight(
3321 const char *filename
,
3323 const char *section
,
3324 unsigned section_line
,
3331 _cleanup_free_
char *path
= NULL
;
3332 CGroupBlockIODeviceWeight
*w
;
3333 CGroupContext
*c
= data
;
3343 if (isempty(rvalue
)) {
3344 while (c
->blockio_device_weights
)
3345 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3350 n
= strcspn(rvalue
, WHITESPACE
);
3351 weight
= rvalue
+ n
;
3352 weight
+= strspn(weight
, WHITESPACE
);
3354 if (isempty(weight
)) {
3355 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3359 path
= strndup(rvalue
, n
);
3363 if (!path_startswith(path
, "/dev")) {
3364 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3368 r
= cg_blkio_weight_parse(weight
, &u
);
3370 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3374 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3376 w
= new0(CGroupBlockIODeviceWeight
, 1);
3385 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3389 int config_parse_blockio_bandwidth(
3391 const char *filename
,
3393 const char *section
,
3394 unsigned section_line
,
3401 _cleanup_free_
char *path
= NULL
;
3402 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3403 CGroupContext
*c
= data
;
3404 const char *bandwidth
;
3414 read
= streq("BlockIOReadBandwidth", lvalue
);
3416 if (isempty(rvalue
)) {
3417 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3418 b
->rbps
= CGROUP_LIMIT_MAX
;
3419 b
->wbps
= CGROUP_LIMIT_MAX
;
3424 n
= strcspn(rvalue
, WHITESPACE
);
3425 bandwidth
= rvalue
+ n
;
3426 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3429 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3433 path
= strndup(rvalue
, n
);
3437 if (!path_startswith(path
, "/dev")) {
3438 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3442 r
= parse_size(bandwidth
, 1000, &bytes
);
3443 if (r
< 0 || bytes
<= 0) {
3444 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3448 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3449 if (path_equal(path
, t
->path
)) {
3456 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3462 b
->rbps
= CGROUP_LIMIT_MAX
;
3463 b
->wbps
= CGROUP_LIMIT_MAX
;
3465 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3476 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3478 int config_parse_job_mode_isolate(
3480 const char *filename
,
3482 const char *section
,
3483 unsigned section_line
,
3497 r
= parse_boolean(rvalue
);
3499 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3503 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3507 int config_parse_runtime_directory(
3509 const char *filename
,
3511 const char *section
,
3512 unsigned section_line
,
3521 const char *word
, *state
;
3530 if (isempty(rvalue
)) {
3531 /* Empty assignment resets the list */
3532 *rt
= strv_free(*rt
);
3536 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3537 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3539 t
= strndup(word
, l
);
3543 r
= unit_name_printf(u
, t
, &n
);
3545 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3549 if (!filename_is_valid(n
)) {
3550 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3554 r
= strv_push(rt
, n
);
3560 if (!isempty(state
))
3561 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3566 int config_parse_set_status(
3568 const char *filename
,
3570 const char *section
,
3571 unsigned section_line
,
3579 const char *word
, *state
;
3581 ExitStatusSet
*status_set
= data
;
3588 /* Empty assignment resets the list */
3589 if (isempty(rvalue
)) {
3590 exit_status_set_free(status_set
);
3594 FOREACH_WORD(word
, l
, rvalue
, state
) {
3595 _cleanup_free_
char *temp
;
3599 temp
= strndup(word
, l
);
3603 r
= safe_atoi(temp
, &val
);
3605 val
= signal_from_string_try_harder(temp
);
3608 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3611 set
= &status_set
->signal
;
3613 if (val
< 0 || val
> 255) {
3614 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3617 set
= &status_set
->status
;
3620 r
= set_ensure_allocated(set
, NULL
);
3624 r
= set_put(*set
, INT_TO_PTR(val
));
3626 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3630 if (!isempty(state
))
3631 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3636 int config_parse_namespace_path_strv(
3638 const char *filename
,
3640 const char *section
,
3641 unsigned section_line
,
3658 if (isempty(rvalue
)) {
3659 /* Empty assignment resets the list */
3660 *sv
= strv_free(*sv
);
3664 prev
= cur
= rvalue
;
3666 _cleanup_free_
char *word
= NULL
;
3669 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3675 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3679 if (!utf8_is_valid(word
)) {
3680 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3685 offset
= word
[0] == '-';
3686 if (!path_is_absolute(word
+ offset
)) {
3687 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3692 path_kill_slashes(word
+ offset
);
3694 r
= strv_push(sv
, word
);
3705 int config_parse_no_new_privileges(
3707 const char *filename
,
3709 const char *section
,
3710 unsigned section_line
,
3717 ExecContext
*c
= data
;
3725 k
= parse_boolean(rvalue
);
3727 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3731 c
->no_new_privileges
= !!k
;
3732 c
->no_new_privileges_set
= true;
3737 int config_parse_protect_home(
3739 const char *filename
,
3741 const char *section
,
3742 unsigned section_line
,
3749 ExecContext
*c
= data
;
3757 /* Our enum shall be a superset of booleans, hence first try
3758 * to parse as boolean, and then as enum */
3760 k
= parse_boolean(rvalue
);
3762 c
->protect_home
= PROTECT_HOME_YES
;
3764 c
->protect_home
= PROTECT_HOME_NO
;
3768 h
= protect_home_from_string(rvalue
);
3770 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3774 c
->protect_home
= h
;
3780 int config_parse_protect_system(
3782 const char *filename
,
3784 const char *section
,
3785 unsigned section_line
,
3792 ExecContext
*c
= data
;
3800 /* Our enum shall be a superset of booleans, hence first try
3801 * to parse as boolean, and then as enum */
3803 k
= parse_boolean(rvalue
);
3805 c
->protect_system
= PROTECT_SYSTEM_YES
;
3807 c
->protect_system
= PROTECT_SYSTEM_NO
;
3811 s
= protect_system_from_string(rvalue
);
3813 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3817 c
->protect_system
= s
;
3823 #define FOLLOW_MAX 8
3825 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3836 /* This will update the filename pointer if the loaded file is
3837 * reached by a symlink. The old string will be freed. */
3840 char *target
, *name
;
3842 if (c
++ >= FOLLOW_MAX
)
3845 path_kill_slashes(*filename
);
3847 /* Add the file name we are currently looking at to
3848 * the names of this unit, but only if it is a valid
3850 name
= basename(*filename
);
3851 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3853 id
= set_get(names
, name
);
3859 r
= set_consume(names
, id
);
3865 /* Try to open the file name, but don't if its a symlink */
3866 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3873 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3874 r
= readlink_and_make_absolute(*filename
, &target
);
3882 f
= fdopen(fd
, "re");
3894 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
3902 /* Let's try to add in all symlink names we found */
3903 while ((k
= set_steal_first(names
))) {
3905 /* First try to merge in the other name into our
3907 r
= unit_merge_by_name(*u
, k
);
3911 /* Hmm, we couldn't merge the other unit into
3912 * ours? Then let's try it the other way
3915 /* If the symlink name we are looking at is unit template, then
3916 we must search for instance of this template */
3917 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
3918 _cleanup_free_
char *instance
= NULL
;
3920 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
3924 other
= manager_get_unit((*u
)->manager
, instance
);
3926 other
= manager_get_unit((*u
)->manager
, k
);
3931 r
= unit_merge(other
, *u
);
3934 return merge_by_names(u
, names
, NULL
);
3942 unit_choose_id(*u
, id
);
3950 static int load_from_path(Unit
*u
, const char *path
) {
3951 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
3952 _cleanup_fclose_
FILE *f
= NULL
;
3953 _cleanup_free_
char *filename
= NULL
;
3962 symlink_names
= set_new(&string_hash_ops
);
3966 if (path_is_absolute(path
)) {
3968 filename
= strdup(path
);
3972 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3974 filename
= mfree(filename
);
3982 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
3984 /* Instead of opening the path right away, we manually
3985 * follow all symlinks and add their name to our unit
3986 * name set while doing so */
3987 filename
= path_make_absolute(path
, *p
);
3991 if (u
->manager
->unit_path_cache
&&
3992 !set_get(u
->manager
->unit_path_cache
, filename
))
3995 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3998 filename
= mfree(filename
);
4000 /* ENOENT means that the file is missing or is a dangling symlink.
4001 * ENOTDIR means that one of paths we expect to be is a directory
4002 * is not a directory, we should just ignore that.
4003 * EACCES means that the directory or file permissions are wrong.
4006 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4007 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4010 /* Empty the symlink names for the next run */
4011 set_clear_free(symlink_names
);
4016 /* Hmm, no suitable file found? */
4019 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4020 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4025 r
= merge_by_names(&merged
, symlink_names
, id
);
4030 u
->load_state
= UNIT_MERGED
;
4034 if (fstat(fileno(f
), &st
) < 0)
4037 if (null_or_empty(&st
)) {
4038 u
->load_state
= UNIT_MASKED
;
4039 u
->fragment_mtime
= 0;
4041 u
->load_state
= UNIT_LOADED
;
4042 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4044 /* Now, parse the file contents */
4045 r
= config_parse(u
->id
, filename
, f
,
4046 UNIT_VTABLE(u
)->sections
,
4047 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4048 false, true, false, u
);
4053 free(u
->fragment_path
);
4054 u
->fragment_path
= filename
;
4057 if (u
->source_path
) {
4058 if (stat(u
->source_path
, &st
) >= 0)
4059 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4061 u
->source_mtime
= 0;
4067 int unit_load_fragment(Unit
*u
) {
4073 assert(u
->load_state
== UNIT_STUB
);
4077 u
->load_state
= UNIT_LOADED
;
4081 /* First, try to find the unit under its id. We always look
4082 * for unit files in the default directories, to make it easy
4083 * to override things by placing things in /etc/systemd/system */
4084 r
= load_from_path(u
, u
->id
);
4088 /* Try to find an alias we can load this with */
4089 if (u
->load_state
== UNIT_STUB
) {
4090 SET_FOREACH(t
, u
->names
, i
) {
4095 r
= load_from_path(u
, t
);
4099 if (u
->load_state
!= UNIT_STUB
)
4104 /* And now, try looking for it under the suggested (originally linked) path */
4105 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4107 r
= load_from_path(u
, u
->fragment_path
);
4111 if (u
->load_state
== UNIT_STUB
)
4112 /* Hmm, this didn't work? Then let's get rid
4113 * of the fragment path stored for us, so that
4114 * we don't point to an invalid location. */
4115 u
->fragment_path
= mfree(u
->fragment_path
);
4118 /* Look for a template */
4119 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4120 _cleanup_free_
char *k
= NULL
;
4122 r
= unit_name_template(u
->id
, &k
);
4126 r
= load_from_path(u
, k
);
4130 if (u
->load_state
== UNIT_STUB
) {
4131 SET_FOREACH(t
, u
->names
, i
) {
4132 _cleanup_free_
char *z
= NULL
;
4137 r
= unit_name_template(t
, &z
);
4141 r
= load_from_path(u
, z
);
4145 if (u
->load_state
!= UNIT_STUB
)
4154 void unit_dump_config_items(FILE *f
) {
4155 static const struct {
4156 const ConfigParserCallback callback
;
4159 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4160 { config_parse_warn_compat
, "NOTSUPPORTED" },
4162 { config_parse_int
, "INTEGER" },
4163 { config_parse_unsigned
, "UNSIGNED" },
4164 { config_parse_iec_size
, "SIZE" },
4165 { config_parse_iec_uint64
, "SIZE" },
4166 { config_parse_si_size
, "SIZE" },
4167 { config_parse_bool
, "BOOLEAN" },
4168 { config_parse_string
, "STRING" },
4169 { config_parse_path
, "PATH" },
4170 { config_parse_unit_path_printf
, "PATH" },
4171 { config_parse_strv
, "STRING [...]" },
4172 { config_parse_exec_nice
, "NICE" },
4173 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4174 { config_parse_exec_io_class
, "IOCLASS" },
4175 { config_parse_exec_io_priority
, "IOPRIORITY" },
4176 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4177 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4178 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4179 { config_parse_mode
, "MODE" },
4180 { config_parse_unit_env_file
, "FILE" },
4181 { config_parse_output
, "OUTPUT" },
4182 { config_parse_input
, "INPUT" },
4183 { config_parse_log_facility
, "FACILITY" },
4184 { config_parse_log_level
, "LEVEL" },
4185 { config_parse_exec_secure_bits
, "SECUREBITS" },
4186 { config_parse_capability_set
, "BOUNDINGSET" },
4187 { config_parse_limit
, "LIMIT" },
4188 { config_parse_unit_deps
, "UNIT [...]" },
4189 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4190 { config_parse_service_type
, "SERVICETYPE" },
4191 { config_parse_service_restart
, "SERVICERESTART" },
4192 #ifdef HAVE_SYSV_COMPAT
4193 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4195 { config_parse_kill_mode
, "KILLMODE" },
4196 { config_parse_signal
, "SIGNAL" },
4197 { config_parse_socket_listen
, "SOCKET [...]" },
4198 { config_parse_socket_bind
, "SOCKETBIND" },
4199 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4200 { config_parse_sec
, "SECONDS" },
4201 { config_parse_nsec
, "NANOSECONDS" },
4202 { config_parse_namespace_path_strv
, "PATH [...]" },
4203 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4204 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4205 { config_parse_unit_string_printf
, "STRING" },
4206 { config_parse_trigger_unit
, "UNIT" },
4207 { config_parse_timer
, "TIMER" },
4208 { config_parse_path_spec
, "PATH" },
4209 { config_parse_notify_access
, "ACCESS" },
4210 { config_parse_ip_tos
, "TOS" },
4211 { config_parse_unit_condition_path
, "CONDITION" },
4212 { config_parse_unit_condition_string
, "CONDITION" },
4213 { config_parse_unit_condition_null
, "CONDITION" },
4214 { config_parse_unit_slice
, "SLICE" },
4215 { config_parse_documentation
, "URL" },
4216 { config_parse_service_timeout
, "SECONDS" },
4217 { config_parse_failure_action
, "ACTION" },
4218 { config_parse_set_status
, "STATUS" },
4219 { config_parse_service_sockets
, "SOCKETS" },
4220 { config_parse_environ
, "ENVIRON" },
4222 { config_parse_syscall_filter
, "SYSCALLS" },
4223 { config_parse_syscall_archs
, "ARCHS" },
4224 { config_parse_syscall_errno
, "ERRNO" },
4225 { config_parse_address_families
, "FAMILIES" },
4227 { config_parse_cpu_shares
, "SHARES" },
4228 { config_parse_cpu_weight
, "WEIGHT" },
4229 { config_parse_memory_limit
, "LIMIT" },
4230 { config_parse_device_allow
, "DEVICE" },
4231 { config_parse_device_policy
, "POLICY" },
4232 { config_parse_io_limit
, "LIMIT" },
4233 { config_parse_io_weight
, "WEIGHT" },
4234 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4235 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4236 { config_parse_blockio_weight
, "WEIGHT" },
4237 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4238 { config_parse_long
, "LONG" },
4239 { config_parse_socket_service
, "SERVICE" },
4241 { config_parse_exec_selinux_context
, "LABEL" },
4243 { config_parse_job_mode
, "MODE" },
4244 { config_parse_job_mode_isolate
, "BOOLEAN" },
4245 { config_parse_personality
, "PERSONALITY" },
4248 const char *prev
= NULL
;
4253 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4254 const char *rvalue
= "OTHER", *lvalue
;
4258 const ConfigPerfItem
*p
;
4260 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4262 dot
= strchr(i
, '.');
4263 lvalue
= dot
? dot
+ 1 : i
;
4267 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4271 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4274 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4275 if (p
->parse
== table
[j
].callback
) {
4276 rvalue
= table
[j
].rvalue
;
4280 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);