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
, u
;
3005 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
3006 *tasks_max
= (uint64_t) -1;
3010 r
= parse_percent(rvalue
);
3012 r
= safe_atou64(rvalue
, &u
);
3014 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3018 u
= system_tasks_max_scale(r
, 100U);
3020 if (u
<= 0 || u
>= UINT64_MAX
) {
3021 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3029 int config_parse_device_allow(
3031 const char *filename
,
3033 const char *section
,
3034 unsigned section_line
,
3041 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3042 CGroupContext
*c
= data
;
3043 CGroupDeviceAllow
*a
;
3044 const char *m
= NULL
;
3048 if (isempty(rvalue
)) {
3049 while (c
->device_allow
)
3050 cgroup_context_free_device_allow(c
, c
->device_allow
);
3055 r
= unit_full_printf(userdata
, rvalue
, &t
);
3057 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3058 "Failed to resolve specifiers in %s, ignoring: %m",
3062 n
= strcspn(t
, WHITESPACE
);
3064 path
= strndup(t
, n
);
3068 if (!startswith(path
, "/dev/") &&
3069 !startswith(path
, "block-") &&
3070 !startswith(path
, "char-")) {
3071 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3075 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3079 if (!in_charset(m
, "rwm")) {
3080 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3084 a
= new0(CGroupDeviceAllow
, 1);
3090 a
->r
= !!strchr(m
, 'r');
3091 a
->w
= !!strchr(m
, 'w');
3092 a
->m
= !!strchr(m
, 'm');
3094 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3098 int config_parse_io_weight(
3100 const char *filename
,
3102 const char *section
,
3103 unsigned section_line
,
3110 uint64_t *weight
= data
;
3117 r
= cg_weight_parse(rvalue
, weight
);
3119 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3126 int config_parse_io_device_weight(
3128 const char *filename
,
3130 const char *section
,
3131 unsigned section_line
,
3138 _cleanup_free_
char *path
= NULL
;
3139 CGroupIODeviceWeight
*w
;
3140 CGroupContext
*c
= data
;
3150 if (isempty(rvalue
)) {
3151 while (c
->io_device_weights
)
3152 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3157 n
= strcspn(rvalue
, WHITESPACE
);
3158 weight
= rvalue
+ n
;
3159 weight
+= strspn(weight
, WHITESPACE
);
3161 if (isempty(weight
)) {
3162 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3166 path
= strndup(rvalue
, n
);
3170 if (!path_startswith(path
, "/dev")) {
3171 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3175 r
= cg_weight_parse(weight
, &u
);
3177 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3181 assert(u
!= CGROUP_WEIGHT_INVALID
);
3183 w
= new0(CGroupIODeviceWeight
, 1);
3192 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3196 int config_parse_io_limit(
3198 const char *filename
,
3200 const char *section
,
3201 unsigned section_line
,
3208 _cleanup_free_
char *path
= NULL
;
3209 CGroupIODeviceLimit
*l
= NULL
, *t
;
3210 CGroupContext
*c
= data
;
3211 CGroupIOLimitType type
;
3221 type
= cgroup_io_limit_type_from_string(lvalue
);
3224 if (isempty(rvalue
)) {
3225 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3226 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3230 n
= strcspn(rvalue
, WHITESPACE
);
3232 limit
+= strspn(limit
, WHITESPACE
);
3235 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3239 path
= strndup(rvalue
, n
);
3243 if (!path_startswith(path
, "/dev")) {
3244 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3248 if (streq("infinity", limit
)) {
3249 num
= CGROUP_LIMIT_MAX
;
3251 r
= parse_size(limit
, 1000, &num
);
3252 if (r
< 0 || num
<= 0) {
3253 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3258 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3259 if (path_equal(path
, t
->path
)) {
3266 CGroupIOLimitType ttype
;
3268 l
= new0(CGroupIODeviceLimit
, 1);
3274 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3275 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3277 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3280 l
->limits
[type
] = num
;
3285 int config_parse_blockio_weight(
3287 const char *filename
,
3289 const char *section
,
3290 unsigned section_line
,
3297 uint64_t *weight
= data
;
3304 r
= cg_blkio_weight_parse(rvalue
, weight
);
3306 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3313 int config_parse_blockio_device_weight(
3315 const char *filename
,
3317 const char *section
,
3318 unsigned section_line
,
3325 _cleanup_free_
char *path
= NULL
;
3326 CGroupBlockIODeviceWeight
*w
;
3327 CGroupContext
*c
= data
;
3337 if (isempty(rvalue
)) {
3338 while (c
->blockio_device_weights
)
3339 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3344 n
= strcspn(rvalue
, WHITESPACE
);
3345 weight
= rvalue
+ n
;
3346 weight
+= strspn(weight
, WHITESPACE
);
3348 if (isempty(weight
)) {
3349 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3353 path
= strndup(rvalue
, n
);
3357 if (!path_startswith(path
, "/dev")) {
3358 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3362 r
= cg_blkio_weight_parse(weight
, &u
);
3364 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3368 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3370 w
= new0(CGroupBlockIODeviceWeight
, 1);
3379 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3383 int config_parse_blockio_bandwidth(
3385 const char *filename
,
3387 const char *section
,
3388 unsigned section_line
,
3395 _cleanup_free_
char *path
= NULL
;
3396 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3397 CGroupContext
*c
= data
;
3398 const char *bandwidth
;
3408 read
= streq("BlockIOReadBandwidth", lvalue
);
3410 if (isempty(rvalue
)) {
3411 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3412 b
->rbps
= CGROUP_LIMIT_MAX
;
3413 b
->wbps
= CGROUP_LIMIT_MAX
;
3418 n
= strcspn(rvalue
, WHITESPACE
);
3419 bandwidth
= rvalue
+ n
;
3420 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3423 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3427 path
= strndup(rvalue
, n
);
3431 if (!path_startswith(path
, "/dev")) {
3432 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3436 r
= parse_size(bandwidth
, 1000, &bytes
);
3437 if (r
< 0 || bytes
<= 0) {
3438 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3442 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3443 if (path_equal(path
, t
->path
)) {
3450 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3456 b
->rbps
= CGROUP_LIMIT_MAX
;
3457 b
->wbps
= CGROUP_LIMIT_MAX
;
3459 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3470 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3472 int config_parse_job_mode_isolate(
3474 const char *filename
,
3476 const char *section
,
3477 unsigned section_line
,
3491 r
= parse_boolean(rvalue
);
3493 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3497 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3501 int config_parse_runtime_directory(
3503 const char *filename
,
3505 const char *section
,
3506 unsigned section_line
,
3515 const char *word
, *state
;
3524 if (isempty(rvalue
)) {
3525 /* Empty assignment resets the list */
3526 *rt
= strv_free(*rt
);
3530 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3531 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3533 t
= strndup(word
, l
);
3537 r
= unit_name_printf(u
, t
, &n
);
3539 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3543 if (!filename_is_valid(n
)) {
3544 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3548 r
= strv_push(rt
, n
);
3554 if (!isempty(state
))
3555 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3560 int config_parse_set_status(
3562 const char *filename
,
3564 const char *section
,
3565 unsigned section_line
,
3573 const char *word
, *state
;
3575 ExitStatusSet
*status_set
= data
;
3582 /* Empty assignment resets the list */
3583 if (isempty(rvalue
)) {
3584 exit_status_set_free(status_set
);
3588 FOREACH_WORD(word
, l
, rvalue
, state
) {
3589 _cleanup_free_
char *temp
;
3593 temp
= strndup(word
, l
);
3597 r
= safe_atoi(temp
, &val
);
3599 val
= signal_from_string_try_harder(temp
);
3602 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3605 set
= &status_set
->signal
;
3607 if (val
< 0 || val
> 255) {
3608 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3611 set
= &status_set
->status
;
3614 r
= set_ensure_allocated(set
, NULL
);
3618 r
= set_put(*set
, INT_TO_PTR(val
));
3620 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3624 if (!isempty(state
))
3625 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3630 int config_parse_namespace_path_strv(
3632 const char *filename
,
3634 const char *section
,
3635 unsigned section_line
,
3652 if (isempty(rvalue
)) {
3653 /* Empty assignment resets the list */
3654 *sv
= strv_free(*sv
);
3658 prev
= cur
= rvalue
;
3660 _cleanup_free_
char *word
= NULL
;
3663 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3669 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3673 if (!utf8_is_valid(word
)) {
3674 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3679 offset
= word
[0] == '-';
3680 if (!path_is_absolute(word
+ offset
)) {
3681 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3686 path_kill_slashes(word
+ offset
);
3688 r
= strv_push(sv
, word
);
3699 int config_parse_no_new_privileges(
3701 const char *filename
,
3703 const char *section
,
3704 unsigned section_line
,
3711 ExecContext
*c
= data
;
3719 k
= parse_boolean(rvalue
);
3721 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3725 c
->no_new_privileges
= !!k
;
3726 c
->no_new_privileges_set
= true;
3731 int config_parse_protect_home(
3733 const char *filename
,
3735 const char *section
,
3736 unsigned section_line
,
3743 ExecContext
*c
= data
;
3751 /* Our enum shall be a superset of booleans, hence first try
3752 * to parse as boolean, and then as enum */
3754 k
= parse_boolean(rvalue
);
3756 c
->protect_home
= PROTECT_HOME_YES
;
3758 c
->protect_home
= PROTECT_HOME_NO
;
3762 h
= protect_home_from_string(rvalue
);
3764 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3768 c
->protect_home
= h
;
3774 int config_parse_protect_system(
3776 const char *filename
,
3778 const char *section
,
3779 unsigned section_line
,
3786 ExecContext
*c
= data
;
3794 /* Our enum shall be a superset of booleans, hence first try
3795 * to parse as boolean, and then as enum */
3797 k
= parse_boolean(rvalue
);
3799 c
->protect_system
= PROTECT_SYSTEM_YES
;
3801 c
->protect_system
= PROTECT_SYSTEM_NO
;
3805 s
= protect_system_from_string(rvalue
);
3807 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3811 c
->protect_system
= s
;
3817 #define FOLLOW_MAX 8
3819 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3830 /* This will update the filename pointer if the loaded file is
3831 * reached by a symlink. The old string will be freed. */
3834 char *target
, *name
;
3836 if (c
++ >= FOLLOW_MAX
)
3839 path_kill_slashes(*filename
);
3841 /* Add the file name we are currently looking at to
3842 * the names of this unit, but only if it is a valid
3844 name
= basename(*filename
);
3845 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3847 id
= set_get(names
, name
);
3853 r
= set_consume(names
, id
);
3859 /* Try to open the file name, but don't if its a symlink */
3860 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3867 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3868 r
= readlink_and_make_absolute(*filename
, &target
);
3876 f
= fdopen(fd
, "re");
3888 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
3896 /* Let's try to add in all symlink names we found */
3897 while ((k
= set_steal_first(names
))) {
3899 /* First try to merge in the other name into our
3901 r
= unit_merge_by_name(*u
, k
);
3905 /* Hmm, we couldn't merge the other unit into
3906 * ours? Then let's try it the other way
3909 /* If the symlink name we are looking at is unit template, then
3910 we must search for instance of this template */
3911 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
3912 _cleanup_free_
char *instance
= NULL
;
3914 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
3918 other
= manager_get_unit((*u
)->manager
, instance
);
3920 other
= manager_get_unit((*u
)->manager
, k
);
3925 r
= unit_merge(other
, *u
);
3928 return merge_by_names(u
, names
, NULL
);
3936 unit_choose_id(*u
, id
);
3944 static int load_from_path(Unit
*u
, const char *path
) {
3945 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
3946 _cleanup_fclose_
FILE *f
= NULL
;
3947 _cleanup_free_
char *filename
= NULL
;
3956 symlink_names
= set_new(&string_hash_ops
);
3960 if (path_is_absolute(path
)) {
3962 filename
= strdup(path
);
3966 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3968 filename
= mfree(filename
);
3976 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
3978 /* Instead of opening the path right away, we manually
3979 * follow all symlinks and add their name to our unit
3980 * name set while doing so */
3981 filename
= path_make_absolute(path
, *p
);
3985 if (u
->manager
->unit_path_cache
&&
3986 !set_get(u
->manager
->unit_path_cache
, filename
))
3989 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3992 filename
= mfree(filename
);
3994 /* ENOENT means that the file is missing or is a dangling symlink.
3995 * ENOTDIR means that one of paths we expect to be is a directory
3996 * is not a directory, we should just ignore that.
3997 * EACCES means that the directory or file permissions are wrong.
4000 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4001 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4004 /* Empty the symlink names for the next run */
4005 set_clear_free(symlink_names
);
4010 /* Hmm, no suitable file found? */
4013 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4014 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4019 r
= merge_by_names(&merged
, symlink_names
, id
);
4024 u
->load_state
= UNIT_MERGED
;
4028 if (fstat(fileno(f
), &st
) < 0)
4031 if (null_or_empty(&st
)) {
4032 u
->load_state
= UNIT_MASKED
;
4033 u
->fragment_mtime
= 0;
4035 u
->load_state
= UNIT_LOADED
;
4036 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4038 /* Now, parse the file contents */
4039 r
= config_parse(u
->id
, filename
, f
,
4040 UNIT_VTABLE(u
)->sections
,
4041 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4042 false, true, false, u
);
4047 free(u
->fragment_path
);
4048 u
->fragment_path
= filename
;
4051 if (u
->source_path
) {
4052 if (stat(u
->source_path
, &st
) >= 0)
4053 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4055 u
->source_mtime
= 0;
4061 int unit_load_fragment(Unit
*u
) {
4067 assert(u
->load_state
== UNIT_STUB
);
4071 u
->load_state
= UNIT_LOADED
;
4075 /* First, try to find the unit under its id. We always look
4076 * for unit files in the default directories, to make it easy
4077 * to override things by placing things in /etc/systemd/system */
4078 r
= load_from_path(u
, u
->id
);
4082 /* Try to find an alias we can load this with */
4083 if (u
->load_state
== UNIT_STUB
) {
4084 SET_FOREACH(t
, u
->names
, i
) {
4089 r
= load_from_path(u
, t
);
4093 if (u
->load_state
!= UNIT_STUB
)
4098 /* And now, try looking for it under the suggested (originally linked) path */
4099 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4101 r
= load_from_path(u
, u
->fragment_path
);
4105 if (u
->load_state
== UNIT_STUB
)
4106 /* Hmm, this didn't work? Then let's get rid
4107 * of the fragment path stored for us, so that
4108 * we don't point to an invalid location. */
4109 u
->fragment_path
= mfree(u
->fragment_path
);
4112 /* Look for a template */
4113 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4114 _cleanup_free_
char *k
= NULL
;
4116 r
= unit_name_template(u
->id
, &k
);
4120 r
= load_from_path(u
, k
);
4124 if (u
->load_state
== UNIT_STUB
) {
4125 SET_FOREACH(t
, u
->names
, i
) {
4126 _cleanup_free_
char *z
= NULL
;
4131 r
= unit_name_template(t
, &z
);
4135 r
= load_from_path(u
, z
);
4139 if (u
->load_state
!= UNIT_STUB
)
4148 void unit_dump_config_items(FILE *f
) {
4149 static const struct {
4150 const ConfigParserCallback callback
;
4153 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4154 { config_parse_warn_compat
, "NOTSUPPORTED" },
4156 { config_parse_int
, "INTEGER" },
4157 { config_parse_unsigned
, "UNSIGNED" },
4158 { config_parse_iec_size
, "SIZE" },
4159 { config_parse_iec_uint64
, "SIZE" },
4160 { config_parse_si_size
, "SIZE" },
4161 { config_parse_bool
, "BOOLEAN" },
4162 { config_parse_string
, "STRING" },
4163 { config_parse_path
, "PATH" },
4164 { config_parse_unit_path_printf
, "PATH" },
4165 { config_parse_strv
, "STRING [...]" },
4166 { config_parse_exec_nice
, "NICE" },
4167 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4168 { config_parse_exec_io_class
, "IOCLASS" },
4169 { config_parse_exec_io_priority
, "IOPRIORITY" },
4170 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4171 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4172 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4173 { config_parse_mode
, "MODE" },
4174 { config_parse_unit_env_file
, "FILE" },
4175 { config_parse_output
, "OUTPUT" },
4176 { config_parse_input
, "INPUT" },
4177 { config_parse_log_facility
, "FACILITY" },
4178 { config_parse_log_level
, "LEVEL" },
4179 { config_parse_exec_secure_bits
, "SECUREBITS" },
4180 { config_parse_capability_set
, "BOUNDINGSET" },
4181 { config_parse_limit
, "LIMIT" },
4182 { config_parse_unit_deps
, "UNIT [...]" },
4183 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4184 { config_parse_service_type
, "SERVICETYPE" },
4185 { config_parse_service_restart
, "SERVICERESTART" },
4186 #ifdef HAVE_SYSV_COMPAT
4187 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4189 { config_parse_kill_mode
, "KILLMODE" },
4190 { config_parse_signal
, "SIGNAL" },
4191 { config_parse_socket_listen
, "SOCKET [...]" },
4192 { config_parse_socket_bind
, "SOCKETBIND" },
4193 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4194 { config_parse_sec
, "SECONDS" },
4195 { config_parse_nsec
, "NANOSECONDS" },
4196 { config_parse_namespace_path_strv
, "PATH [...]" },
4197 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4198 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4199 { config_parse_unit_string_printf
, "STRING" },
4200 { config_parse_trigger_unit
, "UNIT" },
4201 { config_parse_timer
, "TIMER" },
4202 { config_parse_path_spec
, "PATH" },
4203 { config_parse_notify_access
, "ACCESS" },
4204 { config_parse_ip_tos
, "TOS" },
4205 { config_parse_unit_condition_path
, "CONDITION" },
4206 { config_parse_unit_condition_string
, "CONDITION" },
4207 { config_parse_unit_condition_null
, "CONDITION" },
4208 { config_parse_unit_slice
, "SLICE" },
4209 { config_parse_documentation
, "URL" },
4210 { config_parse_service_timeout
, "SECONDS" },
4211 { config_parse_failure_action
, "ACTION" },
4212 { config_parse_set_status
, "STATUS" },
4213 { config_parse_service_sockets
, "SOCKETS" },
4214 { config_parse_environ
, "ENVIRON" },
4216 { config_parse_syscall_filter
, "SYSCALLS" },
4217 { config_parse_syscall_archs
, "ARCHS" },
4218 { config_parse_syscall_errno
, "ERRNO" },
4219 { config_parse_address_families
, "FAMILIES" },
4221 { config_parse_cpu_shares
, "SHARES" },
4222 { config_parse_cpu_weight
, "WEIGHT" },
4223 { config_parse_memory_limit
, "LIMIT" },
4224 { config_parse_device_allow
, "DEVICE" },
4225 { config_parse_device_policy
, "POLICY" },
4226 { config_parse_io_limit
, "LIMIT" },
4227 { config_parse_io_weight
, "WEIGHT" },
4228 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4229 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4230 { config_parse_blockio_weight
, "WEIGHT" },
4231 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4232 { config_parse_long
, "LONG" },
4233 { config_parse_socket_service
, "SERVICE" },
4235 { config_parse_exec_selinux_context
, "LABEL" },
4237 { config_parse_job_mode
, "MODE" },
4238 { config_parse_job_mode_isolate
, "BOOLEAN" },
4239 { config_parse_personality
, "PERSONALITY" },
4242 const char *prev
= NULL
;
4247 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4248 const char *rvalue
= "OTHER", *lvalue
;
4252 const ConfigPerfItem
*p
;
4254 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4256 dot
= strchr(i
, '.');
4257 lvalue
= dot
? dot
+ 1 : i
;
4261 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4265 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4268 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4269 if (p
->parse
== table
[j
].callback
) {
4270 rvalue
= table
[j
].rvalue
;
4274 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);