1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2012 Holger Hans Peter Freyther
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <linux/oom.h>
32 #include <sys/resource.h>
36 #include "alloc-util.h"
37 #include "bus-error.h"
38 #include "bus-internal.h"
41 #include "capability-util.h"
43 #include "conf-parser.h"
44 #include "cpu-set-util.h"
46 #include "errno-list.h"
51 #include "load-fragment.h"
54 #include "parse-util.h"
55 #include "path-util.h"
56 #include "process-util.h"
58 #include "seccomp-util.h"
60 #include "securebits.h"
61 #include "signal-util.h"
62 #include "stat-util.h"
63 #include "string-util.h"
65 #include "unit-name.h"
66 #include "unit-printf.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(const char *unit
,
495 const char *filename
,
498 unsigned section_line
,
505 ExecContext
*c
= data
;
513 r
= safe_atoi(rvalue
, &priority
);
515 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
519 if (priority
< PRIO_MIN
|| priority
>= PRIO_MAX
) {
520 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Nice priority out of range, 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;
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
< 2; i
++) {
615 /* We accept an absolute path as first argument, or
616 * alternatively an absolute prefixed with @ to allow
617 * overriding of argv[0]. */
618 if (*f
== '-' && !ignore
)
620 else if (*f
== '@' && !separate_argv0
)
621 separate_argv0
= true;
628 /* First word is either "-" or "@" with no command. */
629 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty path in command line, ignoring: \"%s\"", rvalue
);
632 if (!string_is_safe(f
)) {
633 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path contains special characters, ignoring: %s", rvalue
);
636 if (!path_is_absolute(f
)) {
637 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path is not absolute, ignoring: %s", rvalue
);
640 if (endswith(f
, "/")) {
641 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path specifies a directory, ignoring: %s", rvalue
);
645 if (f
== firstword
) {
654 if (!separate_argv0
) {
655 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
664 path_kill_slashes(path
);
666 while (!isempty(p
)) {
667 _cleanup_free_
char *word
= NULL
;
669 /* Check explicitly for an unquoted semicolon as
670 * command separator token. */
671 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
673 p
+= strspn(p
, WHITESPACE
);
678 /* Check for \; explicitly, to not confuse it with \\;
679 * or "\;" or "\\;" etc. extract_first_word would
680 * return the same for all of those. */
681 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
683 p
+= strspn(p
, WHITESPACE
);
684 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
694 r
= extract_first_word_and_warn(&p
, &word
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
700 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
708 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue
);
712 nce
= new0(ExecCommand
, 1);
718 nce
->ignore
= ignore
;
720 exec_command_append_list(e
, nce
);
722 /* Do not _cleanup_free_ these. */
733 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
734 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
736 int config_parse_socket_bindtodevice(const char* unit
,
737 const char *filename
,
740 unsigned section_line
,
755 if (rvalue
[0] && !streq(rvalue
, "*")) {
762 free(s
->bind_to_device
);
763 s
->bind_to_device
= n
;
768 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
769 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
771 int config_parse_exec_io_class(const char *unit
,
772 const char *filename
,
775 unsigned section_line
,
782 ExecContext
*c
= data
;
790 x
= ioprio_class_from_string(rvalue
);
792 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
796 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
797 c
->ioprio_set
= true;
802 int config_parse_exec_io_priority(const char *unit
,
803 const char *filename
,
806 unsigned section_line
,
813 ExecContext
*c
= data
;
821 r
= safe_atoi(rvalue
, &i
);
822 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
823 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
827 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
828 c
->ioprio_set
= true;
833 int config_parse_exec_cpu_sched_policy(const char *unit
,
834 const char *filename
,
837 unsigned section_line
,
845 ExecContext
*c
= data
;
853 x
= sched_policy_from_string(rvalue
);
855 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
859 c
->cpu_sched_policy
= x
;
860 /* Moving to or from real-time policy? We need to adjust the priority */
861 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
862 c
->cpu_sched_set
= true;
867 int config_parse_exec_cpu_sched_prio(const char *unit
,
868 const char *filename
,
871 unsigned section_line
,
878 ExecContext
*c
= data
;
886 r
= safe_atoi(rvalue
, &i
);
888 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
892 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
893 min
= sched_get_priority_min(c
->cpu_sched_policy
);
894 max
= sched_get_priority_max(c
->cpu_sched_policy
);
896 if (i
< min
|| i
> max
) {
897 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
901 c
->cpu_sched_priority
= i
;
902 c
->cpu_sched_set
= true;
907 int config_parse_exec_cpu_affinity(const char *unit
,
908 const char *filename
,
911 unsigned section_line
,
918 ExecContext
*c
= data
;
919 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
927 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
935 /* An empty assignment resets the CPU list */
941 c
->cpuset_ncpus
= ncpus
;
946 int config_parse_exec_capabilities(const char *unit
,
947 const char *filename
,
950 unsigned section_line
,
957 ExecContext
*c
= data
;
965 cap
= cap_from_text(rvalue
);
967 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse capabilities, ignoring: %s", rvalue
);
972 cap_free(c
->capabilities
);
973 c
->capabilities
= cap
;
978 int config_parse_exec_secure_bits(const char *unit
,
979 const char *filename
,
982 unsigned section_line
,
989 ExecContext
*c
= data
;
991 const char *word
, *state
;
998 if (isempty(rvalue
)) {
999 /* An empty assignment resets the field */
1004 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
1005 if (first_word(word
, "keep-caps"))
1006 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
1007 else if (first_word(word
, "keep-caps-locked"))
1008 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
1009 else if (first_word(word
, "no-setuid-fixup"))
1010 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
1011 else if (first_word(word
, "no-setuid-fixup-locked"))
1012 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
1013 else if (first_word(word
, "noroot"))
1014 c
->secure_bits
|= 1<<SECURE_NOROOT
;
1015 else if (first_word(word
, "noroot-locked"))
1016 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
1018 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse secure bits, ignoring: %s", rvalue
);
1022 if (!isempty(state
))
1023 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, garbage at the end, ignoring.");
1028 int config_parse_capability_set(
1030 const char *filename
,
1032 const char *section
,
1033 unsigned section_line
,
1040 uint64_t *capability_set
= data
;
1041 uint64_t sum
= 0, initial
= 0;
1042 bool invert
= false;
1050 if (rvalue
[0] == '~') {
1055 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1056 initial
= CAP_ALL
; /* initialized to all bits on */
1057 /* else "AmbientCapabilities" initialized to all bits off */
1061 _cleanup_free_
char *word
= NULL
;
1064 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1070 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1074 cap
= capability_from_name(word
);
1076 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1080 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1083 sum
= invert
? ~sum
: sum
;
1085 if (sum
== 0 || *capability_set
== initial
)
1086 /* "" or uninitialized data -> replace */
1087 *capability_set
= sum
;
1089 /* previous data -> merge */
1090 *capability_set
|= sum
;
1095 static int rlim_parse_u64(const char *val
, rlim_t
*res
) {
1098 if (streq(val
, "infinity"))
1099 *res
= RLIM_INFINITY
;
1103 /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
1104 assert_cc(sizeof(rlim_t
) == sizeof(uint64_t));
1106 r
= safe_atou64(val
, &u
);
1107 if (r
>= 0 && u
>= (uint64_t) RLIM_INFINITY
)
1115 static int rlim_parse_size(const char *val
, rlim_t
*res
) {
1118 if (streq(val
, "infinity"))
1119 *res
= RLIM_INFINITY
;
1123 r
= parse_size(val
, 1024, &u
);
1124 if (r
>= 0 && u
>= (uint64_t) RLIM_INFINITY
)
1132 static int rlim_parse_sec(const char *val
, rlim_t
*res
) {
1135 if (streq(val
, "infinity"))
1136 *res
= RLIM_INFINITY
;
1140 r
= parse_sec(val
, &t
);
1143 if (t
== USEC_INFINITY
)
1144 *res
= RLIM_INFINITY
;
1146 *res
= (rlim_t
) (DIV_ROUND_UP(t
, USEC_PER_SEC
));
1152 static int rlim_parse_usec(const char *val
, rlim_t
*res
) {
1155 if (streq(val
, "infinity"))
1156 *res
= RLIM_INFINITY
;
1160 r
= parse_time(val
, &t
, 1);
1163 if (t
== USEC_INFINITY
)
1164 *res
= RLIM_INFINITY
;
1171 static int parse_rlimit_range(
1173 const char *filename
,
1177 int (*rlim_parser
)(const char *, rlim_t
*)) {
1179 const char *whole_value
= value
;
1181 _cleanup_free_
char *sword
= NULL
, *hword
= NULL
;
1186 /* <value> or <soft:hard> */
1187 nwords
= extract_many_words(&value
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
, &sword
, &hword
, NULL
);
1188 r
= nwords
< 0 ? nwords
: nwords
== 0 ? -EINVAL
: 0;
1191 r
= rlim_parser(sword
, &soft
);
1192 if (r
== 0 && nwords
== 2)
1193 r
= rlim_parser(hword
, &hard
);
1195 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", whole_value
);
1198 if (nwords
== 2 && soft
> hard
)
1199 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid resource value ("RLIM_FMT
" > "RLIM_FMT
"), ignoring: %s", soft
, hard
, whole_value
);
1202 *rl
= new(struct rlimit
, 1);
1206 (*rl
)->rlim_cur
= soft
;
1207 (*rl
)->rlim_max
= nwords
== 2 ? hard
: soft
;
1211 int config_parse_limit(
1213 const char *filename
,
1215 const char *section
,
1216 unsigned section_line
,
1223 struct rlimit
**rl
= data
;
1231 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_u64
);
1234 int config_parse_bytes_limit(
1236 const char *filename
,
1238 const char *section
,
1239 unsigned section_line
,
1246 struct rlimit
**rl
= data
;
1254 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_size
);
1257 int config_parse_sec_limit(
1259 const char *filename
,
1261 const char *section
,
1262 unsigned section_line
,
1269 struct rlimit
**rl
= data
;
1277 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_sec
);
1280 int config_parse_usec_limit(
1282 const char *filename
,
1284 const char *section
,
1285 unsigned section_line
,
1292 struct rlimit
**rl
= data
;
1300 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_usec
);
1305 #ifdef HAVE_SYSV_COMPAT
1306 int config_parse_sysv_priority(const char *unit
,
1307 const char *filename
,
1309 const char *section
,
1310 unsigned section_line
,
1317 int *priority
= data
;
1325 r
= safe_atoi(rvalue
, &i
);
1326 if (r
< 0 || i
< 0) {
1327 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1331 *priority
= (int) i
;
1336 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1337 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1339 int config_parse_exec_mount_flags(const char *unit
,
1340 const char *filename
,
1342 const char *section
,
1343 unsigned section_line
,
1351 unsigned long flags
= 0;
1352 ExecContext
*c
= data
;
1359 if (streq(rvalue
, "shared"))
1361 else if (streq(rvalue
, "slave"))
1363 else if (streq(rvalue
, "private"))
1366 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1370 c
->mount_flags
= flags
;
1375 int config_parse_exec_selinux_context(
1377 const char *filename
,
1379 const char *section
,
1380 unsigned section_line
,
1387 ExecContext
*c
= data
;
1398 if (isempty(rvalue
)) {
1399 c
->selinux_context
= mfree(c
->selinux_context
);
1400 c
->selinux_context_ignore
= false;
1404 if (rvalue
[0] == '-') {
1410 r
= unit_name_printf(u
, rvalue
, &k
);
1412 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1416 free(c
->selinux_context
);
1417 c
->selinux_context
= k
;
1418 c
->selinux_context_ignore
= ignore
;
1423 int config_parse_exec_apparmor_profile(
1425 const char *filename
,
1427 const char *section
,
1428 unsigned section_line
,
1435 ExecContext
*c
= data
;
1446 if (isempty(rvalue
)) {
1447 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1448 c
->apparmor_profile_ignore
= false;
1452 if (rvalue
[0] == '-') {
1458 r
= unit_name_printf(u
, rvalue
, &k
);
1460 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1464 free(c
->apparmor_profile
);
1465 c
->apparmor_profile
= k
;
1466 c
->apparmor_profile_ignore
= ignore
;
1471 int config_parse_exec_smack_process_label(
1473 const char *filename
,
1475 const char *section
,
1476 unsigned section_line
,
1483 ExecContext
*c
= data
;
1494 if (isempty(rvalue
)) {
1495 c
->smack_process_label
= mfree(c
->smack_process_label
);
1496 c
->smack_process_label_ignore
= false;
1500 if (rvalue
[0] == '-') {
1506 r
= unit_name_printf(u
, rvalue
, &k
);
1508 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1512 free(c
->smack_process_label
);
1513 c
->smack_process_label
= k
;
1514 c
->smack_process_label_ignore
= ignore
;
1519 int config_parse_timer(const char *unit
,
1520 const char *filename
,
1522 const char *section
,
1523 unsigned section_line
,
1534 CalendarSpec
*c
= NULL
;
1541 if (isempty(rvalue
)) {
1542 /* Empty assignment resets list */
1543 timer_free_values(t
);
1547 b
= timer_base_from_string(lvalue
);
1549 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1553 if (b
== TIMER_CALENDAR
) {
1554 if (calendar_spec_from_string(rvalue
, &c
) < 0) {
1555 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", rvalue
);
1559 if (parse_sec(rvalue
, &u
) < 0) {
1560 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", rvalue
);
1565 v
= new0(TimerValue
, 1);
1567 calendar_spec_free(c
);
1573 v
->calendar_spec
= c
;
1575 LIST_PREPEND(value
, t
->values
, v
);
1580 int config_parse_trigger_unit(
1582 const char *filename
,
1584 const char *section
,
1585 unsigned section_line
,
1592 _cleanup_free_
char *p
= NULL
;
1602 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1603 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1607 r
= unit_name_printf(u
, rvalue
, &p
);
1609 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1613 type
= unit_name_to_type(p
);
1615 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1619 if (type
== u
->type
) {
1620 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1624 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1626 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1633 int config_parse_path_spec(const char *unit
,
1634 const char *filename
,
1636 const char *section
,
1637 unsigned section_line
,
1647 _cleanup_free_
char *k
= NULL
;
1655 if (isempty(rvalue
)) {
1656 /* Empty assignment clears list */
1661 b
= path_type_from_string(lvalue
);
1663 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1667 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1669 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1673 if (!path_is_absolute(k
)) {
1674 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1678 s
= new0(PathSpec
, 1);
1683 s
->path
= path_kill_slashes(k
);
1688 LIST_PREPEND(spec
, p
->specs
, s
);
1693 int config_parse_socket_service(
1695 const char *filename
,
1697 const char *section
,
1698 unsigned section_line
,
1705 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1706 _cleanup_free_
char *p
= NULL
;
1716 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1718 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1722 if (!endswith(p
, ".service")) {
1723 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1727 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1729 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1733 unit_ref_set(&s
->service
, x
);
1738 int config_parse_fdname(
1740 const char *filename
,
1742 const char *section
,
1743 unsigned section_line
,
1750 _cleanup_free_
char *p
= NULL
;
1759 if (isempty(rvalue
)) {
1760 s
->fdname
= mfree(s
->fdname
);
1764 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1766 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1770 if (!fdname_is_valid(p
)) {
1771 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1782 int config_parse_service_sockets(
1784 const char *filename
,
1786 const char *section
,
1787 unsigned section_line
,
1805 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1807 r
= extract_first_word(&p
, &word
, NULL
, 0);
1813 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1817 r
= unit_name_printf(UNIT(s
), word
, &k
);
1819 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1823 if (!endswith(k
, ".socket")) {
1824 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1828 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1830 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1832 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1834 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1840 int config_parse_bus_name(
1842 const char *filename
,
1844 const char *section
,
1845 unsigned section_line
,
1852 _cleanup_free_
char *k
= NULL
;
1861 r
= unit_full_printf(u
, rvalue
, &k
);
1863 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1867 if (!service_name_is_valid(k
)) {
1868 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1872 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1875 int config_parse_service_timeout(const char *unit
,
1876 const char *filename
,
1878 const char *section
,
1879 unsigned section_line
,
1886 Service
*s
= userdata
;
1894 r
= config_parse_sec(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
1895 rvalue
, data
, userdata
);
1899 if (streq(lvalue
, "TimeoutSec")) {
1900 s
->start_timeout_defined
= true;
1901 s
->timeout_stop_usec
= s
->timeout_start_usec
;
1902 } else if (streq(lvalue
, "TimeoutStartSec"))
1903 s
->start_timeout_defined
= true;
1908 int config_parse_busname_service(
1910 const char *filename
,
1912 const char *section
,
1913 unsigned section_line
,
1920 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1924 _cleanup_free_
char *p
= NULL
;
1931 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
1933 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1937 if (!endswith(p
, ".service")) {
1938 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1942 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
1944 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1948 unit_ref_set(&n
->service
, x
);
1953 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
1955 int config_parse_bus_policy(
1957 const char *filename
,
1959 const char *section
,
1960 unsigned section_line
,
1967 _cleanup_free_ BusNamePolicy
*p
= NULL
;
1968 _cleanup_free_
char *id_str
= NULL
;
1969 BusName
*busname
= data
;
1977 p
= new0(BusNamePolicy
, 1);
1981 if (streq(lvalue
, "AllowUser"))
1982 p
->type
= BUSNAME_POLICY_TYPE_USER
;
1983 else if (streq(lvalue
, "AllowGroup"))
1984 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
1986 assert_not_reached("Unknown lvalue");
1988 id_str
= strdup(rvalue
);
1992 access_str
= strpbrk(id_str
, WHITESPACE
);
1994 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
2000 access_str
+= strspn(access_str
, WHITESPACE
);
2002 p
->access
= bus_policy_access_from_string(access_str
);
2003 if (p
->access
< 0) {
2004 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
2011 LIST_PREPEND(policy
, busname
->policy
, p
);
2017 int config_parse_bus_endpoint_policy(
2019 const char *filename
,
2021 const char *section
,
2022 unsigned section_line
,
2029 _cleanup_free_
char *name
= NULL
;
2030 BusPolicyAccess access
;
2031 ExecContext
*c
= data
;
2040 name
= strdup(rvalue
);
2044 access_str
= strpbrk(name
, WHITESPACE
);
2046 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid endpoint policy value '%s'", rvalue
);
2052 access_str
+= strspn(access_str
, WHITESPACE
);
2054 access
= bus_policy_access_from_string(access_str
);
2055 if (access
<= _BUS_POLICY_ACCESS_INVALID
||
2056 access
>= _BUS_POLICY_ACCESS_MAX
) {
2057 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid endpoint policy access type '%s'", access_str
);
2061 if (!c
->bus_endpoint
) {
2062 r
= bus_endpoint_new(&c
->bus_endpoint
);
2064 return log_error_errno(r
, "Failed to create bus endpoint object: %m");
2067 return bus_endpoint_add_policy(c
->bus_endpoint
, name
, access
);
2070 int config_parse_working_directory(
2072 const char *filename
,
2074 const char *section
,
2075 unsigned section_line
,
2082 ExecContext
*c
= data
;
2093 if (rvalue
[0] == '-') {
2099 if (streq(rvalue
, "~")) {
2100 c
->working_directory_home
= true;
2101 c
->working_directory
= mfree(c
->working_directory
);
2103 _cleanup_free_
char *k
= NULL
;
2105 r
= unit_full_printf(u
, rvalue
, &k
);
2107 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2111 path_kill_slashes(k
);
2113 if (!utf8_is_valid(k
)) {
2114 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2118 if (!path_is_absolute(k
)) {
2119 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2123 free(c
->working_directory
);
2124 c
->working_directory
= k
;
2127 c
->working_directory_home
= false;
2130 c
->working_directory_missing_ok
= missing_ok
;
2134 int config_parse_unit_env_file(const char *unit
,
2135 const char *filename
,
2137 const char *section
,
2138 unsigned section_line
,
2147 _cleanup_free_
char *n
= NULL
;
2155 if (isempty(rvalue
)) {
2156 /* Empty assignment frees the list */
2157 *env
= strv_free(*env
);
2161 r
= unit_full_printf(u
, rvalue
, &n
);
2163 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2167 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2168 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2172 r
= strv_extend(env
, n
);
2179 int config_parse_environ(const char *unit
,
2180 const char *filename
,
2182 const char *section
,
2183 unsigned section_line
,
2192 const char *word
, *state
;
2194 _cleanup_free_
char *k
= NULL
;
2202 if (isempty(rvalue
)) {
2203 /* Empty assignment resets the list */
2204 *env
= strv_free(*env
);
2209 r
= unit_full_printf(u
, rvalue
, &k
);
2211 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2222 FOREACH_WORD_QUOTED(word
, l
, k
, state
) {
2223 _cleanup_free_
char *n
= NULL
;
2226 r
= cunescape_length(word
, l
, 0, &n
);
2228 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Couldn't unescape assignment, ignoring: %s", rvalue
);
2232 if (!env_assignment_is_valid(n
)) {
2233 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid environment assignment, ignoring: %s", rvalue
);
2237 x
= strv_env_set(*env
, n
);
2244 if (!isempty(state
))
2245 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2250 int config_parse_pass_environ(const char *unit
,
2251 const char *filename
,
2253 const char *section
,
2254 unsigned section_line
,
2261 const char *whole_rvalue
= rvalue
;
2262 char*** passenv
= data
;
2263 _cleanup_strv_free_
char **n
= NULL
;
2264 size_t nlen
= 0, nbufsize
= 0;
2272 if (isempty(rvalue
)) {
2273 /* Empty assignment resets the list */
2274 *passenv
= strv_free(*passenv
);
2279 _cleanup_free_
char *word
= NULL
;
2281 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
);
2287 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2288 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2292 if (!env_name_is_valid(word
)) {
2293 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2294 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2298 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2306 r
= strv_extend_strv(passenv
, n
, true);
2314 int config_parse_ip_tos(const char *unit
,
2315 const char *filename
,
2317 const char *section
,
2318 unsigned section_line
,
2325 int *ip_tos
= data
, x
;
2332 x
= ip_tos_from_string(rvalue
);
2334 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2342 int config_parse_unit_condition_path(
2344 const char *filename
,
2346 const char *section
,
2347 unsigned section_line
,
2354 _cleanup_free_
char *p
= NULL
;
2355 Condition
**list
= data
, *c
;
2356 ConditionType t
= ltype
;
2357 bool trigger
, negate
;
2366 if (isempty(rvalue
)) {
2367 /* Empty assignment resets the list */
2368 *list
= condition_free_list(*list
);
2372 trigger
= rvalue
[0] == '|';
2376 negate
= rvalue
[0] == '!';
2380 r
= unit_full_printf(u
, rvalue
, &p
);
2382 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2386 if (!path_is_absolute(p
)) {
2387 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2391 c
= condition_new(t
, p
, trigger
, negate
);
2395 LIST_PREPEND(conditions
, *list
, c
);
2399 int config_parse_unit_condition_string(
2401 const char *filename
,
2403 const char *section
,
2404 unsigned section_line
,
2411 _cleanup_free_
char *s
= NULL
;
2412 Condition
**list
= data
, *c
;
2413 ConditionType t
= ltype
;
2414 bool trigger
, negate
;
2423 if (isempty(rvalue
)) {
2424 /* Empty assignment resets the list */
2425 *list
= condition_free_list(*list
);
2429 trigger
= rvalue
[0] == '|';
2433 negate
= rvalue
[0] == '!';
2437 r
= unit_full_printf(u
, rvalue
, &s
);
2439 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2443 c
= condition_new(t
, s
, trigger
, negate
);
2447 LIST_PREPEND(conditions
, *list
, c
);
2451 int config_parse_unit_condition_null(
2453 const char *filename
,
2455 const char *section
,
2456 unsigned section_line
,
2463 Condition
**list
= data
, *c
;
2464 bool trigger
, negate
;
2472 if (isempty(rvalue
)) {
2473 /* Empty assignment resets the list */
2474 *list
= condition_free_list(*list
);
2478 trigger
= rvalue
[0] == '|';
2482 negate
= rvalue
[0] == '!';
2486 b
= parse_boolean(rvalue
);
2488 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2495 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2499 LIST_PREPEND(conditions
, *list
, c
);
2503 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2504 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action
, failure_action
, FailureAction
, "Failed to parse failure action specifier");
2506 int config_parse_unit_requires_mounts_for(
2508 const char *filename
,
2510 const char *section
,
2511 unsigned section_line
,
2519 const char *word
, *state
;
2527 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2529 _cleanup_free_
char *n
;
2531 n
= strndup(word
, l
);
2535 if (!utf8_is_valid(n
)) {
2536 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2540 r
= unit_require_mounts_for(u
, n
);
2542 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount for, ignoring: %s", rvalue
);
2546 if (!isempty(state
))
2547 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2552 int config_parse_documentation(const char *unit
,
2553 const char *filename
,
2555 const char *section
,
2556 unsigned section_line
,
2572 if (isempty(rvalue
)) {
2573 /* Empty assignment resets the list */
2574 u
->documentation
= strv_free(u
->documentation
);
2578 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2579 rvalue
, data
, userdata
);
2583 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2585 if (documentation_url_is_valid(*a
))
2588 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2599 int config_parse_syscall_filter(
2601 const char *filename
,
2603 const char *section
,
2604 unsigned section_line
,
2611 static const char default_syscalls
[] =
2618 ExecContext
*c
= data
;
2620 bool invert
= false;
2621 const char *word
, *state
;
2630 if (isempty(rvalue
)) {
2631 /* Empty assignment resets the list */
2632 c
->syscall_filter
= set_free(c
->syscall_filter
);
2633 c
->syscall_whitelist
= false;
2637 if (rvalue
[0] == '~') {
2642 if (!c
->syscall_filter
) {
2643 c
->syscall_filter
= set_new(NULL
);
2644 if (!c
->syscall_filter
)
2648 /* Allow everything but the ones listed */
2649 c
->syscall_whitelist
= false;
2653 /* Allow nothing but the ones listed */
2654 c
->syscall_whitelist
= true;
2656 /* Accept default syscalls if we are on a whitelist */
2657 NULSTR_FOREACH(i
, default_syscalls
) {
2660 id
= seccomp_syscall_resolve_name(i
);
2664 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2673 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2674 _cleanup_free_
char *t
= NULL
;
2677 t
= strndup(word
, l
);
2681 id
= seccomp_syscall_resolve_name(t
);
2683 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2687 /* If we previously wanted to forbid a syscall and now
2688 * we want to allow it, then remove it from the list
2690 if (!invert
== c
->syscall_whitelist
) {
2691 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2697 set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2699 if (!isempty(state
))
2700 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2702 /* Turn on NNP, but only if it wasn't configured explicitly
2703 * before, and only if we are in user mode. */
2704 if (!c
->no_new_privileges_set
&& u
->manager
->running_as
== MANAGER_USER
)
2705 c
->no_new_privileges
= true;
2710 int config_parse_syscall_archs(
2712 const char *filename
,
2714 const char *section
,
2715 unsigned section_line
,
2723 const char *word
, *state
;
2727 if (isempty(rvalue
)) {
2728 *archs
= set_free(*archs
);
2732 r
= set_ensure_allocated(archs
, NULL
);
2736 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2737 _cleanup_free_
char *t
= NULL
;
2740 t
= strndup(word
, l
);
2744 r
= seccomp_arch_from_string(t
, &a
);
2746 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call architecture, ignoring: %s", t
);
2750 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2756 if (!isempty(state
))
2757 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2762 int config_parse_syscall_errno(
2764 const char *filename
,
2766 const char *section
,
2767 unsigned section_line
,
2774 ExecContext
*c
= data
;
2781 if (isempty(rvalue
)) {
2782 /* Empty assignment resets to KILL */
2783 c
->syscall_errno
= 0;
2787 e
= errno_from_name(rvalue
);
2789 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2793 c
->syscall_errno
= e
;
2797 int config_parse_address_families(
2799 const char *filename
,
2801 const char *section
,
2802 unsigned section_line
,
2809 ExecContext
*c
= data
;
2810 bool invert
= false;
2811 const char *word
, *state
;
2819 if (isempty(rvalue
)) {
2820 /* Empty assignment resets the list */
2821 c
->address_families
= set_free(c
->address_families
);
2822 c
->address_families_whitelist
= false;
2826 if (rvalue
[0] == '~') {
2831 if (!c
->address_families
) {
2832 c
->address_families
= set_new(NULL
);
2833 if (!c
->address_families
)
2836 c
->address_families_whitelist
= !invert
;
2839 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2840 _cleanup_free_
char *t
= NULL
;
2843 t
= strndup(word
, l
);
2847 af
= af_from_name(t
);
2849 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse address family, ignoring: %s", t
);
2853 /* If we previously wanted to forbid an address family and now
2854 * we want to allow it, then remove it from the list
2856 if (!invert
== c
->address_families_whitelist
) {
2857 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2863 set_remove(c
->address_families
, INT_TO_PTR(af
));
2865 if (!isempty(state
))
2866 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2872 int config_parse_unit_slice(
2874 const char *filename
,
2876 const char *section
,
2877 unsigned section_line
,
2884 _cleanup_free_
char *k
= NULL
;
2885 Unit
*u
= userdata
, *slice
= NULL
;
2893 r
= unit_name_printf(u
, rvalue
, &k
);
2895 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2899 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2901 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2905 r
= unit_set_slice(u
, slice
);
2907 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2914 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2916 int config_parse_cpu_shares(
2918 const char *filename
,
2920 const char *section
,
2921 unsigned section_line
,
2928 uint64_t *shares
= data
;
2935 r
= cg_cpu_shares_parse(rvalue
, shares
);
2937 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2944 int config_parse_cpu_quota(
2946 const char *filename
,
2948 const char *section
,
2949 unsigned section_line
,
2956 CGroupContext
*c
= data
;
2963 if (isempty(rvalue
)) {
2964 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2968 if (!endswith(rvalue
, "%")) {
2969 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue
);
2973 if (sscanf(rvalue
, "%lf%%", &percent
) != 1 || percent
<= 0) {
2974 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' invalid. Ignoring.", rvalue
);
2978 c
->cpu_quota_per_sec_usec
= (usec_t
) (percent
* USEC_PER_SEC
/ 100);
2983 int config_parse_memory_limit(
2985 const char *filename
,
2987 const char *section
,
2988 unsigned section_line
,
2995 CGroupContext
*c
= data
;
2999 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
3000 c
->memory_limit
= (uint64_t) -1;
3004 r
= parse_size(rvalue
, 1024, &bytes
);
3005 if (r
< 0 || bytes
< 1) {
3006 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3010 c
->memory_limit
= bytes
;
3014 int config_parse_tasks_max(
3016 const char *filename
,
3018 const char *section
,
3019 unsigned section_line
,
3026 uint64_t *tasks_max
= data
, u
;
3029 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
3030 *tasks_max
= (uint64_t) -1;
3034 r
= safe_atou64(rvalue
, &u
);
3035 if (r
< 0 || u
< 1) {
3036 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3044 int config_parse_device_allow(
3046 const char *filename
,
3048 const char *section
,
3049 unsigned section_line
,
3056 _cleanup_free_
char *path
= NULL
;
3057 CGroupContext
*c
= data
;
3058 CGroupDeviceAllow
*a
;
3062 if (isempty(rvalue
)) {
3063 while (c
->device_allow
)
3064 cgroup_context_free_device_allow(c
, c
->device_allow
);
3069 n
= strcspn(rvalue
, WHITESPACE
);
3070 path
= strndup(rvalue
, n
);
3074 if (!startswith(path
, "/dev/") &&
3075 !startswith(path
, "block-") &&
3076 !startswith(path
, "char-")) {
3077 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3081 m
= rvalue
+ n
+ strspn(rvalue
+ n
, WHITESPACE
);
3085 if (!in_charset(m
, "rwm")) {
3086 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3090 a
= new0(CGroupDeviceAllow
, 1);
3096 a
->r
= !!strchr(m
, 'r');
3097 a
->w
= !!strchr(m
, 'w');
3098 a
->m
= !!strchr(m
, 'm');
3100 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3104 int config_parse_blockio_weight(
3106 const char *filename
,
3108 const char *section
,
3109 unsigned section_line
,
3116 uint64_t *weight
= data
;
3123 r
= cg_blkio_weight_parse(rvalue
, weight
);
3125 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3132 int config_parse_blockio_device_weight(
3134 const char *filename
,
3136 const char *section
,
3137 unsigned section_line
,
3144 _cleanup_free_
char *path
= NULL
;
3145 CGroupBlockIODeviceWeight
*w
;
3146 CGroupContext
*c
= data
;
3156 if (isempty(rvalue
)) {
3157 while (c
->blockio_device_weights
)
3158 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3163 n
= strcspn(rvalue
, WHITESPACE
);
3164 weight
= rvalue
+ n
;
3165 weight
+= strspn(weight
, WHITESPACE
);
3167 if (isempty(weight
)) {
3168 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3172 path
= strndup(rvalue
, n
);
3176 if (!path_startswith(path
, "/dev")) {
3177 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3181 r
= cg_blkio_weight_parse(weight
, &u
);
3183 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3187 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3189 w
= new0(CGroupBlockIODeviceWeight
, 1);
3198 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3202 int config_parse_blockio_bandwidth(
3204 const char *filename
,
3206 const char *section
,
3207 unsigned section_line
,
3214 _cleanup_free_
char *path
= NULL
;
3215 CGroupBlockIODeviceBandwidth
*b
;
3216 CGroupContext
*c
= data
;
3217 const char *bandwidth
;
3227 read
= streq("BlockIOReadBandwidth", lvalue
);
3229 if (isempty(rvalue
)) {
3230 CGroupBlockIODeviceBandwidth
*next
;
3232 LIST_FOREACH_SAFE (device_bandwidths
, b
, next
, c
->blockio_device_bandwidths
)
3233 if (b
->read
== read
)
3234 cgroup_context_free_blockio_device_bandwidth(c
, b
);
3239 n
= strcspn(rvalue
, WHITESPACE
);
3240 bandwidth
= rvalue
+ n
;
3241 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3244 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3248 path
= strndup(rvalue
, n
);
3252 if (!path_startswith(path
, "/dev")) {
3253 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3257 r
= parse_size(bandwidth
, 1000, &bytes
);
3258 if (r
< 0 || bytes
<= 0) {
3259 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3263 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3269 b
->bandwidth
= bytes
;
3272 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3277 int config_parse_netclass(
3279 const char *filename
,
3281 const char *section
,
3282 unsigned section_line
,
3289 CGroupContext
*c
= data
;
3297 if (streq(rvalue
, "auto")) {
3298 c
->netclass_type
= CGROUP_NETCLASS_TYPE_AUTO
;
3302 r
= safe_atou32(rvalue
, &v
);
3304 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Netclass '%s' invalid. Ignoring.", rvalue
);
3308 if (v
> CGROUP_NETCLASS_FIXED_MAX
)
3309 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3310 "Fixed netclass %" PRIu32
" out of allowed range (0-%d). Applying anyway.", v
, (uint32_t) CGROUP_NETCLASS_FIXED_MAX
);
3313 c
->netclass_type
= CGROUP_NETCLASS_TYPE_FIXED
;
3318 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3320 int config_parse_job_mode_isolate(
3322 const char *filename
,
3324 const char *section
,
3325 unsigned section_line
,
3339 r
= parse_boolean(rvalue
);
3341 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3345 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3349 int config_parse_runtime_directory(
3351 const char *filename
,
3353 const char *section
,
3354 unsigned section_line
,
3363 const char *word
, *state
;
3372 if (isempty(rvalue
)) {
3373 /* Empty assignment resets the list */
3374 *rt
= strv_free(*rt
);
3378 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3379 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3381 t
= strndup(word
, l
);
3385 r
= unit_name_printf(u
, t
, &n
);
3387 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3391 if (!filename_is_valid(n
)) {
3392 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3396 r
= strv_push(rt
, n
);
3402 if (!isempty(state
))
3403 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3408 int config_parse_set_status(
3410 const char *filename
,
3412 const char *section
,
3413 unsigned section_line
,
3421 const char *word
, *state
;
3423 ExitStatusSet
*status_set
= data
;
3430 /* Empty assignment resets the list */
3431 if (isempty(rvalue
)) {
3432 exit_status_set_free(status_set
);
3436 FOREACH_WORD(word
, l
, rvalue
, state
) {
3437 _cleanup_free_
char *temp
;
3441 temp
= strndup(word
, l
);
3445 r
= safe_atoi(temp
, &val
);
3447 val
= signal_from_string_try_harder(temp
);
3450 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3453 set
= &status_set
->signal
;
3455 if (val
< 0 || val
> 255) {
3456 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3459 set
= &status_set
->status
;
3462 r
= set_ensure_allocated(set
, NULL
);
3466 r
= set_put(*set
, INT_TO_PTR(val
));
3468 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3472 if (!isempty(state
))
3473 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3478 int config_parse_namespace_path_strv(
3480 const char *filename
,
3482 const char *section
,
3483 unsigned section_line
,
3500 if (isempty(rvalue
)) {
3501 /* Empty assignment resets the list */
3502 *sv
= strv_free(*sv
);
3506 prev
= cur
= rvalue
;
3508 _cleanup_free_
char *word
= NULL
;
3511 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3517 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3521 if (!utf8_is_valid(word
)) {
3522 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3527 offset
= word
[0] == '-';
3528 if (!path_is_absolute(word
+ offset
)) {
3529 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3534 path_kill_slashes(word
+ offset
);
3536 r
= strv_push(sv
, word
);
3547 int config_parse_no_new_privileges(
3549 const char *filename
,
3551 const char *section
,
3552 unsigned section_line
,
3559 ExecContext
*c
= data
;
3567 k
= parse_boolean(rvalue
);
3569 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3573 c
->no_new_privileges
= !!k
;
3574 c
->no_new_privileges_set
= true;
3579 int config_parse_protect_home(
3581 const char *filename
,
3583 const char *section
,
3584 unsigned section_line
,
3591 ExecContext
*c
= data
;
3599 /* Our enum shall be a superset of booleans, hence first try
3600 * to parse as as boolean, and then as enum */
3602 k
= parse_boolean(rvalue
);
3604 c
->protect_home
= PROTECT_HOME_YES
;
3606 c
->protect_home
= PROTECT_HOME_NO
;
3610 h
= protect_home_from_string(rvalue
);
3612 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3616 c
->protect_home
= h
;
3622 int config_parse_protect_system(
3624 const char *filename
,
3626 const char *section
,
3627 unsigned section_line
,
3634 ExecContext
*c
= data
;
3642 /* Our enum shall be a superset of booleans, hence first try
3643 * to parse as as boolean, and then as enum */
3645 k
= parse_boolean(rvalue
);
3647 c
->protect_system
= PROTECT_SYSTEM_YES
;
3649 c
->protect_system
= PROTECT_SYSTEM_NO
;
3653 s
= protect_system_from_string(rvalue
);
3655 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3659 c
->protect_system
= s
;
3665 #define FOLLOW_MAX 8
3667 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3678 /* This will update the filename pointer if the loaded file is
3679 * reached by a symlink. The old string will be freed. */
3682 char *target
, *name
;
3684 if (c
++ >= FOLLOW_MAX
)
3687 path_kill_slashes(*filename
);
3689 /* Add the file name we are currently looking at to
3690 * the names of this unit, but only if it is a valid
3692 name
= basename(*filename
);
3694 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3696 id
= set_get(names
, name
);
3702 r
= set_consume(names
, id
);
3708 /* Try to open the file name, but don't if its a symlink */
3709 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3716 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3717 r
= readlink_and_make_absolute(*filename
, &target
);
3725 f
= fdopen(fd
, "re");
3736 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
3744 /* Let's try to add in all symlink names we found */
3745 while ((k
= set_steal_first(names
))) {
3747 /* First try to merge in the other name into our
3749 r
= unit_merge_by_name(*u
, k
);
3753 /* Hmm, we couldn't merge the other unit into
3754 * ours? Then let's try it the other way
3757 other
= manager_get_unit((*u
)->manager
, k
);
3761 r
= unit_merge(other
, *u
);
3764 return merge_by_names(u
, names
, NULL
);
3772 unit_choose_id(*u
, id
);
3780 static int load_from_path(Unit
*u
, const char *path
) {
3782 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
3783 _cleanup_fclose_
FILE *f
= NULL
;
3784 _cleanup_free_
char *filename
= NULL
;
3792 symlink_names
= set_new(&string_hash_ops
);
3796 if (path_is_absolute(path
)) {
3798 filename
= strdup(path
);
3802 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3804 filename
= mfree(filename
);
3812 STRV_FOREACH(p
, u
->manager
->lookup_paths
.unit_path
) {
3814 /* Instead of opening the path right away, we manually
3815 * follow all symlinks and add their name to our unit
3816 * name set while doing so */
3817 filename
= path_make_absolute(path
, *p
);
3821 if (u
->manager
->unit_path_cache
&&
3822 !set_get(u
->manager
->unit_path_cache
, filename
))
3825 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3828 filename
= mfree(filename
);
3832 /* Empty the symlink names for the next run */
3833 set_clear_free(symlink_names
);
3842 /* Hmm, no suitable file found? */
3846 r
= merge_by_names(&merged
, symlink_names
, id
);
3851 u
->load_state
= UNIT_MERGED
;
3855 if (fstat(fileno(f
), &st
) < 0)
3858 if (null_or_empty(&st
))
3859 u
->load_state
= UNIT_MASKED
;
3861 u
->load_state
= UNIT_LOADED
;
3863 /* Now, parse the file contents */
3864 r
= config_parse(u
->id
, filename
, f
,
3865 UNIT_VTABLE(u
)->sections
,
3866 config_item_perf_lookup
, load_fragment_gperf_lookup
,
3867 false, true, false, u
);
3872 free(u
->fragment_path
);
3873 u
->fragment_path
= filename
;
3876 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
3878 if (u
->source_path
) {
3879 if (stat(u
->source_path
, &st
) >= 0)
3880 u
->source_mtime
= timespec_load(&st
.st_mtim
);
3882 u
->source_mtime
= 0;
3888 int unit_load_fragment(Unit
*u
) {
3894 assert(u
->load_state
== UNIT_STUB
);
3898 u
->load_state
= UNIT_LOADED
;
3902 /* First, try to find the unit under its id. We always look
3903 * for unit files in the default directories, to make it easy
3904 * to override things by placing things in /etc/systemd/system */
3905 r
= load_from_path(u
, u
->id
);
3909 /* Try to find an alias we can load this with */
3910 if (u
->load_state
== UNIT_STUB
) {
3911 SET_FOREACH(t
, u
->names
, i
) {
3916 r
= load_from_path(u
, t
);
3920 if (u
->load_state
!= UNIT_STUB
)
3925 /* And now, try looking for it under the suggested (originally linked) path */
3926 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
3928 r
= load_from_path(u
, u
->fragment_path
);
3932 if (u
->load_state
== UNIT_STUB
)
3933 /* Hmm, this didn't work? Then let's get rid
3934 * of the fragment path stored for us, so that
3935 * we don't point to an invalid location. */
3936 u
->fragment_path
= mfree(u
->fragment_path
);
3939 /* Look for a template */
3940 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
3941 _cleanup_free_
char *k
= NULL
;
3943 r
= unit_name_template(u
->id
, &k
);
3947 r
= load_from_path(u
, k
);
3951 if (u
->load_state
== UNIT_STUB
) {
3952 SET_FOREACH(t
, u
->names
, i
) {
3953 _cleanup_free_
char *z
= NULL
;
3958 r
= unit_name_template(t
, &z
);
3962 r
= load_from_path(u
, z
);
3966 if (u
->load_state
!= UNIT_STUB
)
3975 void unit_dump_config_items(FILE *f
) {
3976 static const struct {
3977 const ConfigParserCallback callback
;
3980 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3981 { config_parse_warn_compat
, "NOTSUPPORTED" },
3983 { config_parse_int
, "INTEGER" },
3984 { config_parse_unsigned
, "UNSIGNED" },
3985 { config_parse_iec_size
, "SIZE" },
3986 { config_parse_iec_uint64
, "SIZE" },
3987 { config_parse_si_size
, "SIZE" },
3988 { config_parse_bool
, "BOOLEAN" },
3989 { config_parse_string
, "STRING" },
3990 { config_parse_path
, "PATH" },
3991 { config_parse_unit_path_printf
, "PATH" },
3992 { config_parse_strv
, "STRING [...]" },
3993 { config_parse_exec_nice
, "NICE" },
3994 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
3995 { config_parse_exec_io_class
, "IOCLASS" },
3996 { config_parse_exec_io_priority
, "IOPRIORITY" },
3997 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
3998 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
3999 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4000 { config_parse_mode
, "MODE" },
4001 { config_parse_unit_env_file
, "FILE" },
4002 { config_parse_output
, "OUTPUT" },
4003 { config_parse_input
, "INPUT" },
4004 { config_parse_log_facility
, "FACILITY" },
4005 { config_parse_log_level
, "LEVEL" },
4006 { config_parse_exec_capabilities
, "CAPABILITIES" },
4007 { config_parse_exec_secure_bits
, "SECUREBITS" },
4008 { config_parse_capability_set
, "BOUNDINGSET" },
4009 { config_parse_limit
, "LIMIT" },
4010 { config_parse_unit_deps
, "UNIT [...]" },
4011 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4012 { config_parse_service_type
, "SERVICETYPE" },
4013 { config_parse_service_restart
, "SERVICERESTART" },
4014 #ifdef HAVE_SYSV_COMPAT
4015 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4017 { config_parse_kill_mode
, "KILLMODE" },
4018 { config_parse_signal
, "SIGNAL" },
4019 { config_parse_socket_listen
, "SOCKET [...]" },
4020 { config_parse_socket_bind
, "SOCKETBIND" },
4021 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4022 { config_parse_sec
, "SECONDS" },
4023 { config_parse_nsec
, "NANOSECONDS" },
4024 { config_parse_namespace_path_strv
, "PATH [...]" },
4025 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4026 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4027 { config_parse_unit_string_printf
, "STRING" },
4028 { config_parse_trigger_unit
, "UNIT" },
4029 { config_parse_timer
, "TIMER" },
4030 { config_parse_path_spec
, "PATH" },
4031 { config_parse_notify_access
, "ACCESS" },
4032 { config_parse_ip_tos
, "TOS" },
4033 { config_parse_unit_condition_path
, "CONDITION" },
4034 { config_parse_unit_condition_string
, "CONDITION" },
4035 { config_parse_unit_condition_null
, "CONDITION" },
4036 { config_parse_unit_slice
, "SLICE" },
4037 { config_parse_documentation
, "URL" },
4038 { config_parse_service_timeout
, "SECONDS" },
4039 { config_parse_failure_action
, "ACTION" },
4040 { config_parse_set_status
, "STATUS" },
4041 { config_parse_service_sockets
, "SOCKETS" },
4042 { config_parse_environ
, "ENVIRON" },
4044 { config_parse_syscall_filter
, "SYSCALLS" },
4045 { config_parse_syscall_archs
, "ARCHS" },
4046 { config_parse_syscall_errno
, "ERRNO" },
4047 { config_parse_address_families
, "FAMILIES" },
4049 { config_parse_cpu_shares
, "SHARES" },
4050 { config_parse_memory_limit
, "LIMIT" },
4051 { config_parse_device_allow
, "DEVICE" },
4052 { config_parse_device_policy
, "POLICY" },
4053 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4054 { config_parse_blockio_weight
, "WEIGHT" },
4055 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4056 { config_parse_long
, "LONG" },
4057 { config_parse_socket_service
, "SERVICE" },
4059 { config_parse_exec_selinux_context
, "LABEL" },
4061 { config_parse_job_mode
, "MODE" },
4062 { config_parse_job_mode_isolate
, "BOOLEAN" },
4063 { config_parse_personality
, "PERSONALITY" },
4066 const char *prev
= NULL
;
4071 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4072 const char *rvalue
= "OTHER", *lvalue
;
4076 const ConfigPerfItem
*p
;
4078 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4080 dot
= strchr(i
, '.');
4081 lvalue
= dot
? dot
+ 1 : i
;
4085 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4089 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4092 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4093 if (p
->parse
== table
[j
].callback
) {
4094 rvalue
= table
[j
].rvalue
;
4098 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);