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"
70 int config_parse_warn_compat(
75 unsigned section_line
,
81 Disabled reason
= ltype
;
84 case DISABLED_CONFIGURATION
:
85 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
86 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
89 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
90 "Support for option %s= has been removed and it is ignored", lvalue
);
92 case DISABLED_EXPERIMENTAL
:
93 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
94 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
101 int config_parse_unit_deps(
103 const char *filename
,
106 unsigned section_line
,
113 UnitDependency d
= ltype
;
123 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
126 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
132 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
136 r
= unit_name_printf(u
, word
, &k
);
138 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
142 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
144 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
150 int config_parse_obsolete_unit_deps(
152 const char *filename
,
155 unsigned section_line
,
162 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
163 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
165 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
168 int config_parse_unit_string_printf(
170 const char *filename
,
173 unsigned section_line
,
180 _cleanup_free_
char *k
= NULL
;
189 r
= unit_full_printf(u
, rvalue
, &k
);
191 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
195 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
198 int config_parse_unit_strv_printf(
200 const char *filename
,
203 unsigned section_line
,
211 _cleanup_free_
char *k
= NULL
;
219 r
= unit_full_printf(u
, rvalue
, &k
);
221 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
225 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
228 int config_parse_unit_path_printf(
230 const char *filename
,
233 unsigned section_line
,
240 _cleanup_free_
char *k
= NULL
;
249 r
= unit_full_printf(u
, rvalue
, &k
);
251 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
255 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
258 int config_parse_unit_path_strv_printf(
260 const char *filename
,
263 unsigned section_line
,
271 const char *word
, *state
;
281 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
282 _cleanup_free_
char *k
= NULL
;
288 r
= unit_full_printf(u
, t
, &k
);
290 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", t
);
294 if (!utf8_is_valid(k
)) {
295 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
299 if (!path_is_absolute(k
)) {
300 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Symlink path %s is not absolute, ignoring: %m", k
);
304 path_kill_slashes(k
);
313 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, ignoring.");
318 int config_parse_socket_listen(const char *unit
,
319 const char *filename
,
322 unsigned section_line
,
329 _cleanup_free_ SocketPort
*p
= NULL
;
341 if (isempty(rvalue
)) {
342 /* An empty assignment removes all ports */
343 socket_free_ports(s
);
347 p
= new0(SocketPort
, 1);
351 if (ltype
!= SOCKET_SOCKET
) {
354 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
356 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
360 path_kill_slashes(p
->path
);
362 } else if (streq(lvalue
, "ListenNetlink")) {
363 _cleanup_free_
char *k
= NULL
;
365 p
->type
= SOCKET_SOCKET
;
366 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
368 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
372 r
= socket_address_parse_netlink(&p
->address
, k
);
374 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
379 _cleanup_free_
char *k
= NULL
;
381 p
->type
= SOCKET_SOCKET
;
382 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
384 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
388 r
= socket_address_parse_and_warn(&p
->address
, k
);
390 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
394 if (streq(lvalue
, "ListenStream"))
395 p
->address
.type
= SOCK_STREAM
;
396 else if (streq(lvalue
, "ListenDatagram"))
397 p
->address
.type
= SOCK_DGRAM
;
399 assert(streq(lvalue
, "ListenSequentialPacket"));
400 p
->address
.type
= SOCK_SEQPACKET
;
403 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
404 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
410 p
->auxiliary_fds
= NULL
;
411 p
->n_auxiliary_fds
= 0;
415 LIST_FIND_TAIL(port
, s
->ports
, tail
);
416 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
418 LIST_PREPEND(port
, s
->ports
, p
);
424 int config_parse_socket_protocol(const char *unit
,
425 const char *filename
,
428 unsigned section_line
,
443 if (streq(rvalue
, "udplite"))
444 s
->socket_protocol
= IPPROTO_UDPLITE
;
445 else if (streq(rvalue
, "sctp"))
446 s
->socket_protocol
= IPPROTO_SCTP
;
448 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
455 int config_parse_socket_bind(const char *unit
,
456 const char *filename
,
459 unsigned section_line
,
467 SocketAddressBindIPv6Only b
;
476 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
480 r
= parse_boolean(rvalue
);
482 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
486 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
488 s
->bind_ipv6_only
= b
;
493 int config_parse_exec_nice(const char *unit
,
494 const char *filename
,
497 unsigned section_line
,
504 ExecContext
*c
= data
;
512 r
= safe_atoi(rvalue
, &priority
);
514 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
518 if (priority
< PRIO_MIN
|| priority
>= PRIO_MAX
) {
519 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Nice priority out of range, ignoring: %s", rvalue
);
529 int config_parse_exec_oom_score_adjust(const char* unit
,
530 const char *filename
,
533 unsigned section_line
,
540 ExecContext
*c
= data
;
548 r
= safe_atoi(rvalue
, &oa
);
550 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
554 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
555 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
559 c
->oom_score_adjust
= oa
;
560 c
->oom_score_adjust_set
= true;
565 int config_parse_exec(
567 const char *filename
,
570 unsigned section_line
,
577 ExecCommand
**e
= data
;
588 rvalue
+= strspn(rvalue
, WHITESPACE
);
590 if (isempty(rvalue
)) {
591 /* An empty assignment resets the list */
592 *e
= exec_command_free_list(*e
);
598 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
599 bool separate_argv0
= false, ignore
= false, privileged
= false;
600 _cleanup_free_ ExecCommand
*nce
= NULL
;
601 _cleanup_strv_free_
char **n
= NULL
;
602 size_t nlen
= 0, nbufsize
= 0;
608 r
= extract_first_word_and_warn(&p
, &firstword
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
613 for (i
= 0; i
< 3; i
++) {
614 /* We accept an absolute path as first argument.
615 * If it's prefixed with - and the path doesn't exist,
616 * we ignore it instead of erroring out;
617 * if it's prefixed with @, we allow overriding of argv[0];
618 * and if it's prefixed with !, it will be run with full privileges */
619 if (*f
== '-' && !ignore
)
621 else if (*f
== '@' && !separate_argv0
)
622 separate_argv0
= true;
623 else if (*f
== '!' && !privileged
)
631 /* First word is either "-" or "@" with no command. */
632 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty path in command line, ignoring: \"%s\"", rvalue
);
635 if (!string_is_safe(f
)) {
636 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path contains special characters, ignoring: %s", rvalue
);
639 if (!path_is_absolute(f
)) {
640 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path is not absolute, ignoring: %s", rvalue
);
643 if (endswith(f
, "/")) {
644 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path specifies a directory, ignoring: %s", rvalue
);
648 if (f
== firstword
) {
657 if (!separate_argv0
) {
658 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
667 path_kill_slashes(path
);
669 while (!isempty(p
)) {
670 _cleanup_free_
char *word
= NULL
;
672 /* Check explicitly for an unquoted semicolon as
673 * command separator token. */
674 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
676 p
+= strspn(p
, WHITESPACE
);
681 /* Check for \; explicitly, to not confuse it with \\;
682 * or "\;" or "\\;" etc. extract_first_word would
683 * return the same for all of those. */
684 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
686 p
+= strspn(p
, WHITESPACE
);
687 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
697 r
= extract_first_word_and_warn(&p
, &word
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
703 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
711 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue
);
715 nce
= new0(ExecCommand
, 1);
721 nce
->ignore
= ignore
;
722 nce
->privileged
= privileged
;
724 exec_command_append_list(e
, nce
);
726 /* Do not _cleanup_free_ these. */
737 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
738 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
740 int config_parse_socket_bindtodevice(
742 const char *filename
,
745 unsigned section_line
,
760 if (rvalue
[0] && !streq(rvalue
, "*")) {
761 if (!ifname_valid(rvalue
)) {
762 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
772 free(s
->bind_to_device
);
773 s
->bind_to_device
= n
;
778 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
779 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
781 int config_parse_exec_io_class(const char *unit
,
782 const char *filename
,
785 unsigned section_line
,
792 ExecContext
*c
= data
;
800 x
= ioprio_class_from_string(rvalue
);
802 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
806 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
807 c
->ioprio_set
= true;
812 int config_parse_exec_io_priority(const char *unit
,
813 const char *filename
,
816 unsigned section_line
,
823 ExecContext
*c
= data
;
831 r
= safe_atoi(rvalue
, &i
);
832 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
833 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
837 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
838 c
->ioprio_set
= true;
843 int config_parse_exec_cpu_sched_policy(const char *unit
,
844 const char *filename
,
847 unsigned section_line
,
855 ExecContext
*c
= data
;
863 x
= sched_policy_from_string(rvalue
);
865 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
869 c
->cpu_sched_policy
= x
;
870 /* Moving to or from real-time policy? We need to adjust the priority */
871 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
872 c
->cpu_sched_set
= true;
877 int config_parse_exec_cpu_sched_prio(const char *unit
,
878 const char *filename
,
881 unsigned section_line
,
888 ExecContext
*c
= data
;
896 r
= safe_atoi(rvalue
, &i
);
898 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
902 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
903 min
= sched_get_priority_min(c
->cpu_sched_policy
);
904 max
= sched_get_priority_max(c
->cpu_sched_policy
);
906 if (i
< min
|| i
> max
) {
907 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
911 c
->cpu_sched_priority
= i
;
912 c
->cpu_sched_set
= true;
917 int config_parse_exec_cpu_affinity(const char *unit
,
918 const char *filename
,
921 unsigned section_line
,
928 ExecContext
*c
= data
;
929 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
937 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
945 /* An empty assignment resets the CPU list */
951 c
->cpuset_ncpus
= ncpus
;
956 int config_parse_exec_secure_bits(const char *unit
,
957 const char *filename
,
960 unsigned section_line
,
967 ExecContext
*c
= data
;
969 const char *word
, *state
;
976 if (isempty(rvalue
)) {
977 /* An empty assignment resets the field */
982 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
983 if (first_word(word
, "keep-caps"))
984 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
985 else if (first_word(word
, "keep-caps-locked"))
986 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
987 else if (first_word(word
, "no-setuid-fixup"))
988 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
989 else if (first_word(word
, "no-setuid-fixup-locked"))
990 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
991 else if (first_word(word
, "noroot"))
992 c
->secure_bits
|= 1<<SECURE_NOROOT
;
993 else if (first_word(word
, "noroot-locked"))
994 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
996 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse secure bits, ignoring: %s", rvalue
);
1000 if (!isempty(state
))
1001 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, garbage at the end, ignoring.");
1006 int config_parse_capability_set(
1008 const char *filename
,
1010 const char *section
,
1011 unsigned section_line
,
1018 uint64_t *capability_set
= data
;
1019 uint64_t sum
= 0, initial
= 0;
1020 bool invert
= false;
1028 if (rvalue
[0] == '~') {
1033 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1034 initial
= CAP_ALL
; /* initialized to all bits on */
1035 /* else "AmbientCapabilities" initialized to all bits off */
1039 _cleanup_free_
char *word
= NULL
;
1042 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1048 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1052 cap
= capability_from_name(word
);
1054 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1058 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1061 sum
= invert
? ~sum
: sum
;
1063 if (sum
== 0 || *capability_set
== initial
)
1064 /* "" or uninitialized data -> replace */
1065 *capability_set
= sum
;
1067 /* previous data -> merge */
1068 *capability_set
|= sum
;
1073 int config_parse_limit(
1075 const char *filename
,
1077 const char *section
,
1078 unsigned section_line
,
1085 struct rlimit
**rl
= data
, d
= {};
1093 r
= rlimit_parse(ltype
, rvalue
, &d
);
1095 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1099 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1106 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1114 #ifdef HAVE_SYSV_COMPAT
1115 int config_parse_sysv_priority(const char *unit
,
1116 const char *filename
,
1118 const char *section
,
1119 unsigned section_line
,
1126 int *priority
= data
;
1134 r
= safe_atoi(rvalue
, &i
);
1135 if (r
< 0 || i
< 0) {
1136 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1140 *priority
= (int) i
;
1145 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1146 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1148 int config_parse_exec_mount_flags(const char *unit
,
1149 const char *filename
,
1151 const char *section
,
1152 unsigned section_line
,
1160 unsigned long flags
= 0;
1161 ExecContext
*c
= data
;
1168 if (streq(rvalue
, "shared"))
1170 else if (streq(rvalue
, "slave"))
1172 else if (streq(rvalue
, "private"))
1175 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1179 c
->mount_flags
= flags
;
1184 int config_parse_exec_selinux_context(
1186 const char *filename
,
1188 const char *section
,
1189 unsigned section_line
,
1196 ExecContext
*c
= data
;
1207 if (isempty(rvalue
)) {
1208 c
->selinux_context
= mfree(c
->selinux_context
);
1209 c
->selinux_context_ignore
= false;
1213 if (rvalue
[0] == '-') {
1219 r
= unit_name_printf(u
, rvalue
, &k
);
1221 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1225 free(c
->selinux_context
);
1226 c
->selinux_context
= k
;
1227 c
->selinux_context_ignore
= ignore
;
1232 int config_parse_exec_apparmor_profile(
1234 const char *filename
,
1236 const char *section
,
1237 unsigned section_line
,
1244 ExecContext
*c
= data
;
1255 if (isempty(rvalue
)) {
1256 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1257 c
->apparmor_profile_ignore
= false;
1261 if (rvalue
[0] == '-') {
1267 r
= unit_name_printf(u
, rvalue
, &k
);
1269 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1273 free(c
->apparmor_profile
);
1274 c
->apparmor_profile
= k
;
1275 c
->apparmor_profile_ignore
= ignore
;
1280 int config_parse_exec_smack_process_label(
1282 const char *filename
,
1284 const char *section
,
1285 unsigned section_line
,
1292 ExecContext
*c
= data
;
1303 if (isempty(rvalue
)) {
1304 c
->smack_process_label
= mfree(c
->smack_process_label
);
1305 c
->smack_process_label_ignore
= false;
1309 if (rvalue
[0] == '-') {
1315 r
= unit_name_printf(u
, rvalue
, &k
);
1317 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1321 free(c
->smack_process_label
);
1322 c
->smack_process_label
= k
;
1323 c
->smack_process_label_ignore
= ignore
;
1328 int config_parse_timer(const char *unit
,
1329 const char *filename
,
1331 const char *section
,
1332 unsigned section_line
,
1343 CalendarSpec
*c
= NULL
;
1350 if (isempty(rvalue
)) {
1351 /* Empty assignment resets list */
1352 timer_free_values(t
);
1356 b
= timer_base_from_string(lvalue
);
1358 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1362 if (b
== TIMER_CALENDAR
) {
1363 if (calendar_spec_from_string(rvalue
, &c
) < 0) {
1364 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", rvalue
);
1368 if (parse_sec(rvalue
, &u
) < 0) {
1369 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", rvalue
);
1374 v
= new0(TimerValue
, 1);
1376 calendar_spec_free(c
);
1382 v
->calendar_spec
= c
;
1384 LIST_PREPEND(value
, t
->values
, v
);
1389 int config_parse_trigger_unit(
1391 const char *filename
,
1393 const char *section
,
1394 unsigned section_line
,
1401 _cleanup_free_
char *p
= NULL
;
1411 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1412 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1416 r
= unit_name_printf(u
, rvalue
, &p
);
1418 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1422 type
= unit_name_to_type(p
);
1424 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1428 if (type
== u
->type
) {
1429 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1433 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1435 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1442 int config_parse_path_spec(const char *unit
,
1443 const char *filename
,
1445 const char *section
,
1446 unsigned section_line
,
1456 _cleanup_free_
char *k
= NULL
;
1464 if (isempty(rvalue
)) {
1465 /* Empty assignment clears list */
1470 b
= path_type_from_string(lvalue
);
1472 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1476 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1478 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1482 if (!path_is_absolute(k
)) {
1483 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1487 s
= new0(PathSpec
, 1);
1492 s
->path
= path_kill_slashes(k
);
1497 LIST_PREPEND(spec
, p
->specs
, s
);
1502 int config_parse_socket_service(
1504 const char *filename
,
1506 const char *section
,
1507 unsigned section_line
,
1514 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1515 _cleanup_free_
char *p
= NULL
;
1525 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1527 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1531 if (!endswith(p
, ".service")) {
1532 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1536 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1538 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1542 unit_ref_set(&s
->service
, x
);
1547 int config_parse_fdname(
1549 const char *filename
,
1551 const char *section
,
1552 unsigned section_line
,
1559 _cleanup_free_
char *p
= NULL
;
1568 if (isempty(rvalue
)) {
1569 s
->fdname
= mfree(s
->fdname
);
1573 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1575 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1579 if (!fdname_is_valid(p
)) {
1580 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1591 int config_parse_service_sockets(
1593 const char *filename
,
1595 const char *section
,
1596 unsigned section_line
,
1614 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1616 r
= extract_first_word(&p
, &word
, NULL
, 0);
1622 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1626 r
= unit_name_printf(UNIT(s
), word
, &k
);
1628 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1632 if (!endswith(k
, ".socket")) {
1633 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1637 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1639 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1641 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1643 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1649 int config_parse_bus_name(
1651 const char *filename
,
1653 const char *section
,
1654 unsigned section_line
,
1661 _cleanup_free_
char *k
= NULL
;
1670 r
= unit_full_printf(u
, rvalue
, &k
);
1672 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1676 if (!service_name_is_valid(k
)) {
1677 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1681 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1684 int config_parse_service_timeout(
1686 const char *filename
,
1688 const char *section
,
1689 unsigned section_line
,
1696 Service
*s
= userdata
;
1705 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1707 r
= parse_sec(rvalue
, &usec
);
1709 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1713 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1714 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1715 * all other timeouts. */
1717 usec
= USEC_INFINITY
;
1719 if (!streq(lvalue
, "TimeoutStopSec")) {
1720 s
->start_timeout_defined
= true;
1721 s
->timeout_start_usec
= usec
;
1724 if (!streq(lvalue
, "TimeoutStartSec"))
1725 s
->timeout_stop_usec
= usec
;
1730 int config_parse_sec_fix_0(
1732 const char *filename
,
1734 const char *section
,
1735 unsigned section_line
,
1742 usec_t
*usec
= data
;
1750 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1751 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1754 r
= parse_sec(rvalue
, usec
);
1756 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1761 *usec
= USEC_INFINITY
;
1766 int config_parse_busname_service(
1768 const char *filename
,
1770 const char *section
,
1771 unsigned section_line
,
1778 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1782 _cleanup_free_
char *p
= NULL
;
1789 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
1791 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1795 if (!endswith(p
, ".service")) {
1796 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1800 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
1802 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1806 unit_ref_set(&n
->service
, x
);
1811 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
1813 int config_parse_bus_policy(
1815 const char *filename
,
1817 const char *section
,
1818 unsigned section_line
,
1825 _cleanup_free_ BusNamePolicy
*p
= NULL
;
1826 _cleanup_free_
char *id_str
= NULL
;
1827 BusName
*busname
= data
;
1835 p
= new0(BusNamePolicy
, 1);
1839 if (streq(lvalue
, "AllowUser"))
1840 p
->type
= BUSNAME_POLICY_TYPE_USER
;
1841 else if (streq(lvalue
, "AllowGroup"))
1842 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
1844 assert_not_reached("Unknown lvalue");
1846 id_str
= strdup(rvalue
);
1850 access_str
= strpbrk(id_str
, WHITESPACE
);
1852 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
1858 access_str
+= strspn(access_str
, WHITESPACE
);
1860 p
->access
= bus_policy_access_from_string(access_str
);
1861 if (p
->access
< 0) {
1862 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
1869 LIST_PREPEND(policy
, busname
->policy
, p
);
1875 int config_parse_working_directory(
1877 const char *filename
,
1879 const char *section
,
1880 unsigned section_line
,
1887 ExecContext
*c
= data
;
1898 if (rvalue
[0] == '-') {
1904 if (streq(rvalue
, "~")) {
1905 c
->working_directory_home
= true;
1906 c
->working_directory
= mfree(c
->working_directory
);
1908 _cleanup_free_
char *k
= NULL
;
1910 r
= unit_full_printf(u
, rvalue
, &k
);
1912 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
1916 path_kill_slashes(k
);
1918 if (!utf8_is_valid(k
)) {
1919 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
1923 if (!path_is_absolute(k
)) {
1924 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
1928 free(c
->working_directory
);
1929 c
->working_directory
= k
;
1932 c
->working_directory_home
= false;
1935 c
->working_directory_missing_ok
= missing_ok
;
1939 int config_parse_unit_env_file(const char *unit
,
1940 const char *filename
,
1942 const char *section
,
1943 unsigned section_line
,
1952 _cleanup_free_
char *n
= NULL
;
1960 if (isempty(rvalue
)) {
1961 /* Empty assignment frees the list */
1962 *env
= strv_free(*env
);
1966 r
= unit_full_printf(u
, rvalue
, &n
);
1968 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1972 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
1973 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
1977 r
= strv_extend(env
, n
);
1984 int config_parse_environ(const char *unit
,
1985 const char *filename
,
1987 const char *section
,
1988 unsigned section_line
,
1997 const char *word
, *state
;
1999 _cleanup_free_
char *k
= NULL
;
2007 if (isempty(rvalue
)) {
2008 /* Empty assignment resets the list */
2009 *env
= strv_free(*env
);
2014 r
= unit_full_printf(u
, rvalue
, &k
);
2016 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2027 FOREACH_WORD_QUOTED(word
, l
, k
, state
) {
2028 _cleanup_free_
char *n
= NULL
;
2031 r
= cunescape_length(word
, l
, 0, &n
);
2033 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Couldn't unescape assignment, ignoring: %s", rvalue
);
2037 if (!env_assignment_is_valid(n
)) {
2038 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid environment assignment, ignoring: %s", rvalue
);
2042 x
= strv_env_set(*env
, n
);
2049 if (!isempty(state
))
2050 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2055 int config_parse_pass_environ(const char *unit
,
2056 const char *filename
,
2058 const char *section
,
2059 unsigned section_line
,
2066 const char *whole_rvalue
= rvalue
;
2067 char*** passenv
= data
;
2068 _cleanup_strv_free_
char **n
= NULL
;
2069 size_t nlen
= 0, nbufsize
= 0;
2077 if (isempty(rvalue
)) {
2078 /* Empty assignment resets the list */
2079 *passenv
= strv_free(*passenv
);
2084 _cleanup_free_
char *word
= NULL
;
2086 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
);
2092 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2093 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2097 if (!env_name_is_valid(word
)) {
2098 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2099 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2103 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2111 r
= strv_extend_strv(passenv
, n
, true);
2119 int config_parse_ip_tos(const char *unit
,
2120 const char *filename
,
2122 const char *section
,
2123 unsigned section_line
,
2130 int *ip_tos
= data
, x
;
2137 x
= ip_tos_from_string(rvalue
);
2139 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2147 int config_parse_unit_condition_path(
2149 const char *filename
,
2151 const char *section
,
2152 unsigned section_line
,
2159 _cleanup_free_
char *p
= NULL
;
2160 Condition
**list
= data
, *c
;
2161 ConditionType t
= ltype
;
2162 bool trigger
, negate
;
2171 if (isempty(rvalue
)) {
2172 /* Empty assignment resets the list */
2173 *list
= condition_free_list(*list
);
2177 trigger
= rvalue
[0] == '|';
2181 negate
= rvalue
[0] == '!';
2185 r
= unit_full_printf(u
, rvalue
, &p
);
2187 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2191 if (!path_is_absolute(p
)) {
2192 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2196 c
= condition_new(t
, p
, trigger
, negate
);
2200 LIST_PREPEND(conditions
, *list
, c
);
2204 int config_parse_unit_condition_string(
2206 const char *filename
,
2208 const char *section
,
2209 unsigned section_line
,
2216 _cleanup_free_
char *s
= NULL
;
2217 Condition
**list
= data
, *c
;
2218 ConditionType t
= ltype
;
2219 bool trigger
, negate
;
2228 if (isempty(rvalue
)) {
2229 /* Empty assignment resets the list */
2230 *list
= condition_free_list(*list
);
2234 trigger
= rvalue
[0] == '|';
2238 negate
= rvalue
[0] == '!';
2242 r
= unit_full_printf(u
, rvalue
, &s
);
2244 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2248 c
= condition_new(t
, s
, trigger
, negate
);
2252 LIST_PREPEND(conditions
, *list
, c
);
2256 int config_parse_unit_condition_null(
2258 const char *filename
,
2260 const char *section
,
2261 unsigned section_line
,
2268 Condition
**list
= data
, *c
;
2269 bool trigger
, negate
;
2277 if (isempty(rvalue
)) {
2278 /* Empty assignment resets the list */
2279 *list
= condition_free_list(*list
);
2283 trigger
= rvalue
[0] == '|';
2287 negate
= rvalue
[0] == '!';
2291 b
= parse_boolean(rvalue
);
2293 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2300 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2304 LIST_PREPEND(conditions
, *list
, c
);
2308 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2309 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action
, failure_action
, FailureAction
, "Failed to parse failure action specifier");
2311 int config_parse_unit_requires_mounts_for(
2313 const char *filename
,
2315 const char *section
,
2316 unsigned section_line
,
2324 const char *word
, *state
;
2332 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2334 _cleanup_free_
char *n
;
2336 n
= strndup(word
, l
);
2340 if (!utf8_is_valid(n
)) {
2341 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2345 r
= unit_require_mounts_for(u
, n
);
2347 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount for, ignoring: %s", rvalue
);
2351 if (!isempty(state
))
2352 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2357 int config_parse_documentation(const char *unit
,
2358 const char *filename
,
2360 const char *section
,
2361 unsigned section_line
,
2377 if (isempty(rvalue
)) {
2378 /* Empty assignment resets the list */
2379 u
->documentation
= strv_free(u
->documentation
);
2383 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2384 rvalue
, data
, userdata
);
2388 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2390 if (documentation_url_is_valid(*a
))
2393 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2404 static int syscall_filter_parse_one(
2406 const char *filename
,
2415 const SystemCallFilterSet
*set
;
2417 for (set
= syscall_filter_sets
; set
->set_name
; set
++)
2418 if (streq(set
->set_name
, t
)) {
2421 NULSTR_FOREACH(sys
, set
->value
) {
2422 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, sys
, false);
2431 id
= seccomp_syscall_resolve_name(t
);
2434 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2438 /* If we previously wanted to forbid a syscall and now
2439 * we want to allow it, then remove it from the list
2441 if (!invert
== c
->syscall_whitelist
) {
2442 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2448 set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2453 int config_parse_syscall_filter(
2455 const char *filename
,
2457 const char *section
,
2458 unsigned section_line
,
2465 ExecContext
*c
= data
;
2467 bool invert
= false;
2468 const char *word
, *state
;
2477 if (isempty(rvalue
)) {
2478 /* Empty assignment resets the list */
2479 c
->syscall_filter
= set_free(c
->syscall_filter
);
2480 c
->syscall_whitelist
= false;
2484 if (rvalue
[0] == '~') {
2489 if (!c
->syscall_filter
) {
2490 c
->syscall_filter
= set_new(NULL
);
2491 if (!c
->syscall_filter
)
2495 /* Allow everything but the ones listed */
2496 c
->syscall_whitelist
= false;
2498 /* Allow nothing but the ones listed */
2499 c
->syscall_whitelist
= true;
2501 /* Accept default syscalls if we are on a whitelist */
2502 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2508 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2509 _cleanup_free_
char *t
= NULL
;
2511 t
= strndup(word
, l
);
2515 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, t
, true);
2519 if (!isempty(state
))
2520 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2522 /* Turn on NNP, but only if it wasn't configured explicitly
2523 * before, and only if we are in user mode. */
2524 if (!c
->no_new_privileges_set
&& MANAGER_IS_USER(u
->manager
))
2525 c
->no_new_privileges
= true;
2530 int config_parse_syscall_archs(
2532 const char *filename
,
2534 const char *section
,
2535 unsigned section_line
,
2543 const char *word
, *state
;
2547 if (isempty(rvalue
)) {
2548 *archs
= set_free(*archs
);
2552 r
= set_ensure_allocated(archs
, NULL
);
2556 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2557 _cleanup_free_
char *t
= NULL
;
2560 t
= strndup(word
, l
);
2564 r
= seccomp_arch_from_string(t
, &a
);
2566 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call architecture, ignoring: %s", t
);
2570 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2576 if (!isempty(state
))
2577 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2582 int config_parse_syscall_errno(
2584 const char *filename
,
2586 const char *section
,
2587 unsigned section_line
,
2594 ExecContext
*c
= data
;
2601 if (isempty(rvalue
)) {
2602 /* Empty assignment resets to KILL */
2603 c
->syscall_errno
= 0;
2607 e
= errno_from_name(rvalue
);
2609 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2613 c
->syscall_errno
= e
;
2617 int config_parse_address_families(
2619 const char *filename
,
2621 const char *section
,
2622 unsigned section_line
,
2629 ExecContext
*c
= data
;
2630 bool invert
= false;
2631 const char *word
, *state
;
2639 if (isempty(rvalue
)) {
2640 /* Empty assignment resets the list */
2641 c
->address_families
= set_free(c
->address_families
);
2642 c
->address_families_whitelist
= false;
2646 if (rvalue
[0] == '~') {
2651 if (!c
->address_families
) {
2652 c
->address_families
= set_new(NULL
);
2653 if (!c
->address_families
)
2656 c
->address_families_whitelist
= !invert
;
2659 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2660 _cleanup_free_
char *t
= NULL
;
2663 t
= strndup(word
, l
);
2667 af
= af_from_name(t
);
2669 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse address family, ignoring: %s", t
);
2673 /* If we previously wanted to forbid an address family and now
2674 * we want to allow it, then remove it from the list
2676 if (!invert
== c
->address_families_whitelist
) {
2677 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2683 set_remove(c
->address_families
, INT_TO_PTR(af
));
2685 if (!isempty(state
))
2686 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2692 int config_parse_unit_slice(
2694 const char *filename
,
2696 const char *section
,
2697 unsigned section_line
,
2704 _cleanup_free_
char *k
= NULL
;
2705 Unit
*u
= userdata
, *slice
= NULL
;
2713 r
= unit_name_printf(u
, rvalue
, &k
);
2715 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2719 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2721 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2725 r
= unit_set_slice(u
, slice
);
2727 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2734 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2736 int config_parse_cpu_shares(
2738 const char *filename
,
2740 const char *section
,
2741 unsigned section_line
,
2748 uint64_t *shares
= data
;
2755 r
= cg_cpu_shares_parse(rvalue
, shares
);
2757 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2764 int config_parse_cpu_quota(
2766 const char *filename
,
2768 const char *section
,
2769 unsigned section_line
,
2776 CGroupContext
*c
= data
;
2783 if (isempty(rvalue
)) {
2784 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2788 r
= parse_percent(rvalue
);
2790 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
2794 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
2798 int config_parse_memory_limit(
2800 const char *filename
,
2802 const char *section
,
2803 unsigned section_line
,
2810 CGroupContext
*c
= data
;
2811 uint64_t bytes
= CGROUP_LIMIT_MAX
;
2814 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
2816 r
= parse_percent(rvalue
);
2818 r
= parse_size(rvalue
, 1024, &bytes
);
2820 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
2824 bytes
= physical_memory_scale(r
, 100U);
2827 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' too small. Ignoring.", rvalue
);
2832 if (streq(lvalue
, "MemoryLow"))
2833 c
->memory_low
= bytes
;
2834 else if (streq(lvalue
, "MemoryHigh"))
2835 c
->memory_high
= bytes
;
2836 else if (streq(lvalue
, "MemoryMax"))
2837 c
->memory_max
= bytes
;
2839 c
->memory_limit
= bytes
;
2844 int config_parse_tasks_max(
2846 const char *filename
,
2848 const char *section
,
2849 unsigned section_line
,
2856 uint64_t *tasks_max
= data
, u
;
2859 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
2860 *tasks_max
= (uint64_t) -1;
2864 r
= safe_atou64(rvalue
, &u
);
2865 if (r
< 0 || u
< 1) {
2866 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
2874 int config_parse_device_allow(
2876 const char *filename
,
2878 const char *section
,
2879 unsigned section_line
,
2886 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
2887 CGroupContext
*c
= data
;
2888 CGroupDeviceAllow
*a
;
2889 const char *m
= NULL
;
2893 if (isempty(rvalue
)) {
2894 while (c
->device_allow
)
2895 cgroup_context_free_device_allow(c
, c
->device_allow
);
2900 r
= unit_full_printf(userdata
, rvalue
, &t
);
2902 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2903 "Failed to resolve specifiers in %s, ignoring: %m",
2907 n
= strcspn(t
, WHITESPACE
);
2909 path
= strndup(t
, n
);
2913 if (!startswith(path
, "/dev/") &&
2914 !startswith(path
, "block-") &&
2915 !startswith(path
, "char-")) {
2916 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
2920 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
2924 if (!in_charset(m
, "rwm")) {
2925 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
2929 a
= new0(CGroupDeviceAllow
, 1);
2935 a
->r
= !!strchr(m
, 'r');
2936 a
->w
= !!strchr(m
, 'w');
2937 a
->m
= !!strchr(m
, 'm');
2939 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
2943 int config_parse_io_weight(
2945 const char *filename
,
2947 const char *section
,
2948 unsigned section_line
,
2955 uint64_t *weight
= data
;
2962 r
= cg_weight_parse(rvalue
, weight
);
2964 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
2971 int config_parse_io_device_weight(
2973 const char *filename
,
2975 const char *section
,
2976 unsigned section_line
,
2983 _cleanup_free_
char *path
= NULL
;
2984 CGroupIODeviceWeight
*w
;
2985 CGroupContext
*c
= data
;
2995 if (isempty(rvalue
)) {
2996 while (c
->io_device_weights
)
2997 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3002 n
= strcspn(rvalue
, WHITESPACE
);
3003 weight
= rvalue
+ n
;
3004 weight
+= strspn(weight
, WHITESPACE
);
3006 if (isempty(weight
)) {
3007 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3011 path
= strndup(rvalue
, n
);
3015 if (!path_startswith(path
, "/dev")) {
3016 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3020 r
= cg_weight_parse(weight
, &u
);
3022 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3026 assert(u
!= CGROUP_WEIGHT_INVALID
);
3028 w
= new0(CGroupIODeviceWeight
, 1);
3037 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3041 int config_parse_io_limit(
3043 const char *filename
,
3045 const char *section
,
3046 unsigned section_line
,
3053 _cleanup_free_
char *path
= NULL
;
3054 CGroupIODeviceLimit
*l
= NULL
, *t
;
3055 CGroupContext
*c
= data
;
3056 CGroupIOLimitType type
;
3066 type
= cgroup_io_limit_type_from_string(lvalue
);
3069 if (isempty(rvalue
)) {
3070 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3071 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3075 n
= strcspn(rvalue
, WHITESPACE
);
3077 limit
+= strspn(limit
, WHITESPACE
);
3080 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3084 path
= strndup(rvalue
, n
);
3088 if (!path_startswith(path
, "/dev")) {
3089 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3093 if (streq("infinity", limit
)) {
3094 num
= CGROUP_LIMIT_MAX
;
3096 r
= parse_size(limit
, 1000, &num
);
3097 if (r
< 0 || num
<= 0) {
3098 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3103 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3104 if (path_equal(path
, t
->path
)) {
3111 CGroupIOLimitType ttype
;
3113 l
= new0(CGroupIODeviceLimit
, 1);
3119 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3120 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3122 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3125 l
->limits
[type
] = num
;
3130 int config_parse_blockio_weight(
3132 const char *filename
,
3134 const char *section
,
3135 unsigned section_line
,
3142 uint64_t *weight
= data
;
3149 r
= cg_blkio_weight_parse(rvalue
, weight
);
3151 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3158 int config_parse_blockio_device_weight(
3160 const char *filename
,
3162 const char *section
,
3163 unsigned section_line
,
3170 _cleanup_free_
char *path
= NULL
;
3171 CGroupBlockIODeviceWeight
*w
;
3172 CGroupContext
*c
= data
;
3182 if (isempty(rvalue
)) {
3183 while (c
->blockio_device_weights
)
3184 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3189 n
= strcspn(rvalue
, WHITESPACE
);
3190 weight
= rvalue
+ n
;
3191 weight
+= strspn(weight
, WHITESPACE
);
3193 if (isempty(weight
)) {
3194 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3198 path
= strndup(rvalue
, n
);
3202 if (!path_startswith(path
, "/dev")) {
3203 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3207 r
= cg_blkio_weight_parse(weight
, &u
);
3209 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3213 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3215 w
= new0(CGroupBlockIODeviceWeight
, 1);
3224 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3228 int config_parse_blockio_bandwidth(
3230 const char *filename
,
3232 const char *section
,
3233 unsigned section_line
,
3240 _cleanup_free_
char *path
= NULL
;
3241 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3242 CGroupContext
*c
= data
;
3243 const char *bandwidth
;
3253 read
= streq("BlockIOReadBandwidth", lvalue
);
3255 if (isempty(rvalue
)) {
3256 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3257 b
->rbps
= CGROUP_LIMIT_MAX
;
3258 b
->wbps
= CGROUP_LIMIT_MAX
;
3263 n
= strcspn(rvalue
, WHITESPACE
);
3264 bandwidth
= rvalue
+ n
;
3265 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3268 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3272 path
= strndup(rvalue
, n
);
3276 if (!path_startswith(path
, "/dev")) {
3277 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3281 r
= parse_size(bandwidth
, 1000, &bytes
);
3282 if (r
< 0 || bytes
<= 0) {
3283 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3287 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3288 if (path_equal(path
, t
->path
)) {
3295 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3301 b
->rbps
= CGROUP_LIMIT_MAX
;
3302 b
->wbps
= CGROUP_LIMIT_MAX
;
3304 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3315 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3317 int config_parse_job_mode_isolate(
3319 const char *filename
,
3321 const char *section
,
3322 unsigned section_line
,
3336 r
= parse_boolean(rvalue
);
3338 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3342 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3346 int config_parse_runtime_directory(
3348 const char *filename
,
3350 const char *section
,
3351 unsigned section_line
,
3360 const char *word
, *state
;
3369 if (isempty(rvalue
)) {
3370 /* Empty assignment resets the list */
3371 *rt
= strv_free(*rt
);
3375 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3376 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3378 t
= strndup(word
, l
);
3382 r
= unit_name_printf(u
, t
, &n
);
3384 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3388 if (!filename_is_valid(n
)) {
3389 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3393 r
= strv_push(rt
, n
);
3399 if (!isempty(state
))
3400 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3405 int config_parse_set_status(
3407 const char *filename
,
3409 const char *section
,
3410 unsigned section_line
,
3418 const char *word
, *state
;
3420 ExitStatusSet
*status_set
= data
;
3427 /* Empty assignment resets the list */
3428 if (isempty(rvalue
)) {
3429 exit_status_set_free(status_set
);
3433 FOREACH_WORD(word
, l
, rvalue
, state
) {
3434 _cleanup_free_
char *temp
;
3438 temp
= strndup(word
, l
);
3442 r
= safe_atoi(temp
, &val
);
3444 val
= signal_from_string_try_harder(temp
);
3447 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3450 set
= &status_set
->signal
;
3452 if (val
< 0 || val
> 255) {
3453 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3456 set
= &status_set
->status
;
3459 r
= set_ensure_allocated(set
, NULL
);
3463 r
= set_put(*set
, INT_TO_PTR(val
));
3465 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3469 if (!isempty(state
))
3470 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3475 int config_parse_namespace_path_strv(
3477 const char *filename
,
3479 const char *section
,
3480 unsigned section_line
,
3497 if (isempty(rvalue
)) {
3498 /* Empty assignment resets the list */
3499 *sv
= strv_free(*sv
);
3503 prev
= cur
= rvalue
;
3505 _cleanup_free_
char *word
= NULL
;
3508 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3514 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3518 if (!utf8_is_valid(word
)) {
3519 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3524 offset
= word
[0] == '-';
3525 if (!path_is_absolute(word
+ offset
)) {
3526 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3531 path_kill_slashes(word
+ offset
);
3533 r
= strv_push(sv
, word
);
3544 int config_parse_no_new_privileges(
3546 const char *filename
,
3548 const char *section
,
3549 unsigned section_line
,
3556 ExecContext
*c
= data
;
3564 k
= parse_boolean(rvalue
);
3566 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3570 c
->no_new_privileges
= !!k
;
3571 c
->no_new_privileges_set
= true;
3576 int config_parse_protect_home(
3578 const char *filename
,
3580 const char *section
,
3581 unsigned section_line
,
3588 ExecContext
*c
= data
;
3596 /* Our enum shall be a superset of booleans, hence first try
3597 * to parse as as boolean, and then as enum */
3599 k
= parse_boolean(rvalue
);
3601 c
->protect_home
= PROTECT_HOME_YES
;
3603 c
->protect_home
= PROTECT_HOME_NO
;
3607 h
= protect_home_from_string(rvalue
);
3609 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3613 c
->protect_home
= h
;
3619 int config_parse_protect_system(
3621 const char *filename
,
3623 const char *section
,
3624 unsigned section_line
,
3631 ExecContext
*c
= data
;
3639 /* Our enum shall be a superset of booleans, hence first try
3640 * to parse as as boolean, and then as enum */
3642 k
= parse_boolean(rvalue
);
3644 c
->protect_system
= PROTECT_SYSTEM_YES
;
3646 c
->protect_system
= PROTECT_SYSTEM_NO
;
3650 s
= protect_system_from_string(rvalue
);
3652 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3656 c
->protect_system
= s
;
3662 #define FOLLOW_MAX 8
3664 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3675 /* This will update the filename pointer if the loaded file is
3676 * reached by a symlink. The old string will be freed. */
3679 char *target
, *name
;
3681 if (c
++ >= FOLLOW_MAX
)
3684 path_kill_slashes(*filename
);
3686 /* Add the file name we are currently looking at to
3687 * the names of this unit, but only if it is a valid
3689 name
= basename(*filename
);
3690 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3692 id
= set_get(names
, name
);
3698 r
= set_consume(names
, id
);
3704 /* Try to open the file name, but don't if its a symlink */
3705 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3712 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3713 r
= readlink_and_make_absolute(*filename
, &target
);
3721 f
= fdopen(fd
, "re");
3733 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
3741 /* Let's try to add in all symlink names we found */
3742 while ((k
= set_steal_first(names
))) {
3744 /* First try to merge in the other name into our
3746 r
= unit_merge_by_name(*u
, k
);
3750 /* Hmm, we couldn't merge the other unit into
3751 * ours? Then let's try it the other way
3754 /* If the symlink name we are looking at is unit template, then
3755 we must search for instance of this template */
3756 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
3757 _cleanup_free_
char *instance
= NULL
;
3759 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
3763 other
= manager_get_unit((*u
)->manager
, instance
);
3765 other
= manager_get_unit((*u
)->manager
, k
);
3770 r
= unit_merge(other
, *u
);
3773 return merge_by_names(u
, names
, NULL
);
3781 unit_choose_id(*u
, id
);
3789 static int load_from_path(Unit
*u
, const char *path
) {
3790 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
3791 _cleanup_fclose_
FILE *f
= NULL
;
3792 _cleanup_free_
char *filename
= NULL
;
3801 symlink_names
= set_new(&string_hash_ops
);
3805 if (path_is_absolute(path
)) {
3807 filename
= strdup(path
);
3811 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3813 filename
= mfree(filename
);
3821 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
3823 /* Instead of opening the path right away, we manually
3824 * follow all symlinks and add their name to our unit
3825 * name set while doing so */
3826 filename
= path_make_absolute(path
, *p
);
3830 if (u
->manager
->unit_path_cache
&&
3831 !set_get(u
->manager
->unit_path_cache
, filename
))
3834 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3837 filename
= mfree(filename
);
3839 /* ENOENT means that the file is missing or is a dangling symlink.
3840 * ENOTDIR means that one of paths we expect to be is a directory
3841 * is not a directory, we should just ignore that.
3842 * EACCES means that the directory or file permissions are wrong.
3845 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
3846 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
3849 /* Empty the symlink names for the next run */
3850 set_clear_free(symlink_names
);
3855 /* Hmm, no suitable file found? */
3858 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
3859 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
3864 r
= merge_by_names(&merged
, symlink_names
, id
);
3869 u
->load_state
= UNIT_MERGED
;
3873 if (fstat(fileno(f
), &st
) < 0)
3876 if (null_or_empty(&st
)) {
3877 u
->load_state
= UNIT_MASKED
;
3878 u
->fragment_mtime
= 0;
3880 u
->load_state
= UNIT_LOADED
;
3881 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
3883 /* Now, parse the file contents */
3884 r
= config_parse(u
->id
, filename
, f
,
3885 UNIT_VTABLE(u
)->sections
,
3886 config_item_perf_lookup
, load_fragment_gperf_lookup
,
3887 false, true, false, u
);
3892 free(u
->fragment_path
);
3893 u
->fragment_path
= filename
;
3896 if (u
->source_path
) {
3897 if (stat(u
->source_path
, &st
) >= 0)
3898 u
->source_mtime
= timespec_load(&st
.st_mtim
);
3900 u
->source_mtime
= 0;
3906 int unit_load_fragment(Unit
*u
) {
3912 assert(u
->load_state
== UNIT_STUB
);
3916 u
->load_state
= UNIT_LOADED
;
3920 /* First, try to find the unit under its id. We always look
3921 * for unit files in the default directories, to make it easy
3922 * to override things by placing things in /etc/systemd/system */
3923 r
= load_from_path(u
, u
->id
);
3927 /* Try to find an alias we can load this with */
3928 if (u
->load_state
== UNIT_STUB
) {
3929 SET_FOREACH(t
, u
->names
, i
) {
3934 r
= load_from_path(u
, t
);
3938 if (u
->load_state
!= UNIT_STUB
)
3943 /* And now, try looking for it under the suggested (originally linked) path */
3944 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
3946 r
= load_from_path(u
, u
->fragment_path
);
3950 if (u
->load_state
== UNIT_STUB
)
3951 /* Hmm, this didn't work? Then let's get rid
3952 * of the fragment path stored for us, so that
3953 * we don't point to an invalid location. */
3954 u
->fragment_path
= mfree(u
->fragment_path
);
3957 /* Look for a template */
3958 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
3959 _cleanup_free_
char *k
= NULL
;
3961 r
= unit_name_template(u
->id
, &k
);
3965 r
= load_from_path(u
, k
);
3969 if (u
->load_state
== UNIT_STUB
) {
3970 SET_FOREACH(t
, u
->names
, i
) {
3971 _cleanup_free_
char *z
= NULL
;
3976 r
= unit_name_template(t
, &z
);
3980 r
= load_from_path(u
, z
);
3984 if (u
->load_state
!= UNIT_STUB
)
3993 void unit_dump_config_items(FILE *f
) {
3994 static const struct {
3995 const ConfigParserCallback callback
;
3998 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3999 { config_parse_warn_compat
, "NOTSUPPORTED" },
4001 { config_parse_int
, "INTEGER" },
4002 { config_parse_unsigned
, "UNSIGNED" },
4003 { config_parse_iec_size
, "SIZE" },
4004 { config_parse_iec_uint64
, "SIZE" },
4005 { config_parse_si_size
, "SIZE" },
4006 { config_parse_bool
, "BOOLEAN" },
4007 { config_parse_string
, "STRING" },
4008 { config_parse_path
, "PATH" },
4009 { config_parse_unit_path_printf
, "PATH" },
4010 { config_parse_strv
, "STRING [...]" },
4011 { config_parse_exec_nice
, "NICE" },
4012 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4013 { config_parse_exec_io_class
, "IOCLASS" },
4014 { config_parse_exec_io_priority
, "IOPRIORITY" },
4015 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4016 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4017 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4018 { config_parse_mode
, "MODE" },
4019 { config_parse_unit_env_file
, "FILE" },
4020 { config_parse_output
, "OUTPUT" },
4021 { config_parse_input
, "INPUT" },
4022 { config_parse_log_facility
, "FACILITY" },
4023 { config_parse_log_level
, "LEVEL" },
4024 { config_parse_exec_secure_bits
, "SECUREBITS" },
4025 { config_parse_capability_set
, "BOUNDINGSET" },
4026 { config_parse_limit
, "LIMIT" },
4027 { config_parse_unit_deps
, "UNIT [...]" },
4028 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4029 { config_parse_service_type
, "SERVICETYPE" },
4030 { config_parse_service_restart
, "SERVICERESTART" },
4031 #ifdef HAVE_SYSV_COMPAT
4032 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4034 { config_parse_kill_mode
, "KILLMODE" },
4035 { config_parse_signal
, "SIGNAL" },
4036 { config_parse_socket_listen
, "SOCKET [...]" },
4037 { config_parse_socket_bind
, "SOCKETBIND" },
4038 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4039 { config_parse_sec
, "SECONDS" },
4040 { config_parse_nsec
, "NANOSECONDS" },
4041 { config_parse_namespace_path_strv
, "PATH [...]" },
4042 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4043 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4044 { config_parse_unit_string_printf
, "STRING" },
4045 { config_parse_trigger_unit
, "UNIT" },
4046 { config_parse_timer
, "TIMER" },
4047 { config_parse_path_spec
, "PATH" },
4048 { config_parse_notify_access
, "ACCESS" },
4049 { config_parse_ip_tos
, "TOS" },
4050 { config_parse_unit_condition_path
, "CONDITION" },
4051 { config_parse_unit_condition_string
, "CONDITION" },
4052 { config_parse_unit_condition_null
, "CONDITION" },
4053 { config_parse_unit_slice
, "SLICE" },
4054 { config_parse_documentation
, "URL" },
4055 { config_parse_service_timeout
, "SECONDS" },
4056 { config_parse_failure_action
, "ACTION" },
4057 { config_parse_set_status
, "STATUS" },
4058 { config_parse_service_sockets
, "SOCKETS" },
4059 { config_parse_environ
, "ENVIRON" },
4061 { config_parse_syscall_filter
, "SYSCALLS" },
4062 { config_parse_syscall_archs
, "ARCHS" },
4063 { config_parse_syscall_errno
, "ERRNO" },
4064 { config_parse_address_families
, "FAMILIES" },
4066 { config_parse_cpu_shares
, "SHARES" },
4067 { config_parse_memory_limit
, "LIMIT" },
4068 { config_parse_device_allow
, "DEVICE" },
4069 { config_parse_device_policy
, "POLICY" },
4070 { config_parse_io_limit
, "LIMIT" },
4071 { config_parse_io_weight
, "WEIGHT" },
4072 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4073 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4074 { config_parse_blockio_weight
, "WEIGHT" },
4075 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4076 { config_parse_long
, "LONG" },
4077 { config_parse_socket_service
, "SERVICE" },
4079 { config_parse_exec_selinux_context
, "LABEL" },
4081 { config_parse_job_mode
, "MODE" },
4082 { config_parse_job_mode_isolate
, "BOOLEAN" },
4083 { config_parse_personality
, "PERSONALITY" },
4086 const char *prev
= NULL
;
4091 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4092 const char *rvalue
= "OTHER", *lvalue
;
4096 const ConfigPerfItem
*p
;
4098 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4100 dot
= strchr(i
, '.');
4101 lvalue
= dot
? dot
+ 1 : i
;
4105 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4109 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4112 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4113 if (p
->parse
== table
[j
].callback
) {
4114 rvalue
= table
[j
].rvalue
;
4118 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);