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"
42 #include "conf-parser.h"
43 #include "cpu-set-util.h"
45 #include "errno-list.h"
50 #include "load-fragment.h"
53 #include "parse-util.h"
54 #include "path-util.h"
55 #include "process-util.h"
57 #include "seccomp-util.h"
59 #include "securebits.h"
60 #include "signal-util.h"
61 #include "stat-util.h"
62 #include "string-util.h"
64 #include "unit-name.h"
65 #include "unit-printf.h"
70 int config_parse_warn_compat(
75 unsigned section_line
,
81 Disabled reason
= ltype
;
84 case DISABLED_CONFIGURATION
:
85 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
86 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
89 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
90 "Support for option %s= has been removed and it is ignored", lvalue
);
92 case DISABLED_EXPERIMENTAL
:
93 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
94 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
101 int config_parse_unit_deps(
103 const char *filename
,
106 unsigned section_line
,
113 UnitDependency d
= ltype
;
123 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
126 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
132 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
136 r
= unit_name_printf(u
, word
, &k
);
138 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
142 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
144 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
150 int config_parse_obsolete_unit_deps(
152 const char *filename
,
155 unsigned section_line
,
162 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
163 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
165 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
168 int config_parse_unit_string_printf(
170 const char *filename
,
173 unsigned section_line
,
180 _cleanup_free_
char *k
= NULL
;
189 r
= unit_full_printf(u
, rvalue
, &k
);
191 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
195 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
198 int config_parse_unit_strv_printf(
200 const char *filename
,
203 unsigned section_line
,
211 _cleanup_free_
char *k
= NULL
;
219 r
= unit_full_printf(u
, rvalue
, &k
);
221 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
225 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
228 int config_parse_unit_path_printf(
230 const char *filename
,
233 unsigned section_line
,
240 _cleanup_free_
char *k
= NULL
;
249 r
= unit_full_printf(u
, rvalue
, &k
);
251 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
255 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
258 int config_parse_unit_path_strv_printf(
260 const char *filename
,
263 unsigned section_line
,
271 const char *word
, *state
;
281 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
282 _cleanup_free_
char *k
= NULL
;
288 r
= unit_full_printf(u
, t
, &k
);
290 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", t
);
294 if (!utf8_is_valid(k
)) {
295 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
299 if (!path_is_absolute(k
)) {
300 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Symlink path %s is not absolute, ignoring: %m", k
);
304 path_kill_slashes(k
);
313 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, ignoring.");
318 int config_parse_socket_listen(const char *unit
,
319 const char *filename
,
322 unsigned section_line
,
329 _cleanup_free_ SocketPort
*p
= NULL
;
341 if (isempty(rvalue
)) {
342 /* An empty assignment removes all ports */
343 socket_free_ports(s
);
347 p
= new0(SocketPort
, 1);
351 if (ltype
!= SOCKET_SOCKET
) {
354 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
356 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
360 path_kill_slashes(p
->path
);
362 } else if (streq(lvalue
, "ListenNetlink")) {
363 _cleanup_free_
char *k
= NULL
;
365 p
->type
= SOCKET_SOCKET
;
366 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
368 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
372 r
= socket_address_parse_netlink(&p
->address
, k
);
374 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
379 _cleanup_free_
char *k
= NULL
;
381 p
->type
= SOCKET_SOCKET
;
382 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
384 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
388 r
= socket_address_parse_and_warn(&p
->address
, k
);
390 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
394 if (streq(lvalue
, "ListenStream"))
395 p
->address
.type
= SOCK_STREAM
;
396 else if (streq(lvalue
, "ListenDatagram"))
397 p
->address
.type
= SOCK_DGRAM
;
399 assert(streq(lvalue
, "ListenSequentialPacket"));
400 p
->address
.type
= SOCK_SEQPACKET
;
403 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
404 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
410 p
->auxiliary_fds
= NULL
;
411 p
->n_auxiliary_fds
= 0;
415 LIST_FIND_TAIL(port
, s
->ports
, tail
);
416 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
418 LIST_PREPEND(port
, s
->ports
, p
);
424 int config_parse_socket_protocol(const char *unit
,
425 const char *filename
,
428 unsigned section_line
,
443 if (streq(rvalue
, "udplite"))
444 s
->socket_protocol
= IPPROTO_UDPLITE
;
445 else if (streq(rvalue
, "sctp"))
446 s
->socket_protocol
= IPPROTO_SCTP
;
448 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
455 int config_parse_socket_bind(const char *unit
,
456 const char *filename
,
459 unsigned section_line
,
467 SocketAddressBindIPv6Only b
;
476 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
480 r
= parse_boolean(rvalue
);
482 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
486 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
488 s
->bind_ipv6_only
= b
;
493 int config_parse_exec_nice(const char *unit
,
494 const char *filename
,
497 unsigned section_line
,
504 ExecContext
*c
= data
;
512 r
= safe_atoi(rvalue
, &priority
);
514 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
518 if (priority
< PRIO_MIN
|| priority
>= PRIO_MAX
) {
519 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Nice priority out of range, ignoring: %s", rvalue
);
529 int config_parse_exec_oom_score_adjust(const char* unit
,
530 const char *filename
,
533 unsigned section_line
,
540 ExecContext
*c
= data
;
548 r
= safe_atoi(rvalue
, &oa
);
550 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
554 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
555 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
559 c
->oom_score_adjust
= oa
;
560 c
->oom_score_adjust_set
= true;
565 int config_parse_exec(
567 const char *filename
,
570 unsigned section_line
,
577 ExecCommand
**e
= data
;
588 rvalue
+= strspn(rvalue
, WHITESPACE
);
590 if (isempty(rvalue
)) {
591 /* An empty assignment resets the list */
592 *e
= exec_command_free_list(*e
);
598 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
599 bool separate_argv0
= false, ignore
= false;
600 _cleanup_free_ ExecCommand
*nce
= NULL
;
601 _cleanup_strv_free_
char **n
= NULL
;
602 size_t nlen
= 0, nbufsize
= 0;
608 r
= extract_first_word_and_warn(&p
, &firstword
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
613 for (i
= 0; i
< 2; i
++) {
614 /* We accept an absolute path as first argument, or
615 * alternatively an absolute prefixed with @ to allow
616 * overriding of argv[0]. */
617 if (*f
== '-' && !ignore
)
619 else if (*f
== '@' && !separate_argv0
)
620 separate_argv0
= true;
627 /* First word is either "-" or "@" with no command. */
628 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty path in command line, ignoring: \"%s\"", rvalue
);
631 if (!string_is_safe(f
)) {
632 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path contains special characters, ignoring: %s", rvalue
);
635 if (!path_is_absolute(f
)) {
636 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path is not absolute, ignoring: %s", rvalue
);
639 if (endswith(f
, "/")) {
640 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path specifies a directory, ignoring: %s", rvalue
);
644 if (f
== firstword
) {
653 if (!separate_argv0
) {
654 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
663 path_kill_slashes(path
);
665 while (!isempty(p
)) {
666 _cleanup_free_
char *word
= NULL
;
668 /* Check explicitly for an unquoted semicolon as
669 * command separator token. */
670 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
672 p
+= strspn(p
, WHITESPACE
);
677 /* Check for \; explicitly, to not confuse it with \\;
678 * or "\;" or "\\;" etc. extract_first_word would
679 * return the same for all of those. */
680 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
682 p
+= strspn(p
, WHITESPACE
);
683 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
693 r
= extract_first_word_and_warn(&p
, &word
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
699 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
707 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue
);
711 nce
= new0(ExecCommand
, 1);
717 nce
->ignore
= ignore
;
719 exec_command_append_list(e
, nce
);
721 /* Do not _cleanup_free_ these. */
732 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
733 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
735 int config_parse_socket_bindtodevice(const char* unit
,
736 const char *filename
,
739 unsigned section_line
,
754 if (rvalue
[0] && !streq(rvalue
, "*")) {
761 free(s
->bind_to_device
);
762 s
->bind_to_device
= n
;
767 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
768 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
770 int config_parse_exec_io_class(const char *unit
,
771 const char *filename
,
774 unsigned section_line
,
781 ExecContext
*c
= data
;
789 x
= ioprio_class_from_string(rvalue
);
791 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
795 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
796 c
->ioprio_set
= true;
801 int config_parse_exec_io_priority(const char *unit
,
802 const char *filename
,
805 unsigned section_line
,
812 ExecContext
*c
= data
;
820 r
= safe_atoi(rvalue
, &i
);
821 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
822 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
826 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
827 c
->ioprio_set
= true;
832 int config_parse_exec_cpu_sched_policy(const char *unit
,
833 const char *filename
,
836 unsigned section_line
,
844 ExecContext
*c
= data
;
852 x
= sched_policy_from_string(rvalue
);
854 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
858 c
->cpu_sched_policy
= x
;
859 /* Moving to or from real-time policy? We need to adjust the priority */
860 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
861 c
->cpu_sched_set
= true;
866 int config_parse_exec_cpu_sched_prio(const char *unit
,
867 const char *filename
,
870 unsigned section_line
,
877 ExecContext
*c
= data
;
885 r
= safe_atoi(rvalue
, &i
);
887 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
891 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
892 min
= sched_get_priority_min(c
->cpu_sched_policy
);
893 max
= sched_get_priority_max(c
->cpu_sched_policy
);
895 if (i
< min
|| i
> max
) {
896 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
900 c
->cpu_sched_priority
= i
;
901 c
->cpu_sched_set
= true;
906 int config_parse_exec_cpu_affinity(const char *unit
,
907 const char *filename
,
910 unsigned section_line
,
917 ExecContext
*c
= data
;
918 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
926 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
934 /* An empty assignment resets the CPU list */
940 c
->cpuset_ncpus
= ncpus
;
945 int config_parse_exec_capabilities(const char *unit
,
946 const char *filename
,
949 unsigned section_line
,
956 ExecContext
*c
= data
;
964 cap
= cap_from_text(rvalue
);
966 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse capabilities, ignoring: %s", rvalue
);
971 cap_free(c
->capabilities
);
972 c
->capabilities
= cap
;
977 int config_parse_exec_secure_bits(const char *unit
,
978 const char *filename
,
981 unsigned section_line
,
988 ExecContext
*c
= data
;
990 const char *word
, *state
;
997 if (isempty(rvalue
)) {
998 /* An empty assignment resets the field */
1003 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
1004 if (first_word(word
, "keep-caps"))
1005 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
1006 else if (first_word(word
, "keep-caps-locked"))
1007 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
1008 else if (first_word(word
, "no-setuid-fixup"))
1009 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
1010 else if (first_word(word
, "no-setuid-fixup-locked"))
1011 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
1012 else if (first_word(word
, "noroot"))
1013 c
->secure_bits
|= 1<<SECURE_NOROOT
;
1014 else if (first_word(word
, "noroot-locked"))
1015 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
1017 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse secure bits, ignoring: %s", rvalue
);
1021 if (!isempty(state
))
1022 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, garbage at the end, ignoring.");
1027 int config_parse_bounding_set(
1029 const char *filename
,
1031 const char *section
,
1032 unsigned section_line
,
1039 uint64_t *capability_bounding_set_drop
= data
;
1040 uint64_t capability_bounding_set
, sum
= 0;
1041 bool invert
= false;
1049 if (rvalue
[0] == '~') {
1054 /* Note that we store this inverted internally, since the
1055 * kernel wants it like this. But we actually expose it
1056 * non-inverted everywhere to have a fully normalized
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 set, ignoring: %s", word
);
1080 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1083 capability_bounding_set
= invert
? ~sum
: sum
;
1084 if (*capability_bounding_set_drop
!= 0 && capability_bounding_set
!= 0)
1085 *capability_bounding_set_drop
= ~(~*capability_bounding_set_drop
| capability_bounding_set
);
1087 *capability_bounding_set_drop
= ~capability_bounding_set
;
1092 static int rlim_parse_u64(const char *val
, rlim_t
*res
) {
1095 if (streq(val
, "infinity"))
1096 *res
= RLIM_INFINITY
;
1100 /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
1101 assert_cc(sizeof(rlim_t
) == sizeof(uint64_t));
1103 r
= safe_atou64(val
, &u
);
1104 if (r
>= 0 && u
>= (uint64_t) RLIM_INFINITY
)
1112 static int rlim_parse_size(const char *val
, rlim_t
*res
) {
1115 if (streq(val
, "infinity"))
1116 *res
= RLIM_INFINITY
;
1120 r
= parse_size(val
, 1024, &u
);
1121 if (r
>= 0 && u
>= (uint64_t) RLIM_INFINITY
)
1129 static int rlim_parse_sec(const char *val
, rlim_t
*res
) {
1132 if (streq(val
, "infinity"))
1133 *res
= RLIM_INFINITY
;
1137 r
= parse_sec(val
, &t
);
1140 if (t
== USEC_INFINITY
)
1141 *res
= RLIM_INFINITY
;
1143 *res
= (rlim_t
) (DIV_ROUND_UP(t
, USEC_PER_SEC
));
1149 static int rlim_parse_usec(const char *val
, rlim_t
*res
) {
1152 if (streq(val
, "infinity"))
1153 *res
= RLIM_INFINITY
;
1157 r
= parse_time(val
, &t
, 1);
1160 if (t
== USEC_INFINITY
)
1161 *res
= RLIM_INFINITY
;
1168 static int parse_rlimit_range(
1170 const char *filename
,
1174 int (*rlim_parser
)(const char *, rlim_t
*)) {
1176 const char *whole_value
= value
;
1178 _cleanup_free_
char *sword
= NULL
, *hword
= NULL
;
1183 /* <value> or <soft:hard> */
1184 nwords
= extract_many_words(&value
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
, &sword
, &hword
, NULL
);
1185 r
= nwords
< 0 ? nwords
: nwords
== 0 ? -EINVAL
: 0;
1188 r
= rlim_parser(sword
, &soft
);
1189 if (r
== 0 && nwords
== 2)
1190 r
= rlim_parser(hword
, &hard
);
1192 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", whole_value
);
1195 if (nwords
== 2 && soft
> hard
)
1196 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid resource value ("RLIM_FMT
" > "RLIM_FMT
"), ignoring: %s", soft
, hard
, whole_value
);
1199 *rl
= new(struct rlimit
, 1);
1203 (*rl
)->rlim_cur
= soft
;
1204 (*rl
)->rlim_max
= nwords
== 2 ? hard
: soft
;
1208 int config_parse_limit(
1210 const char *filename
,
1212 const char *section
,
1213 unsigned section_line
,
1220 struct rlimit
**rl
= data
;
1228 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_u64
);
1231 int config_parse_bytes_limit(
1233 const char *filename
,
1235 const char *section
,
1236 unsigned section_line
,
1243 struct rlimit
**rl
= data
;
1251 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_size
);
1254 int config_parse_sec_limit(
1256 const char *filename
,
1258 const char *section
,
1259 unsigned section_line
,
1266 struct rlimit
**rl
= data
;
1274 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_sec
);
1277 int config_parse_usec_limit(
1279 const char *filename
,
1281 const char *section
,
1282 unsigned section_line
,
1289 struct rlimit
**rl
= data
;
1297 return parse_rlimit_range(unit
, filename
, line
, rvalue
, rl
, rlim_parse_usec
);
1302 #ifdef HAVE_SYSV_COMPAT
1303 int config_parse_sysv_priority(const char *unit
,
1304 const char *filename
,
1306 const char *section
,
1307 unsigned section_line
,
1314 int *priority
= data
;
1322 r
= safe_atoi(rvalue
, &i
);
1323 if (r
< 0 || i
< 0) {
1324 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1328 *priority
= (int) i
;
1333 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1334 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1336 int config_parse_exec_mount_flags(const char *unit
,
1337 const char *filename
,
1339 const char *section
,
1340 unsigned section_line
,
1348 unsigned long flags
= 0;
1349 ExecContext
*c
= data
;
1356 if (streq(rvalue
, "shared"))
1358 else if (streq(rvalue
, "slave"))
1360 else if (streq(rvalue
, "private"))
1363 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1367 c
->mount_flags
= flags
;
1372 int config_parse_exec_selinux_context(
1374 const char *filename
,
1376 const char *section
,
1377 unsigned section_line
,
1384 ExecContext
*c
= data
;
1395 if (isempty(rvalue
)) {
1396 c
->selinux_context
= mfree(c
->selinux_context
);
1397 c
->selinux_context_ignore
= false;
1401 if (rvalue
[0] == '-') {
1407 r
= unit_name_printf(u
, rvalue
, &k
);
1409 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1413 free(c
->selinux_context
);
1414 c
->selinux_context
= k
;
1415 c
->selinux_context_ignore
= ignore
;
1420 int config_parse_exec_apparmor_profile(
1422 const char *filename
,
1424 const char *section
,
1425 unsigned section_line
,
1432 ExecContext
*c
= data
;
1443 if (isempty(rvalue
)) {
1444 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1445 c
->apparmor_profile_ignore
= false;
1449 if (rvalue
[0] == '-') {
1455 r
= unit_name_printf(u
, rvalue
, &k
);
1457 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1461 free(c
->apparmor_profile
);
1462 c
->apparmor_profile
= k
;
1463 c
->apparmor_profile_ignore
= ignore
;
1468 int config_parse_exec_smack_process_label(
1470 const char *filename
,
1472 const char *section
,
1473 unsigned section_line
,
1480 ExecContext
*c
= data
;
1491 if (isempty(rvalue
)) {
1492 c
->smack_process_label
= mfree(c
->smack_process_label
);
1493 c
->smack_process_label_ignore
= false;
1497 if (rvalue
[0] == '-') {
1503 r
= unit_name_printf(u
, rvalue
, &k
);
1505 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1509 free(c
->smack_process_label
);
1510 c
->smack_process_label
= k
;
1511 c
->smack_process_label_ignore
= ignore
;
1516 int config_parse_timer(const char *unit
,
1517 const char *filename
,
1519 const char *section
,
1520 unsigned section_line
,
1531 CalendarSpec
*c
= NULL
;
1538 if (isempty(rvalue
)) {
1539 /* Empty assignment resets list */
1540 timer_free_values(t
);
1544 b
= timer_base_from_string(lvalue
);
1546 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1550 if (b
== TIMER_CALENDAR
) {
1551 if (calendar_spec_from_string(rvalue
, &c
) < 0) {
1552 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", rvalue
);
1556 if (parse_sec(rvalue
, &u
) < 0) {
1557 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", rvalue
);
1562 v
= new0(TimerValue
, 1);
1564 calendar_spec_free(c
);
1570 v
->calendar_spec
= c
;
1572 LIST_PREPEND(value
, t
->values
, v
);
1577 int config_parse_trigger_unit(
1579 const char *filename
,
1581 const char *section
,
1582 unsigned section_line
,
1589 _cleanup_free_
char *p
= NULL
;
1599 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1600 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1604 r
= unit_name_printf(u
, rvalue
, &p
);
1606 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1610 type
= unit_name_to_type(p
);
1612 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1616 if (type
== u
->type
) {
1617 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1621 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1623 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1630 int config_parse_path_spec(const char *unit
,
1631 const char *filename
,
1633 const char *section
,
1634 unsigned section_line
,
1644 _cleanup_free_
char *k
= NULL
;
1652 if (isempty(rvalue
)) {
1653 /* Empty assignment clears list */
1658 b
= path_type_from_string(lvalue
);
1660 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1664 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1666 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1670 if (!path_is_absolute(k
)) {
1671 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1675 s
= new0(PathSpec
, 1);
1680 s
->path
= path_kill_slashes(k
);
1685 LIST_PREPEND(spec
, p
->specs
, s
);
1690 int config_parse_socket_service(
1692 const char *filename
,
1694 const char *section
,
1695 unsigned section_line
,
1702 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1703 _cleanup_free_
char *p
= NULL
;
1713 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1715 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1719 if (!endswith(p
, ".service")) {
1720 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1724 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1726 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1730 unit_ref_set(&s
->service
, x
);
1735 int config_parse_fdname(
1737 const char *filename
,
1739 const char *section
,
1740 unsigned section_line
,
1747 _cleanup_free_
char *p
= NULL
;
1756 if (isempty(rvalue
)) {
1757 s
->fdname
= mfree(s
->fdname
);
1761 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1763 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1767 if (!fdname_is_valid(p
)) {
1768 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1779 int config_parse_service_sockets(
1781 const char *filename
,
1783 const char *section
,
1784 unsigned section_line
,
1802 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1804 r
= extract_first_word(&p
, &word
, NULL
, 0);
1810 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1814 r
= unit_name_printf(UNIT(s
), word
, &k
);
1816 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1820 if (!endswith(k
, ".socket")) {
1821 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1825 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1827 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1829 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1831 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1837 int config_parse_bus_name(
1839 const char *filename
,
1841 const char *section
,
1842 unsigned section_line
,
1849 _cleanup_free_
char *k
= NULL
;
1858 r
= unit_full_printf(u
, rvalue
, &k
);
1860 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1864 if (!service_name_is_valid(k
)) {
1865 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1869 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1872 int config_parse_service_timeout(const char *unit
,
1873 const char *filename
,
1875 const char *section
,
1876 unsigned section_line
,
1883 Service
*s
= userdata
;
1891 r
= config_parse_sec(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
1892 rvalue
, data
, userdata
);
1896 if (streq(lvalue
, "TimeoutSec")) {
1897 s
->start_timeout_defined
= true;
1898 s
->timeout_stop_usec
= s
->timeout_start_usec
;
1899 } else if (streq(lvalue
, "TimeoutStartSec"))
1900 s
->start_timeout_defined
= true;
1905 int config_parse_busname_service(
1907 const char *filename
,
1909 const char *section
,
1910 unsigned section_line
,
1917 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1921 _cleanup_free_
char *p
= NULL
;
1928 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
1930 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1934 if (!endswith(p
, ".service")) {
1935 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1939 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
1941 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1945 unit_ref_set(&n
->service
, x
);
1950 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
1952 int config_parse_bus_policy(
1954 const char *filename
,
1956 const char *section
,
1957 unsigned section_line
,
1964 _cleanup_free_ BusNamePolicy
*p
= NULL
;
1965 _cleanup_free_
char *id_str
= NULL
;
1966 BusName
*busname
= data
;
1974 p
= new0(BusNamePolicy
, 1);
1978 if (streq(lvalue
, "AllowUser"))
1979 p
->type
= BUSNAME_POLICY_TYPE_USER
;
1980 else if (streq(lvalue
, "AllowGroup"))
1981 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
1983 assert_not_reached("Unknown lvalue");
1985 id_str
= strdup(rvalue
);
1989 access_str
= strpbrk(id_str
, WHITESPACE
);
1991 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
1997 access_str
+= strspn(access_str
, WHITESPACE
);
1999 p
->access
= bus_policy_access_from_string(access_str
);
2000 if (p
->access
< 0) {
2001 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
2008 LIST_PREPEND(policy
, busname
->policy
, p
);
2014 int config_parse_bus_endpoint_policy(
2016 const char *filename
,
2018 const char *section
,
2019 unsigned section_line
,
2026 _cleanup_free_
char *name
= NULL
;
2027 BusPolicyAccess access
;
2028 ExecContext
*c
= data
;
2037 name
= strdup(rvalue
);
2041 access_str
= strpbrk(name
, WHITESPACE
);
2043 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid endpoint policy value '%s'", rvalue
);
2049 access_str
+= strspn(access_str
, WHITESPACE
);
2051 access
= bus_policy_access_from_string(access_str
);
2052 if (access
<= _BUS_POLICY_ACCESS_INVALID
||
2053 access
>= _BUS_POLICY_ACCESS_MAX
) {
2054 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid endpoint policy access type '%s'", access_str
);
2058 if (!c
->bus_endpoint
) {
2059 r
= bus_endpoint_new(&c
->bus_endpoint
);
2061 return log_error_errno(r
, "Failed to create bus endpoint object: %m");
2064 return bus_endpoint_add_policy(c
->bus_endpoint
, name
, access
);
2067 int config_parse_working_directory(
2069 const char *filename
,
2071 const char *section
,
2072 unsigned section_line
,
2079 ExecContext
*c
= data
;
2090 if (rvalue
[0] == '-') {
2096 if (streq(rvalue
, "~")) {
2097 c
->working_directory_home
= true;
2098 c
->working_directory
= mfree(c
->working_directory
);
2100 _cleanup_free_
char *k
= NULL
;
2102 r
= unit_full_printf(u
, rvalue
, &k
);
2104 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2108 path_kill_slashes(k
);
2110 if (!utf8_is_valid(k
)) {
2111 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2115 if (!path_is_absolute(k
)) {
2116 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2120 free(c
->working_directory
);
2121 c
->working_directory
= k
;
2124 c
->working_directory_home
= false;
2127 c
->working_directory_missing_ok
= missing_ok
;
2131 int config_parse_unit_env_file(const char *unit
,
2132 const char *filename
,
2134 const char *section
,
2135 unsigned section_line
,
2144 _cleanup_free_
char *n
= NULL
;
2152 if (isempty(rvalue
)) {
2153 /* Empty assignment frees the list */
2154 *env
= strv_free(*env
);
2158 r
= unit_full_printf(u
, rvalue
, &n
);
2160 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2164 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2165 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2169 r
= strv_extend(env
, n
);
2176 int config_parse_environ(const char *unit
,
2177 const char *filename
,
2179 const char *section
,
2180 unsigned section_line
,
2189 const char *word
, *state
;
2191 _cleanup_free_
char *k
= NULL
;
2199 if (isempty(rvalue
)) {
2200 /* Empty assignment resets the list */
2201 *env
= strv_free(*env
);
2206 r
= unit_full_printf(u
, rvalue
, &k
);
2208 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2219 FOREACH_WORD_QUOTED(word
, l
, k
, state
) {
2220 _cleanup_free_
char *n
= NULL
;
2223 r
= cunescape_length(word
, l
, 0, &n
);
2225 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Couldn't unescape assignment, ignoring: %s", rvalue
);
2229 if (!env_assignment_is_valid(n
)) {
2230 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid environment assignment, ignoring: %s", rvalue
);
2234 x
= strv_env_set(*env
, n
);
2241 if (!isempty(state
))
2242 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2247 int config_parse_pass_environ(const char *unit
,
2248 const char *filename
,
2250 const char *section
,
2251 unsigned section_line
,
2258 const char *whole_rvalue
= rvalue
;
2259 char*** passenv
= data
;
2260 _cleanup_strv_free_
char **n
= NULL
;
2261 size_t nlen
= 0, nbufsize
= 0;
2269 if (isempty(rvalue
)) {
2270 /* Empty assignment resets the list */
2271 *passenv
= strv_free(*passenv
);
2276 _cleanup_free_
char *word
= NULL
;
2278 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
);
2284 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2285 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2289 if (!env_name_is_valid(word
)) {
2290 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2291 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2295 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2303 r
= strv_extend_strv(passenv
, n
, true);
2311 int config_parse_ip_tos(const char *unit
,
2312 const char *filename
,
2314 const char *section
,
2315 unsigned section_line
,
2322 int *ip_tos
= data
, x
;
2329 x
= ip_tos_from_string(rvalue
);
2331 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2339 int config_parse_unit_condition_path(
2341 const char *filename
,
2343 const char *section
,
2344 unsigned section_line
,
2351 _cleanup_free_
char *p
= NULL
;
2352 Condition
**list
= data
, *c
;
2353 ConditionType t
= ltype
;
2354 bool trigger
, negate
;
2363 if (isempty(rvalue
)) {
2364 /* Empty assignment resets the list */
2365 *list
= condition_free_list(*list
);
2369 trigger
= rvalue
[0] == '|';
2373 negate
= rvalue
[0] == '!';
2377 r
= unit_full_printf(u
, rvalue
, &p
);
2379 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2383 if (!path_is_absolute(p
)) {
2384 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2388 c
= condition_new(t
, p
, trigger
, negate
);
2392 LIST_PREPEND(conditions
, *list
, c
);
2396 int config_parse_unit_condition_string(
2398 const char *filename
,
2400 const char *section
,
2401 unsigned section_line
,
2408 _cleanup_free_
char *s
= NULL
;
2409 Condition
**list
= data
, *c
;
2410 ConditionType t
= ltype
;
2411 bool trigger
, negate
;
2420 if (isempty(rvalue
)) {
2421 /* Empty assignment resets the list */
2422 *list
= condition_free_list(*list
);
2426 trigger
= rvalue
[0] == '|';
2430 negate
= rvalue
[0] == '!';
2434 r
= unit_full_printf(u
, rvalue
, &s
);
2436 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2440 c
= condition_new(t
, s
, trigger
, negate
);
2444 LIST_PREPEND(conditions
, *list
, c
);
2448 int config_parse_unit_condition_null(
2450 const char *filename
,
2452 const char *section
,
2453 unsigned section_line
,
2460 Condition
**list
= data
, *c
;
2461 bool trigger
, negate
;
2469 if (isempty(rvalue
)) {
2470 /* Empty assignment resets the list */
2471 *list
= condition_free_list(*list
);
2475 trigger
= rvalue
[0] == '|';
2479 negate
= rvalue
[0] == '!';
2483 b
= parse_boolean(rvalue
);
2485 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2492 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2496 LIST_PREPEND(conditions
, *list
, c
);
2500 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2501 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action
, failure_action
, FailureAction
, "Failed to parse failure action specifier");
2503 int config_parse_unit_requires_mounts_for(
2505 const char *filename
,
2507 const char *section
,
2508 unsigned section_line
,
2516 const char *word
, *state
;
2524 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2526 _cleanup_free_
char *n
;
2528 n
= strndup(word
, l
);
2532 if (!utf8_is_valid(n
)) {
2533 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2537 r
= unit_require_mounts_for(u
, n
);
2539 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount for, ignoring: %s", rvalue
);
2543 if (!isempty(state
))
2544 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2549 int config_parse_documentation(const char *unit
,
2550 const char *filename
,
2552 const char *section
,
2553 unsigned section_line
,
2569 if (isempty(rvalue
)) {
2570 /* Empty assignment resets the list */
2571 u
->documentation
= strv_free(u
->documentation
);
2575 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2576 rvalue
, data
, userdata
);
2580 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2582 if (documentation_url_is_valid(*a
))
2585 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2596 int config_parse_syscall_filter(
2598 const char *filename
,
2600 const char *section
,
2601 unsigned section_line
,
2608 static const char default_syscalls
[] =
2615 ExecContext
*c
= data
;
2617 bool invert
= false;
2618 const char *word
, *state
;
2627 if (isempty(rvalue
)) {
2628 /* Empty assignment resets the list */
2629 c
->syscall_filter
= set_free(c
->syscall_filter
);
2630 c
->syscall_whitelist
= false;
2634 if (rvalue
[0] == '~') {
2639 if (!c
->syscall_filter
) {
2640 c
->syscall_filter
= set_new(NULL
);
2641 if (!c
->syscall_filter
)
2645 /* Allow everything but the ones listed */
2646 c
->syscall_whitelist
= false;
2650 /* Allow nothing but the ones listed */
2651 c
->syscall_whitelist
= true;
2653 /* Accept default syscalls if we are on a whitelist */
2654 NULSTR_FOREACH(i
, default_syscalls
) {
2657 id
= seccomp_syscall_resolve_name(i
);
2661 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2670 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2671 _cleanup_free_
char *t
= NULL
;
2674 t
= strndup(word
, l
);
2678 id
= seccomp_syscall_resolve_name(t
);
2680 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2684 /* If we previously wanted to forbid a syscall and now
2685 * we want to allow it, then remove it from the list
2687 if (!invert
== c
->syscall_whitelist
) {
2688 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2694 set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2696 if (!isempty(state
))
2697 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2699 /* Turn on NNP, but only if it wasn't configured explicitly
2700 * before, and only if we are in user mode. */
2701 if (!c
->no_new_privileges_set
&& u
->manager
->running_as
== MANAGER_USER
)
2702 c
->no_new_privileges
= true;
2707 int config_parse_syscall_archs(
2709 const char *filename
,
2711 const char *section
,
2712 unsigned section_line
,
2720 const char *word
, *state
;
2724 if (isempty(rvalue
)) {
2725 *archs
= set_free(*archs
);
2729 r
= set_ensure_allocated(archs
, NULL
);
2733 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2734 _cleanup_free_
char *t
= NULL
;
2737 t
= strndup(word
, l
);
2741 r
= seccomp_arch_from_string(t
, &a
);
2743 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call architecture, ignoring: %s", t
);
2747 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2753 if (!isempty(state
))
2754 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2759 int config_parse_syscall_errno(
2761 const char *filename
,
2763 const char *section
,
2764 unsigned section_line
,
2771 ExecContext
*c
= data
;
2778 if (isempty(rvalue
)) {
2779 /* Empty assignment resets to KILL */
2780 c
->syscall_errno
= 0;
2784 e
= errno_from_name(rvalue
);
2786 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2790 c
->syscall_errno
= e
;
2794 int config_parse_address_families(
2796 const char *filename
,
2798 const char *section
,
2799 unsigned section_line
,
2806 ExecContext
*c
= data
;
2807 bool invert
= false;
2808 const char *word
, *state
;
2816 if (isempty(rvalue
)) {
2817 /* Empty assignment resets the list */
2818 c
->address_families
= set_free(c
->address_families
);
2819 c
->address_families_whitelist
= false;
2823 if (rvalue
[0] == '~') {
2828 if (!c
->address_families
) {
2829 c
->address_families
= set_new(NULL
);
2830 if (!c
->address_families
)
2833 c
->address_families_whitelist
= !invert
;
2836 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2837 _cleanup_free_
char *t
= NULL
;
2840 t
= strndup(word
, l
);
2844 af
= af_from_name(t
);
2846 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse address family, ignoring: %s", t
);
2850 /* If we previously wanted to forbid an address family and now
2851 * we want to allow it, then remove it from the list
2853 if (!invert
== c
->address_families_whitelist
) {
2854 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2860 set_remove(c
->address_families
, INT_TO_PTR(af
));
2862 if (!isempty(state
))
2863 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2869 int config_parse_unit_slice(
2871 const char *filename
,
2873 const char *section
,
2874 unsigned section_line
,
2881 _cleanup_free_
char *k
= NULL
;
2882 Unit
*u
= userdata
, *slice
= NULL
;
2890 r
= unit_name_printf(u
, rvalue
, &k
);
2892 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2896 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2898 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2902 r
= unit_set_slice(u
, slice
);
2904 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2911 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2913 int config_parse_cpu_shares(
2915 const char *filename
,
2917 const char *section
,
2918 unsigned section_line
,
2925 uint64_t *shares
= data
;
2932 r
= cg_cpu_shares_parse(rvalue
, shares
);
2934 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2941 int config_parse_cpu_quota(
2943 const char *filename
,
2945 const char *section
,
2946 unsigned section_line
,
2953 CGroupContext
*c
= data
;
2960 if (isempty(rvalue
)) {
2961 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2965 if (!endswith(rvalue
, "%")) {
2966 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue
);
2970 if (sscanf(rvalue
, "%lf%%", &percent
) != 1 || percent
<= 0) {
2971 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' invalid. Ignoring.", rvalue
);
2975 c
->cpu_quota_per_sec_usec
= (usec_t
) (percent
* USEC_PER_SEC
/ 100);
2980 int config_parse_memory_limit(
2982 const char *filename
,
2984 const char *section
,
2985 unsigned section_line
,
2992 CGroupContext
*c
= data
;
2996 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
2997 c
->memory_limit
= (uint64_t) -1;
3001 r
= parse_size(rvalue
, 1024, &bytes
);
3002 if (r
< 0 || bytes
< 1) {
3003 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3007 c
->memory_limit
= bytes
;
3011 int config_parse_tasks_max(
3013 const char *filename
,
3015 const char *section
,
3016 unsigned section_line
,
3023 uint64_t *tasks_max
= data
, u
;
3026 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
3027 *tasks_max
= (uint64_t) -1;
3031 r
= safe_atou64(rvalue
, &u
);
3032 if (r
< 0 || u
< 1) {
3033 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3041 int config_parse_device_allow(
3043 const char *filename
,
3045 const char *section
,
3046 unsigned section_line
,
3053 _cleanup_free_
char *path
= NULL
;
3054 CGroupContext
*c
= data
;
3055 CGroupDeviceAllow
*a
;
3059 if (isempty(rvalue
)) {
3060 while (c
->device_allow
)
3061 cgroup_context_free_device_allow(c
, c
->device_allow
);
3066 n
= strcspn(rvalue
, WHITESPACE
);
3067 path
= strndup(rvalue
, n
);
3071 if (!startswith(path
, "/dev/") &&
3072 !startswith(path
, "block-") &&
3073 !startswith(path
, "char-")) {
3074 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3078 m
= rvalue
+ n
+ strspn(rvalue
+ n
, WHITESPACE
);
3082 if (!in_charset(m
, "rwm")) {
3083 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3087 a
= new0(CGroupDeviceAllow
, 1);
3093 a
->r
= !!strchr(m
, 'r');
3094 a
->w
= !!strchr(m
, 'w');
3095 a
->m
= !!strchr(m
, 'm');
3097 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3101 int config_parse_blockio_weight(
3103 const char *filename
,
3105 const char *section
,
3106 unsigned section_line
,
3113 uint64_t *weight
= data
;
3120 r
= cg_blkio_weight_parse(rvalue
, weight
);
3122 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3129 int config_parse_blockio_device_weight(
3131 const char *filename
,
3133 const char *section
,
3134 unsigned section_line
,
3141 _cleanup_free_
char *path
= NULL
;
3142 CGroupBlockIODeviceWeight
*w
;
3143 CGroupContext
*c
= data
;
3153 if (isempty(rvalue
)) {
3154 while (c
->blockio_device_weights
)
3155 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3160 n
= strcspn(rvalue
, WHITESPACE
);
3161 weight
= rvalue
+ n
;
3162 weight
+= strspn(weight
, WHITESPACE
);
3164 if (isempty(weight
)) {
3165 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3169 path
= strndup(rvalue
, n
);
3173 if (!path_startswith(path
, "/dev")) {
3174 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3178 r
= cg_blkio_weight_parse(weight
, &u
);
3180 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3184 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3186 w
= new0(CGroupBlockIODeviceWeight
, 1);
3195 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3199 int config_parse_blockio_bandwidth(
3201 const char *filename
,
3203 const char *section
,
3204 unsigned section_line
,
3211 _cleanup_free_
char *path
= NULL
;
3212 CGroupBlockIODeviceBandwidth
*b
;
3213 CGroupContext
*c
= data
;
3214 const char *bandwidth
;
3224 read
= streq("BlockIOReadBandwidth", lvalue
);
3226 if (isempty(rvalue
)) {
3227 CGroupBlockIODeviceBandwidth
*next
;
3229 LIST_FOREACH_SAFE (device_bandwidths
, b
, next
, c
->blockio_device_bandwidths
)
3230 if (b
->read
== read
)
3231 cgroup_context_free_blockio_device_bandwidth(c
, b
);
3236 n
= strcspn(rvalue
, WHITESPACE
);
3237 bandwidth
= rvalue
+ n
;
3238 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3241 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3245 path
= strndup(rvalue
, n
);
3249 if (!path_startswith(path
, "/dev")) {
3250 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3254 r
= parse_size(bandwidth
, 1000, &bytes
);
3255 if (r
< 0 || bytes
<= 0) {
3256 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3260 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3266 b
->bandwidth
= bytes
;
3269 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3274 int config_parse_netclass(
3276 const char *filename
,
3278 const char *section
,
3279 unsigned section_line
,
3286 CGroupContext
*c
= data
;
3294 if (streq(rvalue
, "auto")) {
3295 c
->netclass_type
= CGROUP_NETCLASS_TYPE_AUTO
;
3299 r
= safe_atou32(rvalue
, &v
);
3301 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Netclass '%s' invalid. Ignoring.", rvalue
);
3305 if (v
> CGROUP_NETCLASS_FIXED_MAX
)
3306 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3307 "Fixed netclass %" PRIu32
" out of allowed range (0-%d). Applying anyway.", v
, (uint32_t) CGROUP_NETCLASS_FIXED_MAX
);
3310 c
->netclass_type
= CGROUP_NETCLASS_TYPE_FIXED
;
3315 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3317 int config_parse_job_mode_isolate(
3319 const char *filename
,
3321 const char *section
,
3322 unsigned section_line
,
3336 r
= parse_boolean(rvalue
);
3338 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3342 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3346 int config_parse_runtime_directory(
3348 const char *filename
,
3350 const char *section
,
3351 unsigned section_line
,
3360 const char *word
, *state
;
3369 if (isempty(rvalue
)) {
3370 /* Empty assignment resets the list */
3371 *rt
= strv_free(*rt
);
3375 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3376 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3378 t
= strndup(word
, l
);
3382 r
= unit_name_printf(u
, t
, &n
);
3384 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3388 if (!filename_is_valid(n
)) {
3389 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3393 r
= strv_push(rt
, n
);
3399 if (!isempty(state
))
3400 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3405 int config_parse_set_status(
3407 const char *filename
,
3409 const char *section
,
3410 unsigned section_line
,
3418 const char *word
, *state
;
3420 ExitStatusSet
*status_set
= data
;
3427 /* Empty assignment resets the list */
3428 if (isempty(rvalue
)) {
3429 exit_status_set_free(status_set
);
3433 FOREACH_WORD(word
, l
, rvalue
, state
) {
3434 _cleanup_free_
char *temp
;
3438 temp
= strndup(word
, l
);
3442 r
= safe_atoi(temp
, &val
);
3444 val
= signal_from_string_try_harder(temp
);
3447 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3450 set
= &status_set
->signal
;
3452 if (val
< 0 || val
> 255) {
3453 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3456 set
= &status_set
->status
;
3459 r
= set_ensure_allocated(set
, NULL
);
3463 r
= set_put(*set
, INT_TO_PTR(val
));
3465 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3469 if (!isempty(state
))
3470 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3475 int config_parse_namespace_path_strv(
3477 const char *filename
,
3479 const char *section
,
3480 unsigned section_line
,
3497 if (isempty(rvalue
)) {
3498 /* Empty assignment resets the list */
3499 *sv
= strv_free(*sv
);
3503 prev
= cur
= rvalue
;
3505 _cleanup_free_
char *word
= NULL
;
3508 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3514 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3518 if (!utf8_is_valid(word
)) {
3519 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3524 offset
= word
[0] == '-';
3525 if (!path_is_absolute(word
+ offset
)) {
3526 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3531 path_kill_slashes(word
+ offset
);
3533 r
= strv_push(sv
, word
);
3544 int config_parse_no_new_privileges(
3546 const char *filename
,
3548 const char *section
,
3549 unsigned section_line
,
3556 ExecContext
*c
= data
;
3564 k
= parse_boolean(rvalue
);
3566 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3570 c
->no_new_privileges
= !!k
;
3571 c
->no_new_privileges_set
= true;
3576 int config_parse_protect_home(
3578 const char *filename
,
3580 const char *section
,
3581 unsigned section_line
,
3588 ExecContext
*c
= data
;
3596 /* Our enum shall be a superset of booleans, hence first try
3597 * to parse as as boolean, and then as enum */
3599 k
= parse_boolean(rvalue
);
3601 c
->protect_home
= PROTECT_HOME_YES
;
3603 c
->protect_home
= PROTECT_HOME_NO
;
3607 h
= protect_home_from_string(rvalue
);
3609 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3613 c
->protect_home
= h
;
3619 int config_parse_protect_system(
3621 const char *filename
,
3623 const char *section
,
3624 unsigned section_line
,
3631 ExecContext
*c
= data
;
3639 /* Our enum shall be a superset of booleans, hence first try
3640 * to parse as as boolean, and then as enum */
3642 k
= parse_boolean(rvalue
);
3644 c
->protect_system
= PROTECT_SYSTEM_YES
;
3646 c
->protect_system
= PROTECT_SYSTEM_NO
;
3650 s
= protect_system_from_string(rvalue
);
3652 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3656 c
->protect_system
= s
;
3662 #define FOLLOW_MAX 8
3664 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3675 /* This will update the filename pointer if the loaded file is
3676 * reached by a symlink. The old string will be freed. */
3679 char *target
, *name
;
3681 if (c
++ >= FOLLOW_MAX
)
3684 path_kill_slashes(*filename
);
3686 /* Add the file name we are currently looking at to
3687 * the names of this unit, but only if it is a valid
3689 name
= basename(*filename
);
3691 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3693 id
= set_get(names
, name
);
3699 r
= set_consume(names
, id
);
3705 /* Try to open the file name, but don't if its a symlink */
3706 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3713 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3714 r
= readlink_and_make_absolute(*filename
, &target
);
3722 f
= fdopen(fd
, "re");
3733 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
3741 /* Let's try to add in all symlink names we found */
3742 while ((k
= set_steal_first(names
))) {
3744 /* First try to merge in the other name into our
3746 r
= unit_merge_by_name(*u
, k
);
3750 /* Hmm, we couldn't merge the other unit into
3751 * ours? Then let's try it the other way
3754 other
= manager_get_unit((*u
)->manager
, k
);
3758 r
= unit_merge(other
, *u
);
3761 return merge_by_names(u
, names
, NULL
);
3769 unit_choose_id(*u
, id
);
3777 static int load_from_path(Unit
*u
, const char *path
) {
3779 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
3780 _cleanup_fclose_
FILE *f
= NULL
;
3781 _cleanup_free_
char *filename
= NULL
;
3789 symlink_names
= set_new(&string_hash_ops
);
3793 if (path_is_absolute(path
)) {
3795 filename
= strdup(path
);
3799 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3801 filename
= mfree(filename
);
3809 STRV_FOREACH(p
, u
->manager
->lookup_paths
.unit_path
) {
3811 /* Instead of opening the path right away, we manually
3812 * follow all symlinks and add their name to our unit
3813 * name set while doing so */
3814 filename
= path_make_absolute(path
, *p
);
3818 if (u
->manager
->unit_path_cache
&&
3819 !set_get(u
->manager
->unit_path_cache
, filename
))
3822 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3825 filename
= mfree(filename
);
3829 /* Empty the symlink names for the next run */
3830 set_clear_free(symlink_names
);
3839 /* Hmm, no suitable file found? */
3843 r
= merge_by_names(&merged
, symlink_names
, id
);
3848 u
->load_state
= UNIT_MERGED
;
3852 if (fstat(fileno(f
), &st
) < 0)
3855 if (null_or_empty(&st
))
3856 u
->load_state
= UNIT_MASKED
;
3858 u
->load_state
= UNIT_LOADED
;
3860 /* Now, parse the file contents */
3861 r
= config_parse(u
->id
, filename
, f
,
3862 UNIT_VTABLE(u
)->sections
,
3863 config_item_perf_lookup
, load_fragment_gperf_lookup
,
3864 false, true, false, u
);
3869 free(u
->fragment_path
);
3870 u
->fragment_path
= filename
;
3873 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
3875 if (u
->source_path
) {
3876 if (stat(u
->source_path
, &st
) >= 0)
3877 u
->source_mtime
= timespec_load(&st
.st_mtim
);
3879 u
->source_mtime
= 0;
3885 int unit_load_fragment(Unit
*u
) {
3891 assert(u
->load_state
== UNIT_STUB
);
3895 u
->load_state
= UNIT_LOADED
;
3899 /* First, try to find the unit under its id. We always look
3900 * for unit files in the default directories, to make it easy
3901 * to override things by placing things in /etc/systemd/system */
3902 r
= load_from_path(u
, u
->id
);
3906 /* Try to find an alias we can load this with */
3907 if (u
->load_state
== UNIT_STUB
) {
3908 SET_FOREACH(t
, u
->names
, i
) {
3913 r
= load_from_path(u
, t
);
3917 if (u
->load_state
!= UNIT_STUB
)
3922 /* And now, try looking for it under the suggested (originally linked) path */
3923 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
3925 r
= load_from_path(u
, u
->fragment_path
);
3929 if (u
->load_state
== UNIT_STUB
)
3930 /* Hmm, this didn't work? Then let's get rid
3931 * of the fragment path stored for us, so that
3932 * we don't point to an invalid location. */
3933 u
->fragment_path
= mfree(u
->fragment_path
);
3936 /* Look for a template */
3937 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
3938 _cleanup_free_
char *k
= NULL
;
3940 r
= unit_name_template(u
->id
, &k
);
3944 r
= load_from_path(u
, k
);
3948 if (u
->load_state
== UNIT_STUB
) {
3949 SET_FOREACH(t
, u
->names
, i
) {
3950 _cleanup_free_
char *z
= NULL
;
3955 r
= unit_name_template(t
, &z
);
3959 r
= load_from_path(u
, z
);
3963 if (u
->load_state
!= UNIT_STUB
)
3972 void unit_dump_config_items(FILE *f
) {
3973 static const struct {
3974 const ConfigParserCallback callback
;
3977 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3978 { config_parse_warn_compat
, "NOTSUPPORTED" },
3980 { config_parse_int
, "INTEGER" },
3981 { config_parse_unsigned
, "UNSIGNED" },
3982 { config_parse_iec_size
, "SIZE" },
3983 { config_parse_iec_uint64
, "SIZE" },
3984 { config_parse_si_size
, "SIZE" },
3985 { config_parse_bool
, "BOOLEAN" },
3986 { config_parse_string
, "STRING" },
3987 { config_parse_path
, "PATH" },
3988 { config_parse_unit_path_printf
, "PATH" },
3989 { config_parse_strv
, "STRING [...]" },
3990 { config_parse_exec_nice
, "NICE" },
3991 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
3992 { config_parse_exec_io_class
, "IOCLASS" },
3993 { config_parse_exec_io_priority
, "IOPRIORITY" },
3994 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
3995 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
3996 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
3997 { config_parse_mode
, "MODE" },
3998 { config_parse_unit_env_file
, "FILE" },
3999 { config_parse_output
, "OUTPUT" },
4000 { config_parse_input
, "INPUT" },
4001 { config_parse_log_facility
, "FACILITY" },
4002 { config_parse_log_level
, "LEVEL" },
4003 { config_parse_exec_capabilities
, "CAPABILITIES" },
4004 { config_parse_exec_secure_bits
, "SECUREBITS" },
4005 { config_parse_bounding_set
, "BOUNDINGSET" },
4006 { config_parse_limit
, "LIMIT" },
4007 { config_parse_unit_deps
, "UNIT [...]" },
4008 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4009 { config_parse_service_type
, "SERVICETYPE" },
4010 { config_parse_service_restart
, "SERVICERESTART" },
4011 #ifdef HAVE_SYSV_COMPAT
4012 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4014 { config_parse_kill_mode
, "KILLMODE" },
4015 { config_parse_signal
, "SIGNAL" },
4016 { config_parse_socket_listen
, "SOCKET [...]" },
4017 { config_parse_socket_bind
, "SOCKETBIND" },
4018 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4019 { config_parse_sec
, "SECONDS" },
4020 { config_parse_nsec
, "NANOSECONDS" },
4021 { config_parse_namespace_path_strv
, "PATH [...]" },
4022 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4023 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4024 { config_parse_unit_string_printf
, "STRING" },
4025 { config_parse_trigger_unit
, "UNIT" },
4026 { config_parse_timer
, "TIMER" },
4027 { config_parse_path_spec
, "PATH" },
4028 { config_parse_notify_access
, "ACCESS" },
4029 { config_parse_ip_tos
, "TOS" },
4030 { config_parse_unit_condition_path
, "CONDITION" },
4031 { config_parse_unit_condition_string
, "CONDITION" },
4032 { config_parse_unit_condition_null
, "CONDITION" },
4033 { config_parse_unit_slice
, "SLICE" },
4034 { config_parse_documentation
, "URL" },
4035 { config_parse_service_timeout
, "SECONDS" },
4036 { config_parse_failure_action
, "ACTION" },
4037 { config_parse_set_status
, "STATUS" },
4038 { config_parse_service_sockets
, "SOCKETS" },
4039 { config_parse_environ
, "ENVIRON" },
4041 { config_parse_syscall_filter
, "SYSCALLS" },
4042 { config_parse_syscall_archs
, "ARCHS" },
4043 { config_parse_syscall_errno
, "ERRNO" },
4044 { config_parse_address_families
, "FAMILIES" },
4046 { config_parse_cpu_shares
, "SHARES" },
4047 { config_parse_memory_limit
, "LIMIT" },
4048 { config_parse_device_allow
, "DEVICE" },
4049 { config_parse_device_policy
, "POLICY" },
4050 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4051 { config_parse_blockio_weight
, "WEIGHT" },
4052 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4053 { config_parse_long
, "LONG" },
4054 { config_parse_socket_service
, "SERVICE" },
4056 { config_parse_exec_selinux_context
, "LABEL" },
4058 { config_parse_job_mode
, "MODE" },
4059 { config_parse_job_mode_isolate
, "BOOLEAN" },
4060 { config_parse_personality
, "PERSONALITY" },
4063 const char *prev
= NULL
;
4068 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4069 const char *rvalue
= "OTHER", *lvalue
;
4073 const ConfigPerfItem
*p
;
4075 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4077 dot
= strchr(i
, '.');
4078 lvalue
= dot
? dot
+ 1 : i
;
4082 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4086 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4089 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4090 if (p
->parse
== table
[j
].callback
) {
4091 rvalue
= table
[j
].rvalue
;
4095 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);