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_input
, exec_input
, ExecInput
, "Failed to parse input literal specifier");
780 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output literal specifier");
782 int config_parse_exec_input(const char *unit
,
783 const char *filename
,
786 unsigned section_line
,
792 ExecContext
*c
= data
;
801 name
= startswith(rvalue
, "fd:");
803 /* Strip prefix and validate fd name */
804 if (!fdname_is_valid(name
)) {
805 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
808 c
->std_input
= EXEC_INPUT_NAMED_FD
;
809 r
= free_and_strdup(&c
->stdio_fdname
[STDIN_FILENO
], name
);
814 ExecInput ei
= exec_input_from_string(rvalue
);
815 if (ei
== _EXEC_INPUT_INVALID
)
816 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
823 int config_parse_exec_output(const char *unit
,
824 const char *filename
,
827 unsigned section_line
,
833 ExecContext
*c
= data
;
844 name
= startswith(rvalue
, "fd:");
846 /* Strip prefix and validate fd name */
847 if (!fdname_is_valid(name
)) {
848 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", name
);
851 eo
= EXEC_OUTPUT_NAMED_FD
;
853 eo
= exec_output_from_string(rvalue
);
854 if (eo
== _EXEC_OUTPUT_INVALID
) {
855 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
860 if (streq(lvalue
, "StandardOutput")) {
862 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], name
);
866 } else if (streq(lvalue
, "StandardError")) {
868 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], name
);
873 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output property, ignoring: %s", lvalue
);
878 int config_parse_exec_io_class(const char *unit
,
879 const char *filename
,
882 unsigned section_line
,
889 ExecContext
*c
= data
;
897 x
= ioprio_class_from_string(rvalue
);
899 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
903 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
904 c
->ioprio_set
= true;
909 int config_parse_exec_io_priority(const char *unit
,
910 const char *filename
,
913 unsigned section_line
,
920 ExecContext
*c
= data
;
928 r
= safe_atoi(rvalue
, &i
);
929 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
930 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
934 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
935 c
->ioprio_set
= true;
940 int config_parse_exec_cpu_sched_policy(const char *unit
,
941 const char *filename
,
944 unsigned section_line
,
952 ExecContext
*c
= data
;
960 x
= sched_policy_from_string(rvalue
);
962 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
966 c
->cpu_sched_policy
= x
;
967 /* Moving to or from real-time policy? We need to adjust the priority */
968 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
969 c
->cpu_sched_set
= true;
974 int config_parse_exec_cpu_sched_prio(const char *unit
,
975 const char *filename
,
978 unsigned section_line
,
985 ExecContext
*c
= data
;
993 r
= safe_atoi(rvalue
, &i
);
995 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
999 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1000 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1001 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1003 if (i
< min
|| i
> max
) {
1004 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1008 c
->cpu_sched_priority
= i
;
1009 c
->cpu_sched_set
= true;
1014 int config_parse_exec_cpu_affinity(const char *unit
,
1015 const char *filename
,
1017 const char *section
,
1018 unsigned section_line
,
1025 ExecContext
*c
= data
;
1026 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1034 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1039 CPU_FREE(c
->cpuset
);
1042 /* An empty assignment resets the CPU list */
1048 c
->cpuset_ncpus
= ncpus
;
1053 int config_parse_exec_secure_bits(const char *unit
,
1054 const char *filename
,
1056 const char *section
,
1057 unsigned section_line
,
1064 ExecContext
*c
= data
;
1066 const char *word
, *state
;
1073 if (isempty(rvalue
)) {
1074 /* An empty assignment resets the field */
1079 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
1080 if (first_word(word
, "keep-caps"))
1081 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
1082 else if (first_word(word
, "keep-caps-locked"))
1083 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
1084 else if (first_word(word
, "no-setuid-fixup"))
1085 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
1086 else if (first_word(word
, "no-setuid-fixup-locked"))
1087 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
1088 else if (first_word(word
, "noroot"))
1089 c
->secure_bits
|= 1<<SECURE_NOROOT
;
1090 else if (first_word(word
, "noroot-locked"))
1091 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
1093 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse secure bits, ignoring: %s", rvalue
);
1097 if (!isempty(state
))
1098 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, garbage at the end, ignoring.");
1103 int config_parse_capability_set(
1105 const char *filename
,
1107 const char *section
,
1108 unsigned section_line
,
1115 uint64_t *capability_set
= data
;
1116 uint64_t sum
= 0, initial
= 0;
1117 bool invert
= false;
1125 if (rvalue
[0] == '~') {
1130 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1131 initial
= CAP_ALL
; /* initialized to all bits on */
1132 /* else "AmbientCapabilities" initialized to all bits off */
1136 _cleanup_free_
char *word
= NULL
;
1139 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1145 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1149 cap
= capability_from_name(word
);
1151 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1155 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1158 sum
= invert
? ~sum
: sum
;
1160 if (sum
== 0 || *capability_set
== initial
)
1161 /* "" or uninitialized data -> replace */
1162 *capability_set
= sum
;
1164 /* previous data -> merge */
1165 *capability_set
|= sum
;
1170 int config_parse_limit(
1172 const char *filename
,
1174 const char *section
,
1175 unsigned section_line
,
1182 struct rlimit
**rl
= data
, d
= {};
1190 r
= rlimit_parse(ltype
, rvalue
, &d
);
1192 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1196 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1203 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1211 #ifdef HAVE_SYSV_COMPAT
1212 int config_parse_sysv_priority(const char *unit
,
1213 const char *filename
,
1215 const char *section
,
1216 unsigned section_line
,
1223 int *priority
= data
;
1231 r
= safe_atoi(rvalue
, &i
);
1232 if (r
< 0 || i
< 0) {
1233 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1237 *priority
= (int) i
;
1242 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1243 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1245 int config_parse_exec_mount_flags(const char *unit
,
1246 const char *filename
,
1248 const char *section
,
1249 unsigned section_line
,
1257 unsigned long flags
= 0;
1258 ExecContext
*c
= data
;
1265 if (streq(rvalue
, "shared"))
1267 else if (streq(rvalue
, "slave"))
1269 else if (streq(rvalue
, "private"))
1272 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1276 c
->mount_flags
= flags
;
1281 int config_parse_exec_selinux_context(
1283 const char *filename
,
1285 const char *section
,
1286 unsigned section_line
,
1293 ExecContext
*c
= data
;
1304 if (isempty(rvalue
)) {
1305 c
->selinux_context
= mfree(c
->selinux_context
);
1306 c
->selinux_context_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
->selinux_context
);
1323 c
->selinux_context
= k
;
1324 c
->selinux_context_ignore
= ignore
;
1329 int config_parse_exec_apparmor_profile(
1331 const char *filename
,
1333 const char *section
,
1334 unsigned section_line
,
1341 ExecContext
*c
= data
;
1352 if (isempty(rvalue
)) {
1353 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1354 c
->apparmor_profile_ignore
= false;
1358 if (rvalue
[0] == '-') {
1364 r
= unit_name_printf(u
, rvalue
, &k
);
1366 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1370 free(c
->apparmor_profile
);
1371 c
->apparmor_profile
= k
;
1372 c
->apparmor_profile_ignore
= ignore
;
1377 int config_parse_exec_smack_process_label(
1379 const char *filename
,
1381 const char *section
,
1382 unsigned section_line
,
1389 ExecContext
*c
= data
;
1400 if (isempty(rvalue
)) {
1401 c
->smack_process_label
= mfree(c
->smack_process_label
);
1402 c
->smack_process_label_ignore
= false;
1406 if (rvalue
[0] == '-') {
1412 r
= unit_name_printf(u
, rvalue
, &k
);
1414 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1418 free(c
->smack_process_label
);
1419 c
->smack_process_label
= k
;
1420 c
->smack_process_label_ignore
= ignore
;
1425 int config_parse_timer(const char *unit
,
1426 const char *filename
,
1428 const char *section
,
1429 unsigned section_line
,
1440 CalendarSpec
*c
= NULL
;
1442 _cleanup_free_
char *k
= NULL
;
1450 if (isempty(rvalue
)) {
1451 /* Empty assignment resets list */
1452 timer_free_values(t
);
1456 b
= timer_base_from_string(lvalue
);
1458 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1462 r
= unit_full_printf(u
, rvalue
, &k
);
1464 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1468 if (b
== TIMER_CALENDAR
) {
1469 if (calendar_spec_from_string(k
, &c
) < 0) {
1470 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1474 if (parse_sec(k
, &usec
) < 0) {
1475 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1480 v
= new0(TimerValue
, 1);
1482 calendar_spec_free(c
);
1488 v
->calendar_spec
= c
;
1490 LIST_PREPEND(value
, t
->values
, v
);
1495 int config_parse_trigger_unit(
1497 const char *filename
,
1499 const char *section
,
1500 unsigned section_line
,
1507 _cleanup_free_
char *p
= NULL
;
1517 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1518 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1522 r
= unit_name_printf(u
, rvalue
, &p
);
1524 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1528 type
= unit_name_to_type(p
);
1530 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1534 if (type
== u
->type
) {
1535 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1539 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1541 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1548 int config_parse_path_spec(const char *unit
,
1549 const char *filename
,
1551 const char *section
,
1552 unsigned section_line
,
1562 _cleanup_free_
char *k
= NULL
;
1570 if (isempty(rvalue
)) {
1571 /* Empty assignment clears list */
1576 b
= path_type_from_string(lvalue
);
1578 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1582 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1584 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1588 if (!path_is_absolute(k
)) {
1589 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1593 s
= new0(PathSpec
, 1);
1598 s
->path
= path_kill_slashes(k
);
1603 LIST_PREPEND(spec
, p
->specs
, s
);
1608 int config_parse_socket_service(
1610 const char *filename
,
1612 const char *section
,
1613 unsigned section_line
,
1620 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1621 _cleanup_free_
char *p
= NULL
;
1631 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1633 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1637 if (!endswith(p
, ".service")) {
1638 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1642 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1644 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1648 unit_ref_set(&s
->service
, x
);
1653 int config_parse_fdname(
1655 const char *filename
,
1657 const char *section
,
1658 unsigned section_line
,
1665 _cleanup_free_
char *p
= NULL
;
1674 if (isempty(rvalue
)) {
1675 s
->fdname
= mfree(s
->fdname
);
1679 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1681 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1685 if (!fdname_is_valid(p
)) {
1686 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1690 return free_and_replace(s
->fdname
, p
);
1693 int config_parse_service_sockets(
1695 const char *filename
,
1697 const char *section
,
1698 unsigned section_line
,
1716 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1718 r
= extract_first_word(&p
, &word
, NULL
, 0);
1724 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1728 r
= unit_name_printf(UNIT(s
), word
, &k
);
1730 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1734 if (!endswith(k
, ".socket")) {
1735 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1739 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1741 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1743 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1745 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1751 int config_parse_bus_name(
1753 const char *filename
,
1755 const char *section
,
1756 unsigned section_line
,
1763 _cleanup_free_
char *k
= NULL
;
1772 r
= unit_full_printf(u
, rvalue
, &k
);
1774 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1778 if (!service_name_is_valid(k
)) {
1779 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1783 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1786 int config_parse_service_timeout(
1788 const char *filename
,
1790 const char *section
,
1791 unsigned section_line
,
1798 Service
*s
= userdata
;
1807 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1809 r
= parse_sec(rvalue
, &usec
);
1811 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1815 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1816 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1817 * all other timeouts. */
1819 usec
= USEC_INFINITY
;
1821 if (!streq(lvalue
, "TimeoutStopSec")) {
1822 s
->start_timeout_defined
= true;
1823 s
->timeout_start_usec
= usec
;
1826 if (!streq(lvalue
, "TimeoutStartSec"))
1827 s
->timeout_stop_usec
= usec
;
1832 int config_parse_sec_fix_0(
1834 const char *filename
,
1836 const char *section
,
1837 unsigned section_line
,
1844 usec_t
*usec
= data
;
1852 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1853 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1856 r
= parse_sec(rvalue
, usec
);
1858 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1863 *usec
= USEC_INFINITY
;
1868 int config_parse_user_group(
1870 const char *filename
,
1872 const char *section
,
1873 unsigned section_line
,
1880 char **user
= data
, *n
;
1889 if (isempty(rvalue
))
1892 _cleanup_free_
char *k
= NULL
;
1894 r
= unit_full_printf(u
, rvalue
, &k
);
1896 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1900 if (!valid_user_group_name_or_id(k
)) {
1901 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1915 int config_parse_user_group_strv(
1917 const char *filename
,
1919 const char *section
,
1920 unsigned section_line
,
1927 char ***users
= data
;
1937 if (isempty(rvalue
)) {
1940 empty
= new0(char*, 1);
1952 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1954 r
= extract_first_word(&p
, &word
, WHITESPACE
, 0);
1960 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1964 r
= unit_full_printf(u
, word
, &k
);
1966 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", word
);
1970 if (!valid_user_group_name_or_id(k
)) {
1971 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID, ignoring: %s", k
);
1975 r
= strv_push(users
, k
);
1985 int config_parse_busname_service(
1987 const char *filename
,
1989 const char *section
,
1990 unsigned section_line
,
1997 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2001 _cleanup_free_
char *p
= NULL
;
2008 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
2010 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2014 if (!endswith(p
, ".service")) {
2015 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
2019 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
2021 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
2025 unit_ref_set(&n
->service
, x
);
2030 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
2032 int config_parse_bus_policy(
2034 const char *filename
,
2036 const char *section
,
2037 unsigned section_line
,
2044 _cleanup_free_ BusNamePolicy
*p
= NULL
;
2045 _cleanup_free_
char *id_str
= NULL
;
2046 BusName
*busname
= data
;
2054 p
= new0(BusNamePolicy
, 1);
2058 if (streq(lvalue
, "AllowUser"))
2059 p
->type
= BUSNAME_POLICY_TYPE_USER
;
2060 else if (streq(lvalue
, "AllowGroup"))
2061 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
2063 assert_not_reached("Unknown lvalue");
2065 id_str
= strdup(rvalue
);
2069 access_str
= strpbrk(id_str
, WHITESPACE
);
2071 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
2077 access_str
+= strspn(access_str
, WHITESPACE
);
2079 p
->access
= bus_policy_access_from_string(access_str
);
2080 if (p
->access
< 0) {
2081 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
2088 LIST_PREPEND(policy
, busname
->policy
, p
);
2094 int config_parse_working_directory(
2096 const char *filename
,
2098 const char *section
,
2099 unsigned section_line
,
2106 ExecContext
*c
= data
;
2117 if (rvalue
[0] == '-') {
2123 if (streq(rvalue
, "~")) {
2124 c
->working_directory_home
= true;
2125 c
->working_directory
= mfree(c
->working_directory
);
2127 _cleanup_free_
char *k
= NULL
;
2129 r
= unit_full_printf(u
, rvalue
, &k
);
2131 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2135 path_kill_slashes(k
);
2137 if (!utf8_is_valid(k
)) {
2138 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2142 if (!path_is_absolute(k
)) {
2143 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2147 free_and_replace(c
->working_directory
, k
);
2149 c
->working_directory_home
= false;
2152 c
->working_directory_missing_ok
= missing_ok
;
2156 int config_parse_unit_env_file(const char *unit
,
2157 const char *filename
,
2159 const char *section
,
2160 unsigned section_line
,
2169 _cleanup_free_
char *n
= NULL
;
2177 if (isempty(rvalue
)) {
2178 /* Empty assignment frees the list */
2179 *env
= strv_free(*env
);
2183 r
= unit_full_printf(u
, rvalue
, &n
);
2185 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2189 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2190 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2194 r
= strv_extend(env
, n
);
2201 int config_parse_environ(const char *unit
,
2202 const char *filename
,
2204 const char *section
,
2205 unsigned section_line
,
2214 const char *word
, *state
;
2216 _cleanup_free_
char *k
= NULL
;
2224 if (isempty(rvalue
)) {
2225 /* Empty assignment resets the list */
2226 *env
= strv_free(*env
);
2231 r
= unit_full_printf(u
, rvalue
, &k
);
2233 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2244 FOREACH_WORD_QUOTED(word
, l
, k
, state
) {
2245 _cleanup_free_
char *n
= NULL
;
2248 r
= cunescape_length(word
, l
, 0, &n
);
2250 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Couldn't unescape assignment, ignoring: %s", rvalue
);
2254 if (!env_assignment_is_valid(n
)) {
2255 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid environment assignment, ignoring: %s", rvalue
);
2259 x
= strv_env_set(*env
, n
);
2266 if (!isempty(state
))
2267 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2272 int config_parse_pass_environ(const char *unit
,
2273 const char *filename
,
2275 const char *section
,
2276 unsigned section_line
,
2283 const char *whole_rvalue
= rvalue
;
2284 char*** passenv
= data
;
2285 _cleanup_strv_free_
char **n
= NULL
;
2286 size_t nlen
= 0, nbufsize
= 0;
2294 if (isempty(rvalue
)) {
2295 /* Empty assignment resets the list */
2296 *passenv
= strv_free(*passenv
);
2301 _cleanup_free_
char *word
= NULL
;
2303 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
);
2309 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2310 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2314 if (!env_name_is_valid(word
)) {
2315 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2316 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2320 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2328 r
= strv_extend_strv(passenv
, n
, true);
2336 int config_parse_ip_tos(const char *unit
,
2337 const char *filename
,
2339 const char *section
,
2340 unsigned section_line
,
2347 int *ip_tos
= data
, x
;
2354 x
= ip_tos_from_string(rvalue
);
2356 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2364 int config_parse_unit_condition_path(
2366 const char *filename
,
2368 const char *section
,
2369 unsigned section_line
,
2376 _cleanup_free_
char *p
= NULL
;
2377 Condition
**list
= data
, *c
;
2378 ConditionType t
= ltype
;
2379 bool trigger
, negate
;
2388 if (isempty(rvalue
)) {
2389 /* Empty assignment resets the list */
2390 *list
= condition_free_list(*list
);
2394 trigger
= rvalue
[0] == '|';
2398 negate
= rvalue
[0] == '!';
2402 r
= unit_full_printf(u
, rvalue
, &p
);
2404 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2408 if (!path_is_absolute(p
)) {
2409 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2413 c
= condition_new(t
, p
, trigger
, negate
);
2417 LIST_PREPEND(conditions
, *list
, c
);
2421 int config_parse_unit_condition_string(
2423 const char *filename
,
2425 const char *section
,
2426 unsigned section_line
,
2433 _cleanup_free_
char *s
= NULL
;
2434 Condition
**list
= data
, *c
;
2435 ConditionType t
= ltype
;
2436 bool trigger
, negate
;
2445 if (isempty(rvalue
)) {
2446 /* Empty assignment resets the list */
2447 *list
= condition_free_list(*list
);
2451 trigger
= rvalue
[0] == '|';
2455 negate
= rvalue
[0] == '!';
2459 r
= unit_full_printf(u
, rvalue
, &s
);
2461 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2465 c
= condition_new(t
, s
, trigger
, negate
);
2469 LIST_PREPEND(conditions
, *list
, c
);
2473 int config_parse_unit_condition_null(
2475 const char *filename
,
2477 const char *section
,
2478 unsigned section_line
,
2485 Condition
**list
= data
, *c
;
2486 bool trigger
, negate
;
2494 if (isempty(rvalue
)) {
2495 /* Empty assignment resets the list */
2496 *list
= condition_free_list(*list
);
2500 trigger
= rvalue
[0] == '|';
2504 negate
= rvalue
[0] == '!';
2508 b
= parse_boolean(rvalue
);
2510 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2517 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2521 LIST_PREPEND(conditions
, *list
, c
);
2525 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2526 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2528 int config_parse_unit_requires_mounts_for(
2530 const char *filename
,
2532 const char *section
,
2533 unsigned section_line
,
2541 const char *word
, *state
;
2549 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2551 _cleanup_free_
char *n
;
2553 n
= strndup(word
, l
);
2557 if (!utf8_is_valid(n
)) {
2558 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2562 r
= unit_require_mounts_for(u
, n
);
2564 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount for, ignoring: %s", rvalue
);
2568 if (!isempty(state
))
2569 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2574 int config_parse_documentation(const char *unit
,
2575 const char *filename
,
2577 const char *section
,
2578 unsigned section_line
,
2594 if (isempty(rvalue
)) {
2595 /* Empty assignment resets the list */
2596 u
->documentation
= strv_free(u
->documentation
);
2600 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2601 rvalue
, data
, userdata
);
2605 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2607 if (documentation_url_is_valid(*a
))
2610 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2622 static int syscall_filter_parse_one(
2624 const char *filename
,
2633 const SyscallFilterSet
*set
;
2636 set
= syscall_filter_set_find(t
);
2639 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Don't know system call group, ignoring: %s", t
);
2643 NULSTR_FOREACH(i
, set
->value
) {
2644 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, i
, false);
2651 id
= seccomp_syscall_resolve_name(t
);
2652 if (id
== __NR_SCMP_ERROR
) {
2654 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2658 /* If we previously wanted to forbid a syscall and now
2659 * we want to allow it, then remove it from the list
2661 if (!invert
== c
->syscall_whitelist
) {
2662 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2668 (void) set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2674 int config_parse_syscall_filter(
2676 const char *filename
,
2678 const char *section
,
2679 unsigned section_line
,
2686 ExecContext
*c
= data
;
2688 bool invert
= false;
2697 if (isempty(rvalue
)) {
2698 /* Empty assignment resets the list */
2699 c
->syscall_filter
= set_free(c
->syscall_filter
);
2700 c
->syscall_whitelist
= false;
2704 if (rvalue
[0] == '~') {
2709 if (!c
->syscall_filter
) {
2710 c
->syscall_filter
= set_new(NULL
);
2711 if (!c
->syscall_filter
)
2715 /* Allow everything but the ones listed */
2716 c
->syscall_whitelist
= false;
2718 /* Allow nothing but the ones listed */
2719 c
->syscall_whitelist
= true;
2721 /* Accept default syscalls if we are on a whitelist */
2722 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2730 _cleanup_free_
char *word
= NULL
;
2732 r
= extract_first_word(&p
, &word
, NULL
, 0);
2738 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2742 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, word
, true);
2750 int config_parse_syscall_archs(
2752 const char *filename
,
2754 const char *section
,
2755 unsigned section_line
,
2763 const char *word
, *state
;
2767 if (isempty(rvalue
)) {
2768 *archs
= set_free(*archs
);
2772 r
= set_ensure_allocated(archs
, NULL
);
2776 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2777 _cleanup_free_
char *t
= NULL
;
2780 t
= strndup(word
, l
);
2784 r
= seccomp_arch_from_string(t
, &a
);
2786 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call architecture, ignoring: %s", t
);
2790 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2796 if (!isempty(state
))
2797 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2802 int config_parse_syscall_errno(
2804 const char *filename
,
2806 const char *section
,
2807 unsigned section_line
,
2814 ExecContext
*c
= data
;
2821 if (isempty(rvalue
)) {
2822 /* Empty assignment resets to KILL */
2823 c
->syscall_errno
= 0;
2827 e
= errno_from_name(rvalue
);
2829 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2833 c
->syscall_errno
= e
;
2837 int config_parse_address_families(
2839 const char *filename
,
2841 const char *section
,
2842 unsigned section_line
,
2849 ExecContext
*c
= data
;
2850 bool invert
= false;
2851 const char *word
, *state
;
2859 if (isempty(rvalue
)) {
2860 /* Empty assignment resets the list */
2861 c
->address_families
= set_free(c
->address_families
);
2862 c
->address_families_whitelist
= false;
2866 if (rvalue
[0] == '~') {
2871 if (!c
->address_families
) {
2872 c
->address_families
= set_new(NULL
);
2873 if (!c
->address_families
)
2876 c
->address_families_whitelist
= !invert
;
2879 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2880 _cleanup_free_
char *t
= NULL
;
2883 t
= strndup(word
, l
);
2887 af
= af_from_name(t
);
2889 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse address family, ignoring: %s", t
);
2893 /* If we previously wanted to forbid an address family and now
2894 * we want to allow it, then remove it from the list
2896 if (!invert
== c
->address_families_whitelist
) {
2897 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2903 set_remove(c
->address_families
, INT_TO_PTR(af
));
2905 if (!isempty(state
))
2906 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2912 int config_parse_unit_slice(
2914 const char *filename
,
2916 const char *section
,
2917 unsigned section_line
,
2924 _cleanup_free_
char *k
= NULL
;
2925 Unit
*u
= userdata
, *slice
= NULL
;
2933 r
= unit_name_printf(u
, rvalue
, &k
);
2935 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2939 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2941 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2945 r
= unit_set_slice(u
, slice
);
2947 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2954 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2956 int config_parse_cpu_weight(
2958 const char *filename
,
2960 const char *section
,
2961 unsigned section_line
,
2968 uint64_t *weight
= data
;
2975 r
= cg_weight_parse(rvalue
, weight
);
2977 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
2984 int config_parse_cpu_shares(
2986 const char *filename
,
2988 const char *section
,
2989 unsigned section_line
,
2996 uint64_t *shares
= data
;
3003 r
= cg_cpu_shares_parse(rvalue
, shares
);
3005 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3012 int config_parse_cpu_quota(
3014 const char *filename
,
3016 const char *section
,
3017 unsigned section_line
,
3024 CGroupContext
*c
= data
;
3031 if (isempty(rvalue
)) {
3032 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3036 r
= parse_percent_unbounded(rvalue
);
3038 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3042 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3046 int config_parse_memory_limit(
3048 const char *filename
,
3050 const char *section
,
3051 unsigned section_line
,
3058 CGroupContext
*c
= data
;
3059 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3062 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3064 r
= parse_percent(rvalue
);
3066 r
= parse_size(rvalue
, 1024, &bytes
);
3068 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3072 bytes
= physical_memory_scale(r
, 100U);
3074 if (bytes
<= 0 || bytes
>= UINT64_MAX
) {
3075 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3080 if (streq(lvalue
, "MemoryLow"))
3081 c
->memory_low
= bytes
;
3082 else if (streq(lvalue
, "MemoryHigh"))
3083 c
->memory_high
= bytes
;
3084 else if (streq(lvalue
, "MemoryMax"))
3085 c
->memory_max
= bytes
;
3086 else if (streq(lvalue
, "MemorySwapMax"))
3087 c
->memory_swap_max
= bytes
;
3088 else if (streq(lvalue
, "MemoryLimit"))
3089 c
->memory_limit
= bytes
;
3096 int config_parse_tasks_max(
3098 const char *filename
,
3100 const char *section
,
3101 unsigned section_line
,
3108 uint64_t *tasks_max
= data
, v
;
3112 if (isempty(rvalue
)) {
3113 *tasks_max
= u
->manager
->default_tasks_max
;
3117 if (streq(rvalue
, "infinity")) {
3118 *tasks_max
= CGROUP_LIMIT_MAX
;
3122 r
= parse_percent(rvalue
);
3124 r
= safe_atou64(rvalue
, &v
);
3126 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3130 v
= system_tasks_max_scale(r
, 100U);
3132 if (v
<= 0 || v
>= UINT64_MAX
) {
3133 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3141 int config_parse_device_allow(
3143 const char *filename
,
3145 const char *section
,
3146 unsigned section_line
,
3153 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3154 CGroupContext
*c
= data
;
3155 CGroupDeviceAllow
*a
;
3156 const char *m
= NULL
;
3160 if (isempty(rvalue
)) {
3161 while (c
->device_allow
)
3162 cgroup_context_free_device_allow(c
, c
->device_allow
);
3167 r
= unit_full_printf(userdata
, rvalue
, &t
);
3169 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3170 "Failed to resolve specifiers in %s, ignoring: %m",
3174 n
= strcspn(t
, WHITESPACE
);
3176 path
= strndup(t
, n
);
3180 if (!is_deviceallow_pattern(path
)) {
3181 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3185 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3189 if (!in_charset(m
, "rwm")) {
3190 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3194 a
= new0(CGroupDeviceAllow
, 1);
3200 a
->r
= !!strchr(m
, 'r');
3201 a
->w
= !!strchr(m
, 'w');
3202 a
->m
= !!strchr(m
, 'm');
3204 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3208 int config_parse_io_weight(
3210 const char *filename
,
3212 const char *section
,
3213 unsigned section_line
,
3220 uint64_t *weight
= data
;
3227 r
= cg_weight_parse(rvalue
, weight
);
3229 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3236 int config_parse_io_device_weight(
3238 const char *filename
,
3240 const char *section
,
3241 unsigned section_line
,
3248 _cleanup_free_
char *path
= NULL
;
3249 CGroupIODeviceWeight
*w
;
3250 CGroupContext
*c
= data
;
3260 if (isempty(rvalue
)) {
3261 while (c
->io_device_weights
)
3262 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3267 n
= strcspn(rvalue
, WHITESPACE
);
3268 weight
= rvalue
+ n
;
3269 weight
+= strspn(weight
, WHITESPACE
);
3271 if (isempty(weight
)) {
3272 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3276 path
= strndup(rvalue
, n
);
3280 if (!path_startswith(path
, "/dev")) {
3281 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3285 r
= cg_weight_parse(weight
, &u
);
3287 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3291 assert(u
!= CGROUP_WEIGHT_INVALID
);
3293 w
= new0(CGroupIODeviceWeight
, 1);
3302 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3306 int config_parse_io_limit(
3308 const char *filename
,
3310 const char *section
,
3311 unsigned section_line
,
3318 _cleanup_free_
char *path
= NULL
;
3319 CGroupIODeviceLimit
*l
= NULL
, *t
;
3320 CGroupContext
*c
= data
;
3321 CGroupIOLimitType type
;
3331 type
= cgroup_io_limit_type_from_string(lvalue
);
3334 if (isempty(rvalue
)) {
3335 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3336 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3340 n
= strcspn(rvalue
, WHITESPACE
);
3342 limit
+= strspn(limit
, WHITESPACE
);
3345 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3349 path
= strndup(rvalue
, n
);
3353 if (!path_startswith(path
, "/dev")) {
3354 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3358 if (streq("infinity", limit
)) {
3359 num
= CGROUP_LIMIT_MAX
;
3361 r
= parse_size(limit
, 1000, &num
);
3362 if (r
< 0 || num
<= 0) {
3363 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3368 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3369 if (path_equal(path
, t
->path
)) {
3376 CGroupIOLimitType ttype
;
3378 l
= new0(CGroupIODeviceLimit
, 1);
3384 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3385 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3387 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3390 l
->limits
[type
] = num
;
3395 int config_parse_blockio_weight(
3397 const char *filename
,
3399 const char *section
,
3400 unsigned section_line
,
3407 uint64_t *weight
= data
;
3414 r
= cg_blkio_weight_parse(rvalue
, weight
);
3416 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3423 int config_parse_blockio_device_weight(
3425 const char *filename
,
3427 const char *section
,
3428 unsigned section_line
,
3435 _cleanup_free_
char *path
= NULL
;
3436 CGroupBlockIODeviceWeight
*w
;
3437 CGroupContext
*c
= data
;
3447 if (isempty(rvalue
)) {
3448 while (c
->blockio_device_weights
)
3449 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3454 n
= strcspn(rvalue
, WHITESPACE
);
3455 weight
= rvalue
+ n
;
3456 weight
+= strspn(weight
, WHITESPACE
);
3458 if (isempty(weight
)) {
3459 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3463 path
= strndup(rvalue
, n
);
3467 if (!path_startswith(path
, "/dev")) {
3468 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3472 r
= cg_blkio_weight_parse(weight
, &u
);
3474 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3478 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3480 w
= new0(CGroupBlockIODeviceWeight
, 1);
3489 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3493 int config_parse_blockio_bandwidth(
3495 const char *filename
,
3497 const char *section
,
3498 unsigned section_line
,
3505 _cleanup_free_
char *path
= NULL
;
3506 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3507 CGroupContext
*c
= data
;
3508 const char *bandwidth
;
3518 read
= streq("BlockIOReadBandwidth", lvalue
);
3520 if (isempty(rvalue
)) {
3521 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3522 b
->rbps
= CGROUP_LIMIT_MAX
;
3523 b
->wbps
= CGROUP_LIMIT_MAX
;
3528 n
= strcspn(rvalue
, WHITESPACE
);
3529 bandwidth
= rvalue
+ n
;
3530 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3533 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3537 path
= strndup(rvalue
, n
);
3541 if (!path_startswith(path
, "/dev")) {
3542 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3546 r
= parse_size(bandwidth
, 1000, &bytes
);
3547 if (r
< 0 || bytes
<= 0) {
3548 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3552 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3553 if (path_equal(path
, t
->path
)) {
3560 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3566 b
->rbps
= CGROUP_LIMIT_MAX
;
3567 b
->wbps
= CGROUP_LIMIT_MAX
;
3569 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3580 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3582 int config_parse_job_mode_isolate(
3584 const char *filename
,
3586 const char *section
,
3587 unsigned section_line
,
3601 r
= parse_boolean(rvalue
);
3603 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3607 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3611 int config_parse_runtime_directory(
3613 const char *filename
,
3615 const char *section
,
3616 unsigned section_line
,
3625 const char *word
, *state
;
3634 if (isempty(rvalue
)) {
3635 /* Empty assignment resets the list */
3636 *rt
= strv_free(*rt
);
3640 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3641 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3643 t
= strndup(word
, l
);
3647 r
= unit_name_printf(u
, t
, &n
);
3649 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3653 if (!filename_is_valid(n
)) {
3654 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3658 r
= strv_push(rt
, n
);
3664 if (!isempty(state
))
3665 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3670 int config_parse_set_status(
3672 const char *filename
,
3674 const char *section
,
3675 unsigned section_line
,
3683 const char *word
, *state
;
3685 ExitStatusSet
*status_set
= data
;
3692 /* Empty assignment resets the list */
3693 if (isempty(rvalue
)) {
3694 exit_status_set_free(status_set
);
3698 FOREACH_WORD(word
, l
, rvalue
, state
) {
3699 _cleanup_free_
char *temp
;
3703 temp
= strndup(word
, l
);
3707 r
= safe_atoi(temp
, &val
);
3709 val
= signal_from_string_try_harder(temp
);
3712 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3715 set
= &status_set
->signal
;
3717 if (val
< 0 || val
> 255) {
3718 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3721 set
= &status_set
->status
;
3724 r
= set_ensure_allocated(set
, NULL
);
3728 r
= set_put(*set
, INT_TO_PTR(val
));
3730 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3734 if (!isempty(state
))
3735 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3740 int config_parse_namespace_path_strv(
3742 const char *filename
,
3744 const char *section
,
3745 unsigned section_line
,
3762 if (isempty(rvalue
)) {
3763 /* Empty assignment resets the list */
3764 *sv
= strv_free(*sv
);
3768 prev
= cur
= rvalue
;
3770 _cleanup_free_
char *word
= NULL
;
3773 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3779 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3783 if (!utf8_is_valid(word
)) {
3784 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3789 offset
= word
[0] == '-';
3790 if (!path_is_absolute(word
+ offset
)) {
3791 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3796 path_kill_slashes(word
+ offset
);
3798 r
= strv_push(sv
, word
);
3809 int config_parse_no_new_privileges(
3811 const char *filename
,
3813 const char *section
,
3814 unsigned section_line
,
3821 ExecContext
*c
= data
;
3829 k
= parse_boolean(rvalue
);
3831 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3835 c
->no_new_privileges
= k
;
3836 c
->no_new_privileges_set
= true;
3841 int config_parse_protect_home(
3843 const char *filename
,
3845 const char *section
,
3846 unsigned section_line
,
3853 ExecContext
*c
= data
;
3861 /* Our enum shall be a superset of booleans, hence first try
3862 * to parse as boolean, and then as enum */
3864 k
= parse_boolean(rvalue
);
3866 c
->protect_home
= PROTECT_HOME_YES
;
3868 c
->protect_home
= PROTECT_HOME_NO
;
3872 h
= protect_home_from_string(rvalue
);
3874 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3878 c
->protect_home
= h
;
3884 int config_parse_protect_system(
3886 const char *filename
,
3888 const char *section
,
3889 unsigned section_line
,
3896 ExecContext
*c
= data
;
3904 /* Our enum shall be a superset of booleans, hence first try
3905 * to parse as boolean, and then as enum */
3907 k
= parse_boolean(rvalue
);
3909 c
->protect_system
= PROTECT_SYSTEM_YES
;
3911 c
->protect_system
= PROTECT_SYSTEM_NO
;
3915 s
= protect_system_from_string(rvalue
);
3917 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3921 c
->protect_system
= s
;
3927 #define FOLLOW_MAX 8
3929 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3940 /* This will update the filename pointer if the loaded file is
3941 * reached by a symlink. The old string will be freed. */
3944 char *target
, *name
;
3946 if (c
++ >= FOLLOW_MAX
)
3949 path_kill_slashes(*filename
);
3951 /* Add the file name we are currently looking at to
3952 * the names of this unit, but only if it is a valid
3954 name
= basename(*filename
);
3955 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3957 id
= set_get(names
, name
);
3963 r
= set_consume(names
, id
);
3969 /* Try to open the file name, but don't if its a symlink */
3970 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3977 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3978 r
= readlink_and_make_absolute(*filename
, &target
);
3986 f
= fdopen(fd
, "re");
3998 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4006 /* Let's try to add in all symlink names we found */
4007 while ((k
= set_steal_first(names
))) {
4009 /* First try to merge in the other name into our
4011 r
= unit_merge_by_name(*u
, k
);
4015 /* Hmm, we couldn't merge the other unit into
4016 * ours? Then let's try it the other way
4019 /* If the symlink name we are looking at is unit template, then
4020 we must search for instance of this template */
4021 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4022 _cleanup_free_
char *instance
= NULL
;
4024 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4028 other
= manager_get_unit((*u
)->manager
, instance
);
4030 other
= manager_get_unit((*u
)->manager
, k
);
4035 r
= unit_merge(other
, *u
);
4038 return merge_by_names(u
, names
, NULL
);
4046 unit_choose_id(*u
, id
);
4054 static int load_from_path(Unit
*u
, const char *path
) {
4055 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4056 _cleanup_fclose_
FILE *f
= NULL
;
4057 _cleanup_free_
char *filename
= NULL
;
4066 symlink_names
= set_new(&string_hash_ops
);
4070 if (path_is_absolute(path
)) {
4072 filename
= strdup(path
);
4076 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4078 filename
= mfree(filename
);
4086 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4088 /* Instead of opening the path right away, we manually
4089 * follow all symlinks and add their name to our unit
4090 * name set while doing so */
4091 filename
= path_make_absolute(path
, *p
);
4095 if (u
->manager
->unit_path_cache
&&
4096 !set_get(u
->manager
->unit_path_cache
, filename
))
4099 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4102 filename
= mfree(filename
);
4104 /* ENOENT means that the file is missing or is a dangling symlink.
4105 * ENOTDIR means that one of paths we expect to be is a directory
4106 * is not a directory, we should just ignore that.
4107 * EACCES means that the directory or file permissions are wrong.
4110 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4111 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4114 /* Empty the symlink names for the next run */
4115 set_clear_free(symlink_names
);
4120 /* Hmm, no suitable file found? */
4123 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4124 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4129 r
= merge_by_names(&merged
, symlink_names
, id
);
4134 u
->load_state
= UNIT_MERGED
;
4138 if (fstat(fileno(f
), &st
) < 0)
4141 if (null_or_empty(&st
)) {
4142 u
->load_state
= UNIT_MASKED
;
4143 u
->fragment_mtime
= 0;
4145 u
->load_state
= UNIT_LOADED
;
4146 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4148 /* Now, parse the file contents */
4149 r
= config_parse(u
->id
, filename
, f
,
4150 UNIT_VTABLE(u
)->sections
,
4151 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4152 false, true, false, u
);
4157 free(u
->fragment_path
);
4158 u
->fragment_path
= filename
;
4161 if (u
->source_path
) {
4162 if (stat(u
->source_path
, &st
) >= 0)
4163 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4165 u
->source_mtime
= 0;
4171 int unit_load_fragment(Unit
*u
) {
4177 assert(u
->load_state
== UNIT_STUB
);
4181 u
->load_state
= UNIT_LOADED
;
4185 /* First, try to find the unit under its id. We always look
4186 * for unit files in the default directories, to make it easy
4187 * to override things by placing things in /etc/systemd/system */
4188 r
= load_from_path(u
, u
->id
);
4192 /* Try to find an alias we can load this with */
4193 if (u
->load_state
== UNIT_STUB
) {
4194 SET_FOREACH(t
, u
->names
, i
) {
4199 r
= load_from_path(u
, t
);
4203 if (u
->load_state
!= UNIT_STUB
)
4208 /* And now, try looking for it under the suggested (originally linked) path */
4209 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4211 r
= load_from_path(u
, u
->fragment_path
);
4215 if (u
->load_state
== UNIT_STUB
)
4216 /* Hmm, this didn't work? Then let's get rid
4217 * of the fragment path stored for us, so that
4218 * we don't point to an invalid location. */
4219 u
->fragment_path
= mfree(u
->fragment_path
);
4222 /* Look for a template */
4223 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4224 _cleanup_free_
char *k
= NULL
;
4226 r
= unit_name_template(u
->id
, &k
);
4230 r
= load_from_path(u
, k
);
4234 if (u
->load_state
== UNIT_STUB
) {
4235 SET_FOREACH(t
, u
->names
, i
) {
4236 _cleanup_free_
char *z
= NULL
;
4241 r
= unit_name_template(t
, &z
);
4245 r
= load_from_path(u
, z
);
4249 if (u
->load_state
!= UNIT_STUB
)
4258 void unit_dump_config_items(FILE *f
) {
4259 static const struct {
4260 const ConfigParserCallback callback
;
4263 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
4264 { config_parse_warn_compat
, "NOTSUPPORTED" },
4266 { config_parse_int
, "INTEGER" },
4267 { config_parse_unsigned
, "UNSIGNED" },
4268 { config_parse_iec_size
, "SIZE" },
4269 { config_parse_iec_uint64
, "SIZE" },
4270 { config_parse_si_size
, "SIZE" },
4271 { config_parse_bool
, "BOOLEAN" },
4272 { config_parse_string
, "STRING" },
4273 { config_parse_path
, "PATH" },
4274 { config_parse_unit_path_printf
, "PATH" },
4275 { config_parse_strv
, "STRING [...]" },
4276 { config_parse_exec_nice
, "NICE" },
4277 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4278 { config_parse_exec_io_class
, "IOCLASS" },
4279 { config_parse_exec_io_priority
, "IOPRIORITY" },
4280 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4281 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4282 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4283 { config_parse_mode
, "MODE" },
4284 { config_parse_unit_env_file
, "FILE" },
4285 { config_parse_exec_output
, "OUTPUT" },
4286 { config_parse_exec_input
, "INPUT" },
4287 { config_parse_log_facility
, "FACILITY" },
4288 { config_parse_log_level
, "LEVEL" },
4289 { config_parse_exec_secure_bits
, "SECUREBITS" },
4290 { config_parse_capability_set
, "BOUNDINGSET" },
4291 { config_parse_limit
, "LIMIT" },
4292 { config_parse_unit_deps
, "UNIT [...]" },
4293 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4294 { config_parse_service_type
, "SERVICETYPE" },
4295 { config_parse_service_restart
, "SERVICERESTART" },
4296 #ifdef HAVE_SYSV_COMPAT
4297 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4299 { config_parse_kill_mode
, "KILLMODE" },
4300 { config_parse_signal
, "SIGNAL" },
4301 { config_parse_socket_listen
, "SOCKET [...]" },
4302 { config_parse_socket_bind
, "SOCKETBIND" },
4303 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4304 { config_parse_sec
, "SECONDS" },
4305 { config_parse_nsec
, "NANOSECONDS" },
4306 { config_parse_namespace_path_strv
, "PATH [...]" },
4307 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4308 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4309 { config_parse_unit_string_printf
, "STRING" },
4310 { config_parse_trigger_unit
, "UNIT" },
4311 { config_parse_timer
, "TIMER" },
4312 { config_parse_path_spec
, "PATH" },
4313 { config_parse_notify_access
, "ACCESS" },
4314 { config_parse_ip_tos
, "TOS" },
4315 { config_parse_unit_condition_path
, "CONDITION" },
4316 { config_parse_unit_condition_string
, "CONDITION" },
4317 { config_parse_unit_condition_null
, "CONDITION" },
4318 { config_parse_unit_slice
, "SLICE" },
4319 { config_parse_documentation
, "URL" },
4320 { config_parse_service_timeout
, "SECONDS" },
4321 { config_parse_emergency_action
, "ACTION" },
4322 { config_parse_set_status
, "STATUS" },
4323 { config_parse_service_sockets
, "SOCKETS" },
4324 { config_parse_environ
, "ENVIRON" },
4326 { config_parse_syscall_filter
, "SYSCALLS" },
4327 { config_parse_syscall_archs
, "ARCHS" },
4328 { config_parse_syscall_errno
, "ERRNO" },
4329 { config_parse_address_families
, "FAMILIES" },
4331 { config_parse_cpu_shares
, "SHARES" },
4332 { config_parse_cpu_weight
, "WEIGHT" },
4333 { config_parse_memory_limit
, "LIMIT" },
4334 { config_parse_device_allow
, "DEVICE" },
4335 { config_parse_device_policy
, "POLICY" },
4336 { config_parse_io_limit
, "LIMIT" },
4337 { config_parse_io_weight
, "WEIGHT" },
4338 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4339 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4340 { config_parse_blockio_weight
, "WEIGHT" },
4341 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4342 { config_parse_long
, "LONG" },
4343 { config_parse_socket_service
, "SERVICE" },
4345 { config_parse_exec_selinux_context
, "LABEL" },
4347 { config_parse_job_mode
, "MODE" },
4348 { config_parse_job_mode_isolate
, "BOOLEAN" },
4349 { config_parse_personality
, "PERSONALITY" },
4352 const char *prev
= NULL
;
4357 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4358 const char *rvalue
= "OTHER", *lvalue
;
4362 const ConfigPerfItem
*p
;
4364 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4366 dot
= strchr(i
, '.');
4367 lvalue
= dot
? dot
+ 1 : i
;
4371 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4375 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4378 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4379 if (p
->parse
== table
[j
].callback
) {
4380 rvalue
= table
[j
].rvalue
;
4384 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);