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>
35 #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_bind(const char *unit
,
425 const char *filename
,
428 unsigned section_line
,
436 SocketAddressBindIPv6Only b
;
445 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
449 r
= parse_boolean(rvalue
);
451 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
455 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
457 s
->bind_ipv6_only
= b
;
462 int config_parse_exec_nice(const char *unit
,
463 const char *filename
,
466 unsigned section_line
,
473 ExecContext
*c
= data
;
481 r
= safe_atoi(rvalue
, &priority
);
483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
487 if (priority
< PRIO_MIN
|| priority
>= PRIO_MAX
) {
488 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Nice priority out of range, ignoring: %s", rvalue
);
498 int config_parse_exec_oom_score_adjust(const char* unit
,
499 const char *filename
,
502 unsigned section_line
,
509 ExecContext
*c
= data
;
517 r
= safe_atoi(rvalue
, &oa
);
519 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
523 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
524 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
528 c
->oom_score_adjust
= oa
;
529 c
->oom_score_adjust_set
= true;
534 int config_parse_exec(
536 const char *filename
,
539 unsigned section_line
,
546 ExecCommand
**e
= data
;
557 rvalue
+= strspn(rvalue
, WHITESPACE
);
559 if (isempty(rvalue
)) {
560 /* An empty assignment resets the list */
561 *e
= exec_command_free_list(*e
);
567 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
568 bool separate_argv0
= false, ignore
= false;
569 _cleanup_free_ ExecCommand
*nce
= NULL
;
570 _cleanup_strv_free_
char **n
= NULL
;
571 size_t nlen
= 0, nbufsize
= 0;
577 r
= extract_first_word_and_warn(&p
, &firstword
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
582 for (i
= 0; i
< 2; i
++) {
583 /* We accept an absolute path as first argument, or
584 * alternatively an absolute prefixed with @ to allow
585 * overriding of argv[0]. */
586 if (*f
== '-' && !ignore
)
588 else if (*f
== '@' && !separate_argv0
)
589 separate_argv0
= true;
596 /* First word is either "-" or "@" with no command. */
597 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty path in command line, ignoring: \"%s\"", rvalue
);
600 if (!string_is_safe(f
)) {
601 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path contains special characters, ignoring: %s", rvalue
);
604 if (!path_is_absolute(f
)) {
605 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path is not absolute, ignoring: %s", rvalue
);
608 if (endswith(f
, "/")) {
609 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Executable path specifies a directory, ignoring: %s", rvalue
);
613 if (f
== firstword
) {
622 if (!separate_argv0
) {
623 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
632 path_kill_slashes(path
);
634 while (!isempty(p
)) {
635 _cleanup_free_
char *word
= NULL
;
637 /* Check explicitly for an unquoted semicolon as
638 * command separator token. */
639 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
641 p
+= strspn(p
, WHITESPACE
);
646 /* Check for \; explicitly, to not confuse it with \\;
647 * or "\;" or "\\;" etc. extract_first_word would
648 * return the same for all of those. */
649 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
651 p
+= strspn(p
, WHITESPACE
);
652 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
662 r
= extract_first_word_and_warn(&p
, &word
, WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
668 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
676 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue
);
680 nce
= new0(ExecCommand
, 1);
686 nce
->ignore
= ignore
;
688 exec_command_append_list(e
, nce
);
690 /* Do not _cleanup_free_ these. */
701 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
702 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
704 int config_parse_socket_bindtodevice(const char* unit
,
705 const char *filename
,
708 unsigned section_line
,
723 if (rvalue
[0] && !streq(rvalue
, "*")) {
730 free(s
->bind_to_device
);
731 s
->bind_to_device
= n
;
736 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
737 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
739 int config_parse_exec_io_class(const char *unit
,
740 const char *filename
,
743 unsigned section_line
,
750 ExecContext
*c
= data
;
758 x
= ioprio_class_from_string(rvalue
);
760 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
764 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
765 c
->ioprio_set
= true;
770 int config_parse_exec_io_priority(const char *unit
,
771 const char *filename
,
774 unsigned section_line
,
781 ExecContext
*c
= data
;
789 r
= safe_atoi(rvalue
, &i
);
790 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
791 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
795 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
796 c
->ioprio_set
= true;
801 int config_parse_exec_cpu_sched_policy(const char *unit
,
802 const char *filename
,
805 unsigned section_line
,
813 ExecContext
*c
= data
;
821 x
= sched_policy_from_string(rvalue
);
823 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
827 c
->cpu_sched_policy
= x
;
828 /* Moving to or from real-time policy? We need to adjust the priority */
829 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
830 c
->cpu_sched_set
= true;
835 int config_parse_exec_cpu_sched_prio(const char *unit
,
836 const char *filename
,
839 unsigned section_line
,
846 ExecContext
*c
= data
;
854 r
= safe_atoi(rvalue
, &i
);
856 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
860 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
861 min
= sched_get_priority_min(c
->cpu_sched_policy
);
862 max
= sched_get_priority_max(c
->cpu_sched_policy
);
864 if (i
< min
|| i
> max
) {
865 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
869 c
->cpu_sched_priority
= i
;
870 c
->cpu_sched_set
= true;
875 int config_parse_exec_cpu_affinity(const char *unit
,
876 const char *filename
,
879 unsigned section_line
,
886 ExecContext
*c
= data
;
887 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
895 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
903 /* An empty assignment resets the CPU list */
909 c
->cpuset_ncpus
= ncpus
;
914 int config_parse_exec_capabilities(const char *unit
,
915 const char *filename
,
918 unsigned section_line
,
925 ExecContext
*c
= data
;
933 cap
= cap_from_text(rvalue
);
935 log_syntax(unit
, LOG_ERR
, filename
, line
, errno
, "Failed to parse capabilities, ignoring: %s", rvalue
);
940 cap_free(c
->capabilities
);
941 c
->capabilities
= cap
;
946 int config_parse_exec_secure_bits(const char *unit
,
947 const char *filename
,
950 unsigned section_line
,
957 ExecContext
*c
= data
;
959 const char *word
, *state
;
966 if (isempty(rvalue
)) {
967 /* An empty assignment resets the field */
972 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
973 if (first_word(word
, "keep-caps"))
974 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
975 else if (first_word(word
, "keep-caps-locked"))
976 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
977 else if (first_word(word
, "no-setuid-fixup"))
978 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
979 else if (first_word(word
, "no-setuid-fixup-locked"))
980 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
981 else if (first_word(word
, "noroot"))
982 c
->secure_bits
|= 1<<SECURE_NOROOT
;
983 else if (first_word(word
, "noroot-locked"))
984 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
986 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse secure bits, ignoring: %s", rvalue
);
991 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, garbage at the end, ignoring.");
996 int config_parse_bounding_set(
998 const char *filename
,
1000 const char *section
,
1001 unsigned section_line
,
1008 uint64_t *capability_bounding_set_drop
= data
;
1009 uint64_t capability_bounding_set
, sum
= 0;
1010 bool invert
= false;
1018 if (rvalue
[0] == '~') {
1023 /* Note that we store this inverted internally, since the
1024 * kernel wants it like this. But we actually expose it
1025 * non-inverted everywhere to have a fully normalized
1030 _cleanup_free_
char *word
= NULL
;
1033 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1039 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1043 cap
= capability_from_name(word
);
1045 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding set, ignoring: %s", word
);
1049 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1052 capability_bounding_set
= invert
? ~sum
: sum
;
1053 if (*capability_bounding_set_drop
!= 0 && capability_bounding_set
!= 0)
1054 *capability_bounding_set_drop
= ~(~*capability_bounding_set_drop
| capability_bounding_set
);
1056 *capability_bounding_set_drop
= ~capability_bounding_set
;
1061 int config_parse_limit(
1063 const char *filename
,
1065 const char *section
,
1066 unsigned section_line
,
1073 struct rlimit
**rl
= data
;
1084 if (streq(rvalue
, "infinity"))
1089 /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
1090 assert_cc(sizeof(rlim_t
) == sizeof(uint64_t));
1092 r
= safe_atou64(rvalue
, &u
);
1093 if (r
>= 0 && u
>= (uint64_t) RLIM_INFINITY
)
1096 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1104 *rl
= new(struct rlimit
, 1);
1109 (*rl
)->rlim_cur
= (*rl
)->rlim_max
= v
;
1113 int config_parse_bytes_limit(
1115 const char *filename
,
1117 const char *section
,
1118 unsigned section_line
,
1125 struct rlimit
**rl
= data
;
1136 if (streq(rvalue
, "infinity"))
1137 bytes
= RLIM_INFINITY
;
1141 r
= parse_size(rvalue
, 1024, &u
);
1142 if (r
>= 0 && u
>= (uint64_t) RLIM_INFINITY
)
1145 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1153 *rl
= new(struct rlimit
, 1);
1158 (*rl
)->rlim_cur
= (*rl
)->rlim_max
= bytes
;
1162 int config_parse_sec_limit(
1164 const char *filename
,
1166 const char *section
,
1167 unsigned section_line
,
1174 struct rlimit
**rl
= data
;
1185 if (streq(rvalue
, "infinity"))
1186 seconds
= RLIM_INFINITY
;
1190 r
= parse_sec(rvalue
, &t
);
1192 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1196 if (t
== USEC_INFINITY
)
1197 seconds
= RLIM_INFINITY
;
1199 seconds
= (rlim_t
) (DIV_ROUND_UP(t
, USEC_PER_SEC
));
1203 *rl
= new(struct rlimit
, 1);
1208 (*rl
)->rlim_cur
= (*rl
)->rlim_max
= seconds
;
1213 int config_parse_usec_limit(
1215 const char *filename
,
1217 const char *section
,
1218 unsigned section_line
,
1225 struct rlimit
**rl
= data
;
1236 if (streq(rvalue
, "infinity"))
1237 useconds
= RLIM_INFINITY
;
1241 r
= parse_time(rvalue
, &t
, 1);
1243 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1247 if (t
== USEC_INFINITY
)
1248 useconds
= RLIM_INFINITY
;
1250 useconds
= (rlim_t
) t
;
1254 *rl
= new(struct rlimit
, 1);
1259 (*rl
)->rlim_cur
= (*rl
)->rlim_max
= useconds
;
1263 #ifdef HAVE_SYSV_COMPAT
1264 int config_parse_sysv_priority(const char *unit
,
1265 const char *filename
,
1267 const char *section
,
1268 unsigned section_line
,
1275 int *priority
= data
;
1283 r
= safe_atoi(rvalue
, &i
);
1284 if (r
< 0 || i
< 0) {
1285 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1289 *priority
= (int) i
;
1294 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1295 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1297 int config_parse_exec_mount_flags(const char *unit
,
1298 const char *filename
,
1300 const char *section
,
1301 unsigned section_line
,
1308 ExecContext
*c
= data
;
1309 const char *word
, *state
;
1311 unsigned long flags
= 0;
1318 FOREACH_WORD_SEPARATOR(word
, l
, rvalue
, ", ", state
) {
1319 _cleanup_free_
char *t
;
1321 t
= strndup(word
, l
);
1325 if (streq(t
, "shared"))
1327 else if (streq(t
, "slave"))
1329 else if (streq(t
, "private"))
1332 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring: %s", t
, rvalue
);
1336 if (!isempty(state
))
1337 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
1339 c
->mount_flags
= flags
;
1343 int config_parse_exec_selinux_context(
1345 const char *filename
,
1347 const char *section
,
1348 unsigned section_line
,
1355 ExecContext
*c
= data
;
1366 if (isempty(rvalue
)) {
1367 c
->selinux_context
= mfree(c
->selinux_context
);
1368 c
->selinux_context_ignore
= false;
1372 if (rvalue
[0] == '-') {
1378 r
= unit_name_printf(u
, rvalue
, &k
);
1380 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1384 free(c
->selinux_context
);
1385 c
->selinux_context
= k
;
1386 c
->selinux_context_ignore
= ignore
;
1391 int config_parse_exec_apparmor_profile(
1393 const char *filename
,
1395 const char *section
,
1396 unsigned section_line
,
1403 ExecContext
*c
= data
;
1414 if (isempty(rvalue
)) {
1415 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1416 c
->apparmor_profile_ignore
= false;
1420 if (rvalue
[0] == '-') {
1426 r
= unit_name_printf(u
, rvalue
, &k
);
1428 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1432 free(c
->apparmor_profile
);
1433 c
->apparmor_profile
= k
;
1434 c
->apparmor_profile_ignore
= ignore
;
1439 int config_parse_exec_smack_process_label(
1441 const char *filename
,
1443 const char *section
,
1444 unsigned section_line
,
1451 ExecContext
*c
= data
;
1462 if (isempty(rvalue
)) {
1463 c
->smack_process_label
= mfree(c
->smack_process_label
);
1464 c
->smack_process_label_ignore
= false;
1468 if (rvalue
[0] == '-') {
1474 r
= unit_name_printf(u
, rvalue
, &k
);
1476 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1480 free(c
->smack_process_label
);
1481 c
->smack_process_label
= k
;
1482 c
->smack_process_label_ignore
= ignore
;
1487 int config_parse_timer(const char *unit
,
1488 const char *filename
,
1490 const char *section
,
1491 unsigned section_line
,
1502 CalendarSpec
*c
= NULL
;
1509 if (isempty(rvalue
)) {
1510 /* Empty assignment resets list */
1511 timer_free_values(t
);
1515 b
= timer_base_from_string(lvalue
);
1517 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1521 if (b
== TIMER_CALENDAR
) {
1522 if (calendar_spec_from_string(rvalue
, &c
) < 0) {
1523 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", rvalue
);
1527 if (parse_sec(rvalue
, &u
) < 0) {
1528 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", rvalue
);
1533 v
= new0(TimerValue
, 1);
1535 calendar_spec_free(c
);
1541 v
->calendar_spec
= c
;
1543 LIST_PREPEND(value
, t
->values
, v
);
1548 int config_parse_trigger_unit(
1550 const char *filename
,
1552 const char *section
,
1553 unsigned section_line
,
1560 _cleanup_free_
char *p
= NULL
;
1570 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1571 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1575 r
= unit_name_printf(u
, rvalue
, &p
);
1577 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1581 type
= unit_name_to_type(p
);
1583 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1587 if (type
== u
->type
) {
1588 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1592 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1594 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1601 int config_parse_path_spec(const char *unit
,
1602 const char *filename
,
1604 const char *section
,
1605 unsigned section_line
,
1615 _cleanup_free_
char *k
= NULL
;
1623 if (isempty(rvalue
)) {
1624 /* Empty assignment clears list */
1629 b
= path_type_from_string(lvalue
);
1631 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1635 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1637 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1641 if (!path_is_absolute(k
)) {
1642 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1646 s
= new0(PathSpec
, 1);
1651 s
->path
= path_kill_slashes(k
);
1656 LIST_PREPEND(spec
, p
->specs
, s
);
1661 int config_parse_socket_service(
1663 const char *filename
,
1665 const char *section
,
1666 unsigned section_line
,
1673 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1674 _cleanup_free_
char *p
= NULL
;
1684 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1686 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1690 if (!endswith(p
, ".service")) {
1691 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1695 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1697 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1701 unit_ref_set(&s
->service
, x
);
1706 int config_parse_fdname(
1708 const char *filename
,
1710 const char *section
,
1711 unsigned section_line
,
1718 _cleanup_free_
char *p
= NULL
;
1727 if (isempty(rvalue
)) {
1728 s
->fdname
= mfree(s
->fdname
);
1732 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1734 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1738 if (!fdname_is_valid(p
)) {
1739 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1750 int config_parse_service_sockets(
1752 const char *filename
,
1754 const char *section
,
1755 unsigned section_line
,
1773 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1775 r
= extract_first_word(&p
, &word
, NULL
, 0);
1781 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1785 r
= unit_name_printf(UNIT(s
), word
, &k
);
1787 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1791 if (!endswith(k
, ".socket")) {
1792 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1796 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1798 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1800 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1802 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1808 int config_parse_bus_name(
1810 const char *filename
,
1812 const char *section
,
1813 unsigned section_line
,
1820 _cleanup_free_
char *k
= NULL
;
1829 r
= unit_full_printf(u
, rvalue
, &k
);
1831 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1835 if (!service_name_is_valid(k
)) {
1836 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1840 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1843 int config_parse_service_timeout(const char *unit
,
1844 const char *filename
,
1846 const char *section
,
1847 unsigned section_line
,
1854 Service
*s
= userdata
;
1862 r
= config_parse_sec(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
1863 rvalue
, data
, userdata
);
1867 if (streq(lvalue
, "TimeoutSec")) {
1868 s
->start_timeout_defined
= true;
1869 s
->timeout_stop_usec
= s
->timeout_start_usec
;
1870 } else if (streq(lvalue
, "TimeoutStartSec"))
1871 s
->start_timeout_defined
= true;
1876 int config_parse_busname_service(
1878 const char *filename
,
1880 const char *section
,
1881 unsigned section_line
,
1888 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1892 _cleanup_free_
char *p
= NULL
;
1899 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
1901 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1905 if (!endswith(p
, ".service")) {
1906 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1910 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
1912 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1916 unit_ref_set(&n
->service
, x
);
1921 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
1923 int config_parse_bus_policy(
1925 const char *filename
,
1927 const char *section
,
1928 unsigned section_line
,
1935 _cleanup_free_ BusNamePolicy
*p
= NULL
;
1936 _cleanup_free_
char *id_str
= NULL
;
1937 BusName
*busname
= data
;
1945 p
= new0(BusNamePolicy
, 1);
1949 if (streq(lvalue
, "AllowUser"))
1950 p
->type
= BUSNAME_POLICY_TYPE_USER
;
1951 else if (streq(lvalue
, "AllowGroup"))
1952 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
1954 assert_not_reached("Unknown lvalue");
1956 id_str
= strdup(rvalue
);
1960 access_str
= strpbrk(id_str
, WHITESPACE
);
1962 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
1968 access_str
+= strspn(access_str
, WHITESPACE
);
1970 p
->access
= bus_policy_access_from_string(access_str
);
1971 if (p
->access
< 0) {
1972 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
1979 LIST_PREPEND(policy
, busname
->policy
, p
);
1985 int config_parse_bus_endpoint_policy(
1987 const char *filename
,
1989 const char *section
,
1990 unsigned section_line
,
1997 _cleanup_free_
char *name
= NULL
;
1998 BusPolicyAccess access
;
1999 ExecContext
*c
= data
;
2008 name
= strdup(rvalue
);
2012 access_str
= strpbrk(name
, WHITESPACE
);
2014 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid endpoint policy value '%s'", rvalue
);
2020 access_str
+= strspn(access_str
, WHITESPACE
);
2022 access
= bus_policy_access_from_string(access_str
);
2023 if (access
<= _BUS_POLICY_ACCESS_INVALID
||
2024 access
>= _BUS_POLICY_ACCESS_MAX
) {
2025 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid endpoint policy access type '%s'", access_str
);
2029 if (!c
->bus_endpoint
) {
2030 r
= bus_endpoint_new(&c
->bus_endpoint
);
2032 return log_error_errno(r
, "Failed to create bus endpoint object: %m");
2035 return bus_endpoint_add_policy(c
->bus_endpoint
, name
, access
);
2038 int config_parse_working_directory(
2040 const char *filename
,
2042 const char *section
,
2043 unsigned section_line
,
2050 ExecContext
*c
= data
;
2061 if (rvalue
[0] == '-') {
2067 if (streq(rvalue
, "~")) {
2068 c
->working_directory_home
= true;
2069 c
->working_directory
= mfree(c
->working_directory
);
2071 _cleanup_free_
char *k
= NULL
;
2073 r
= unit_full_printf(u
, rvalue
, &k
);
2075 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
2079 path_kill_slashes(k
);
2081 if (!utf8_is_valid(k
)) {
2082 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2086 if (!path_is_absolute(k
)) {
2087 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
2091 free(c
->working_directory
);
2092 c
->working_directory
= k
;
2095 c
->working_directory_home
= false;
2098 c
->working_directory_missing_ok
= missing_ok
;
2102 int config_parse_unit_env_file(const char *unit
,
2103 const char *filename
,
2105 const char *section
,
2106 unsigned section_line
,
2115 _cleanup_free_
char *n
= NULL
;
2123 if (isempty(rvalue
)) {
2124 /* Empty assignment frees the list */
2125 *env
= strv_free(*env
);
2129 r
= unit_full_printf(u
, rvalue
, &n
);
2131 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2135 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2136 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2140 r
= strv_extend(env
, n
);
2147 int config_parse_environ(const char *unit
,
2148 const char *filename
,
2150 const char *section
,
2151 unsigned section_line
,
2160 const char *word
, *state
;
2162 _cleanup_free_
char *k
= NULL
;
2170 if (isempty(rvalue
)) {
2171 /* Empty assignment resets the list */
2172 *env
= strv_free(*env
);
2177 r
= unit_full_printf(u
, rvalue
, &k
);
2179 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2190 FOREACH_WORD_QUOTED(word
, l
, k
, state
) {
2191 _cleanup_free_
char *n
= NULL
;
2194 r
= cunescape_length(word
, l
, 0, &n
);
2196 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Couldn't unescape assignment, ignoring: %s", rvalue
);
2200 if (!env_assignment_is_valid(n
)) {
2201 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid environment assignment, ignoring: %s", rvalue
);
2205 x
= strv_env_set(*env
, n
);
2212 if (!isempty(state
))
2213 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2218 int config_parse_pass_environ(const char *unit
,
2219 const char *filename
,
2221 const char *section
,
2222 unsigned section_line
,
2229 const char *whole_rvalue
= rvalue
;
2230 char*** passenv
= data
;
2231 _cleanup_strv_free_
char **n
= NULL
;
2232 size_t nlen
= 0, nbufsize
= 0;
2240 if (isempty(rvalue
)) {
2241 /* Empty assignment resets the list */
2242 *passenv
= strv_free(*passenv
);
2247 _cleanup_free_
char *word
= NULL
;
2249 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
);
2255 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2256 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2260 if (!env_name_is_valid(word
)) {
2261 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2262 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2266 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2274 r
= strv_extend_strv(passenv
, n
, true);
2282 int config_parse_ip_tos(const char *unit
,
2283 const char *filename
,
2285 const char *section
,
2286 unsigned section_line
,
2293 int *ip_tos
= data
, x
;
2300 x
= ip_tos_from_string(rvalue
);
2302 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2310 int config_parse_unit_condition_path(
2312 const char *filename
,
2314 const char *section
,
2315 unsigned section_line
,
2322 _cleanup_free_
char *p
= NULL
;
2323 Condition
**list
= data
, *c
;
2324 ConditionType t
= ltype
;
2325 bool trigger
, negate
;
2334 if (isempty(rvalue
)) {
2335 /* Empty assignment resets the list */
2336 *list
= condition_free_list(*list
);
2340 trigger
= rvalue
[0] == '|';
2344 negate
= rvalue
[0] == '!';
2348 r
= unit_full_printf(u
, rvalue
, &p
);
2350 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2354 if (!path_is_absolute(p
)) {
2355 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2359 c
= condition_new(t
, p
, trigger
, negate
);
2363 LIST_PREPEND(conditions
, *list
, c
);
2367 int config_parse_unit_condition_string(
2369 const char *filename
,
2371 const char *section
,
2372 unsigned section_line
,
2379 _cleanup_free_
char *s
= NULL
;
2380 Condition
**list
= data
, *c
;
2381 ConditionType t
= ltype
;
2382 bool trigger
, negate
;
2391 if (isempty(rvalue
)) {
2392 /* Empty assignment resets the list */
2393 *list
= condition_free_list(*list
);
2397 trigger
= rvalue
[0] == '|';
2401 negate
= rvalue
[0] == '!';
2405 r
= unit_full_printf(u
, rvalue
, &s
);
2407 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2411 c
= condition_new(t
, s
, trigger
, negate
);
2415 LIST_PREPEND(conditions
, *list
, c
);
2419 int config_parse_unit_condition_null(
2421 const char *filename
,
2423 const char *section
,
2424 unsigned section_line
,
2431 Condition
**list
= data
, *c
;
2432 bool trigger
, negate
;
2440 if (isempty(rvalue
)) {
2441 /* Empty assignment resets the list */
2442 *list
= condition_free_list(*list
);
2446 trigger
= rvalue
[0] == '|';
2450 negate
= rvalue
[0] == '!';
2454 b
= parse_boolean(rvalue
);
2456 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2463 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2467 LIST_PREPEND(conditions
, *list
, c
);
2471 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2472 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action
, failure_action
, FailureAction
, "Failed to parse failure action specifier");
2474 int config_parse_unit_requires_mounts_for(
2476 const char *filename
,
2478 const char *section
,
2479 unsigned section_line
,
2487 const char *word
, *state
;
2495 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2497 _cleanup_free_
char *n
;
2499 n
= strndup(word
, l
);
2503 if (!utf8_is_valid(n
)) {
2504 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2508 r
= unit_require_mounts_for(u
, n
);
2510 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount for, ignoring: %s", rvalue
);
2514 if (!isempty(state
))
2515 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2520 int config_parse_documentation(const char *unit
,
2521 const char *filename
,
2523 const char *section
,
2524 unsigned section_line
,
2540 if (isempty(rvalue
)) {
2541 /* Empty assignment resets the list */
2542 u
->documentation
= strv_free(u
->documentation
);
2546 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2547 rvalue
, data
, userdata
);
2551 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2553 if (documentation_url_is_valid(*a
))
2556 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2567 int config_parse_syscall_filter(
2569 const char *filename
,
2571 const char *section
,
2572 unsigned section_line
,
2579 static const char default_syscalls
[] =
2586 ExecContext
*c
= data
;
2588 bool invert
= false;
2589 const char *word
, *state
;
2598 if (isempty(rvalue
)) {
2599 /* Empty assignment resets the list */
2600 c
->syscall_filter
= set_free(c
->syscall_filter
);
2601 c
->syscall_whitelist
= false;
2605 if (rvalue
[0] == '~') {
2610 if (!c
->syscall_filter
) {
2611 c
->syscall_filter
= set_new(NULL
);
2612 if (!c
->syscall_filter
)
2616 /* Allow everything but the ones listed */
2617 c
->syscall_whitelist
= false;
2621 /* Allow nothing but the ones listed */
2622 c
->syscall_whitelist
= true;
2624 /* Accept default syscalls if we are on a whitelist */
2625 NULSTR_FOREACH(i
, default_syscalls
) {
2628 id
= seccomp_syscall_resolve_name(i
);
2632 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2641 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2642 _cleanup_free_
char *t
= NULL
;
2645 t
= strndup(word
, l
);
2649 id
= seccomp_syscall_resolve_name(t
);
2651 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2655 /* If we previously wanted to forbid a syscall and now
2656 * we want to allow it, then remove it from the list
2658 if (!invert
== c
->syscall_whitelist
) {
2659 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2665 set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2667 if (!isempty(state
))
2668 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2670 /* Turn on NNP, but only if it wasn't configured explicitly
2671 * before, and only if we are in user mode. */
2672 if (!c
->no_new_privileges_set
&& u
->manager
->running_as
== MANAGER_USER
)
2673 c
->no_new_privileges
= true;
2678 int config_parse_syscall_archs(
2680 const char *filename
,
2682 const char *section
,
2683 unsigned section_line
,
2691 const char *word
, *state
;
2695 if (isempty(rvalue
)) {
2696 *archs
= set_free(*archs
);
2700 r
= set_ensure_allocated(archs
, NULL
);
2704 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2705 _cleanup_free_
char *t
= NULL
;
2708 t
= strndup(word
, l
);
2712 r
= seccomp_arch_from_string(t
, &a
);
2714 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call architecture, ignoring: %s", t
);
2718 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2724 if (!isempty(state
))
2725 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2730 int config_parse_syscall_errno(
2732 const char *filename
,
2734 const char *section
,
2735 unsigned section_line
,
2742 ExecContext
*c
= data
;
2749 if (isempty(rvalue
)) {
2750 /* Empty assignment resets to KILL */
2751 c
->syscall_errno
= 0;
2755 e
= errno_from_name(rvalue
);
2757 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2761 c
->syscall_errno
= e
;
2765 int config_parse_address_families(
2767 const char *filename
,
2769 const char *section
,
2770 unsigned section_line
,
2777 ExecContext
*c
= data
;
2778 bool invert
= false;
2779 const char *word
, *state
;
2787 if (isempty(rvalue
)) {
2788 /* Empty assignment resets the list */
2789 c
->address_families
= set_free(c
->address_families
);
2790 c
->address_families_whitelist
= false;
2794 if (rvalue
[0] == '~') {
2799 if (!c
->address_families
) {
2800 c
->address_families
= set_new(NULL
);
2801 if (!c
->address_families
)
2804 c
->address_families_whitelist
= !invert
;
2807 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2808 _cleanup_free_
char *t
= NULL
;
2811 t
= strndup(word
, l
);
2815 af
= af_from_name(t
);
2817 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse address family, ignoring: %s", t
);
2821 /* If we previously wanted to forbid an address family and now
2822 * we want to allow it, then remove it from the list
2824 if (!invert
== c
->address_families_whitelist
) {
2825 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2831 set_remove(c
->address_families
, INT_TO_PTR(af
));
2833 if (!isempty(state
))
2834 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2840 int config_parse_unit_slice(
2842 const char *filename
,
2844 const char *section
,
2845 unsigned section_line
,
2852 _cleanup_free_
char *k
= NULL
;
2853 Unit
*u
= userdata
, *slice
= NULL
;
2861 r
= unit_name_printf(u
, rvalue
, &k
);
2863 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2867 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2869 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2873 r
= unit_set_slice(u
, slice
);
2875 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2882 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2884 int config_parse_cpu_shares(
2886 const char *filename
,
2888 const char *section
,
2889 unsigned section_line
,
2896 uint64_t *shares
= data
;
2903 r
= cg_cpu_shares_parse(rvalue
, shares
);
2905 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2912 int config_parse_cpu_quota(
2914 const char *filename
,
2916 const char *section
,
2917 unsigned section_line
,
2924 CGroupContext
*c
= data
;
2931 if (isempty(rvalue
)) {
2932 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2936 if (!endswith(rvalue
, "%")) {
2937 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue
);
2941 if (sscanf(rvalue
, "%lf%%", &percent
) != 1 || percent
<= 0) {
2942 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' invalid. Ignoring.", rvalue
);
2946 c
->cpu_quota_per_sec_usec
= (usec_t
) (percent
* USEC_PER_SEC
/ 100);
2951 int config_parse_memory_limit(
2953 const char *filename
,
2955 const char *section
,
2956 unsigned section_line
,
2963 CGroupContext
*c
= data
;
2967 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
2968 c
->memory_limit
= (uint64_t) -1;
2972 r
= parse_size(rvalue
, 1024, &bytes
);
2973 if (r
< 0 || bytes
< 1) {
2974 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
2978 c
->memory_limit
= bytes
;
2982 int config_parse_tasks_max(
2984 const char *filename
,
2986 const char *section
,
2987 unsigned section_line
,
2994 CGroupContext
*c
= data
;
2998 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
2999 c
->tasks_max
= (uint64_t) -1;
3003 r
= safe_atou64(rvalue
, &u
);
3004 if (r
< 0 || u
< 1) {
3005 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3013 int config_parse_device_allow(
3015 const char *filename
,
3017 const char *section
,
3018 unsigned section_line
,
3025 _cleanup_free_
char *path
= NULL
;
3026 CGroupContext
*c
= data
;
3027 CGroupDeviceAllow
*a
;
3031 if (isempty(rvalue
)) {
3032 while (c
->device_allow
)
3033 cgroup_context_free_device_allow(c
, c
->device_allow
);
3038 n
= strcspn(rvalue
, WHITESPACE
);
3039 path
= strndup(rvalue
, n
);
3043 if (!startswith(path
, "/dev/") &&
3044 !startswith(path
, "block-") &&
3045 !startswith(path
, "char-")) {
3046 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3050 m
= rvalue
+ n
+ strspn(rvalue
+ n
, WHITESPACE
);
3054 if (!in_charset(m
, "rwm")) {
3055 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3059 a
= new0(CGroupDeviceAllow
, 1);
3065 a
->r
= !!strchr(m
, 'r');
3066 a
->w
= !!strchr(m
, 'w');
3067 a
->m
= !!strchr(m
, 'm');
3069 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3073 int config_parse_blockio_weight(
3075 const char *filename
,
3077 const char *section
,
3078 unsigned section_line
,
3085 uint64_t *weight
= data
;
3092 r
= cg_blkio_weight_parse(rvalue
, weight
);
3094 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3101 int config_parse_blockio_device_weight(
3103 const char *filename
,
3105 const char *section
,
3106 unsigned section_line
,
3113 _cleanup_free_
char *path
= NULL
;
3114 CGroupBlockIODeviceWeight
*w
;
3115 CGroupContext
*c
= data
;
3125 if (isempty(rvalue
)) {
3126 while (c
->blockio_device_weights
)
3127 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3132 n
= strcspn(rvalue
, WHITESPACE
);
3133 weight
= rvalue
+ n
;
3134 weight
+= strspn(weight
, WHITESPACE
);
3136 if (isempty(weight
)) {
3137 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3141 path
= strndup(rvalue
, n
);
3145 if (!path_startswith(path
, "/dev")) {
3146 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3150 r
= cg_blkio_weight_parse(weight
, &u
);
3152 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3156 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3158 w
= new0(CGroupBlockIODeviceWeight
, 1);
3167 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3171 int config_parse_blockio_bandwidth(
3173 const char *filename
,
3175 const char *section
,
3176 unsigned section_line
,
3183 _cleanup_free_
char *path
= NULL
;
3184 CGroupBlockIODeviceBandwidth
*b
;
3185 CGroupContext
*c
= data
;
3186 const char *bandwidth
;
3196 read
= streq("BlockIOReadBandwidth", lvalue
);
3198 if (isempty(rvalue
)) {
3199 CGroupBlockIODeviceBandwidth
*next
;
3201 LIST_FOREACH_SAFE (device_bandwidths
, b
, next
, c
->blockio_device_bandwidths
)
3202 if (b
->read
== read
)
3203 cgroup_context_free_blockio_device_bandwidth(c
, b
);
3208 n
= strcspn(rvalue
, WHITESPACE
);
3209 bandwidth
= rvalue
+ n
;
3210 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3213 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3217 path
= strndup(rvalue
, n
);
3221 if (!path_startswith(path
, "/dev")) {
3222 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3226 r
= parse_size(bandwidth
, 1000, &bytes
);
3227 if (r
< 0 || bytes
<= 0) {
3228 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3232 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3238 b
->bandwidth
= bytes
;
3241 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3246 int config_parse_netclass(
3248 const char *filename
,
3250 const char *section
,
3251 unsigned section_line
,
3258 CGroupContext
*c
= data
;
3266 if (streq(rvalue
, "auto")) {
3267 c
->netclass_type
= CGROUP_NETCLASS_TYPE_AUTO
;
3271 r
= safe_atou32(rvalue
, &v
);
3273 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Netclass '%s' invalid. Ignoring.", rvalue
);
3277 if (v
> CGROUP_NETCLASS_FIXED_MAX
)
3278 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3279 "Fixed netclass %" PRIu32
" out of allowed range (0-%d). Applying anyway.", v
, (uint32_t) CGROUP_NETCLASS_FIXED_MAX
);
3282 c
->netclass_type
= CGROUP_NETCLASS_TYPE_FIXED
;
3287 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3289 int config_parse_job_mode_isolate(
3291 const char *filename
,
3293 const char *section
,
3294 unsigned section_line
,
3308 r
= parse_boolean(rvalue
);
3310 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3314 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3318 int config_parse_runtime_directory(
3320 const char *filename
,
3322 const char *section
,
3323 unsigned section_line
,
3332 const char *word
, *state
;
3341 if (isempty(rvalue
)) {
3342 /* Empty assignment resets the list */
3343 *rt
= strv_free(*rt
);
3347 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3348 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3350 t
= strndup(word
, l
);
3354 r
= unit_name_printf(u
, t
, &n
);
3356 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3360 if (!filename_is_valid(n
)) {
3361 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3365 r
= strv_push(rt
, n
);
3371 if (!isempty(state
))
3372 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3377 int config_parse_set_status(
3379 const char *filename
,
3381 const char *section
,
3382 unsigned section_line
,
3390 const char *word
, *state
;
3392 ExitStatusSet
*status_set
= data
;
3399 /* Empty assignment resets the list */
3400 if (isempty(rvalue
)) {
3401 exit_status_set_free(status_set
);
3405 FOREACH_WORD(word
, l
, rvalue
, state
) {
3406 _cleanup_free_
char *temp
;
3410 temp
= strndup(word
, l
);
3414 r
= safe_atoi(temp
, &val
);
3416 val
= signal_from_string_try_harder(temp
);
3419 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3422 set
= &status_set
->signal
;
3424 if (val
< 0 || val
> 255) {
3425 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3428 set
= &status_set
->status
;
3431 r
= set_ensure_allocated(set
, NULL
);
3435 r
= set_put(*set
, INT_TO_PTR(val
));
3437 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3441 if (!isempty(state
))
3442 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3447 int config_parse_namespace_path_strv(
3449 const char *filename
,
3451 const char *section
,
3452 unsigned section_line
,
3469 if (isempty(rvalue
)) {
3470 /* Empty assignment resets the list */
3471 *sv
= strv_free(*sv
);
3475 prev
= cur
= rvalue
;
3477 _cleanup_free_
char *word
= NULL
;
3480 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3486 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3490 if (!utf8_is_valid(word
)) {
3491 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3496 offset
= word
[0] == '-';
3497 if (!path_is_absolute(word
+ offset
)) {
3498 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3503 path_kill_slashes(word
+ offset
);
3505 r
= strv_push(sv
, word
);
3516 int config_parse_no_new_privileges(
3518 const char *filename
,
3520 const char *section
,
3521 unsigned section_line
,
3528 ExecContext
*c
= data
;
3536 k
= parse_boolean(rvalue
);
3538 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3542 c
->no_new_privileges
= !!k
;
3543 c
->no_new_privileges_set
= true;
3548 int config_parse_protect_home(
3550 const char *filename
,
3552 const char *section
,
3553 unsigned section_line
,
3560 ExecContext
*c
= data
;
3568 /* Our enum shall be a superset of booleans, hence first try
3569 * to parse as as boolean, and then as enum */
3571 k
= parse_boolean(rvalue
);
3573 c
->protect_home
= PROTECT_HOME_YES
;
3575 c
->protect_home
= PROTECT_HOME_NO
;
3579 h
= protect_home_from_string(rvalue
);
3581 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3585 c
->protect_home
= h
;
3591 int config_parse_protect_system(
3593 const char *filename
,
3595 const char *section
,
3596 unsigned section_line
,
3603 ExecContext
*c
= data
;
3611 /* Our enum shall be a superset of booleans, hence first try
3612 * to parse as as boolean, and then as enum */
3614 k
= parse_boolean(rvalue
);
3616 c
->protect_system
= PROTECT_SYSTEM_YES
;
3618 c
->protect_system
= PROTECT_SYSTEM_NO
;
3622 s
= protect_system_from_string(rvalue
);
3624 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3628 c
->protect_system
= s
;
3634 #define FOLLOW_MAX 8
3636 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3647 /* This will update the filename pointer if the loaded file is
3648 * reached by a symlink. The old string will be freed. */
3651 char *target
, *name
;
3653 if (c
++ >= FOLLOW_MAX
)
3656 path_kill_slashes(*filename
);
3658 /* Add the file name we are currently looking at to
3659 * the names of this unit, but only if it is a valid
3661 name
= basename(*filename
);
3663 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3665 id
= set_get(names
, name
);
3671 r
= set_consume(names
, id
);
3677 /* Try to open the file name, but don't if its a symlink */
3678 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3685 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3686 r
= readlink_and_make_absolute(*filename
, &target
);
3694 f
= fdopen(fd
, "re");
3705 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
3713 /* Let's try to add in all symlink names we found */
3714 while ((k
= set_steal_first(names
))) {
3716 /* First try to merge in the other name into our
3718 r
= unit_merge_by_name(*u
, k
);
3722 /* Hmm, we couldn't merge the other unit into
3723 * ours? Then let's try it the other way
3726 other
= manager_get_unit((*u
)->manager
, k
);
3730 r
= unit_merge(other
, *u
);
3733 return merge_by_names(u
, names
, NULL
);
3741 unit_choose_id(*u
, id
);
3749 static int load_from_path(Unit
*u
, const char *path
) {
3751 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
3752 _cleanup_fclose_
FILE *f
= NULL
;
3753 _cleanup_free_
char *filename
= NULL
;
3761 symlink_names
= set_new(&string_hash_ops
);
3765 if (path_is_absolute(path
)) {
3767 filename
= strdup(path
);
3771 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3773 filename
= mfree(filename
);
3781 STRV_FOREACH(p
, u
->manager
->lookup_paths
.unit_path
) {
3783 /* Instead of opening the path right away, we manually
3784 * follow all symlinks and add their name to our unit
3785 * name set while doing so */
3786 filename
= path_make_absolute(path
, *p
);
3790 if (u
->manager
->unit_path_cache
&&
3791 !set_get(u
->manager
->unit_path_cache
, filename
))
3794 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3797 filename
= mfree(filename
);
3801 /* Empty the symlink names for the next run */
3802 set_clear_free(symlink_names
);
3811 /* Hmm, no suitable file found? */
3815 r
= merge_by_names(&merged
, symlink_names
, id
);
3820 u
->load_state
= UNIT_MERGED
;
3824 if (fstat(fileno(f
), &st
) < 0)
3827 if (null_or_empty(&st
))
3828 u
->load_state
= UNIT_MASKED
;
3830 u
->load_state
= UNIT_LOADED
;
3832 /* Now, parse the file contents */
3833 r
= config_parse(u
->id
, filename
, f
,
3834 UNIT_VTABLE(u
)->sections
,
3835 config_item_perf_lookup
, load_fragment_gperf_lookup
,
3836 false, true, false, u
);
3841 free(u
->fragment_path
);
3842 u
->fragment_path
= filename
;
3845 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
3847 if (u
->source_path
) {
3848 if (stat(u
->source_path
, &st
) >= 0)
3849 u
->source_mtime
= timespec_load(&st
.st_mtim
);
3851 u
->source_mtime
= 0;
3857 int unit_load_fragment(Unit
*u
) {
3863 assert(u
->load_state
== UNIT_STUB
);
3867 u
->load_state
= UNIT_LOADED
;
3871 /* First, try to find the unit under its id. We always look
3872 * for unit files in the default directories, to make it easy
3873 * to override things by placing things in /etc/systemd/system */
3874 r
= load_from_path(u
, u
->id
);
3878 /* Try to find an alias we can load this with */
3879 if (u
->load_state
== UNIT_STUB
) {
3880 SET_FOREACH(t
, u
->names
, i
) {
3885 r
= load_from_path(u
, t
);
3889 if (u
->load_state
!= UNIT_STUB
)
3894 /* And now, try looking for it under the suggested (originally linked) path */
3895 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
3897 r
= load_from_path(u
, u
->fragment_path
);
3901 if (u
->load_state
== UNIT_STUB
)
3902 /* Hmm, this didn't work? Then let's get rid
3903 * of the fragment path stored for us, so that
3904 * we don't point to an invalid location. */
3905 u
->fragment_path
= mfree(u
->fragment_path
);
3908 /* Look for a template */
3909 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
3910 _cleanup_free_
char *k
= NULL
;
3912 r
= unit_name_template(u
->id
, &k
);
3916 r
= load_from_path(u
, k
);
3920 if (u
->load_state
== UNIT_STUB
) {
3921 SET_FOREACH(t
, u
->names
, i
) {
3922 _cleanup_free_
char *z
= NULL
;
3927 r
= unit_name_template(t
, &z
);
3931 r
= load_from_path(u
, z
);
3935 if (u
->load_state
!= UNIT_STUB
)
3944 void unit_dump_config_items(FILE *f
) {
3945 static const struct {
3946 const ConfigParserCallback callback
;
3949 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3950 { config_parse_warn_compat
, "NOTSUPPORTED" },
3952 { config_parse_int
, "INTEGER" },
3953 { config_parse_unsigned
, "UNSIGNED" },
3954 { config_parse_iec_size
, "SIZE" },
3955 { config_parse_iec_uint64
, "SIZE" },
3956 { config_parse_si_size
, "SIZE" },
3957 { config_parse_bool
, "BOOLEAN" },
3958 { config_parse_string
, "STRING" },
3959 { config_parse_path
, "PATH" },
3960 { config_parse_unit_path_printf
, "PATH" },
3961 { config_parse_strv
, "STRING [...]" },
3962 { config_parse_exec_nice
, "NICE" },
3963 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
3964 { config_parse_exec_io_class
, "IOCLASS" },
3965 { config_parse_exec_io_priority
, "IOPRIORITY" },
3966 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
3967 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
3968 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
3969 { config_parse_mode
, "MODE" },
3970 { config_parse_unit_env_file
, "FILE" },
3971 { config_parse_output
, "OUTPUT" },
3972 { config_parse_input
, "INPUT" },
3973 { config_parse_log_facility
, "FACILITY" },
3974 { config_parse_log_level
, "LEVEL" },
3975 { config_parse_exec_capabilities
, "CAPABILITIES" },
3976 { config_parse_exec_secure_bits
, "SECUREBITS" },
3977 { config_parse_bounding_set
, "BOUNDINGSET" },
3978 { config_parse_limit
, "LIMIT" },
3979 { config_parse_unit_deps
, "UNIT [...]" },
3980 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
3981 { config_parse_service_type
, "SERVICETYPE" },
3982 { config_parse_service_restart
, "SERVICERESTART" },
3983 #ifdef HAVE_SYSV_COMPAT
3984 { config_parse_sysv_priority
, "SYSVPRIORITY" },
3986 { config_parse_kill_mode
, "KILLMODE" },
3987 { config_parse_signal
, "SIGNAL" },
3988 { config_parse_socket_listen
, "SOCKET [...]" },
3989 { config_parse_socket_bind
, "SOCKETBIND" },
3990 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
3991 { config_parse_sec
, "SECONDS" },
3992 { config_parse_nsec
, "NANOSECONDS" },
3993 { config_parse_namespace_path_strv
, "PATH [...]" },
3994 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
3995 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
3996 { config_parse_unit_string_printf
, "STRING" },
3997 { config_parse_trigger_unit
, "UNIT" },
3998 { config_parse_timer
, "TIMER" },
3999 { config_parse_path_spec
, "PATH" },
4000 { config_parse_notify_access
, "ACCESS" },
4001 { config_parse_ip_tos
, "TOS" },
4002 { config_parse_unit_condition_path
, "CONDITION" },
4003 { config_parse_unit_condition_string
, "CONDITION" },
4004 { config_parse_unit_condition_null
, "CONDITION" },
4005 { config_parse_unit_slice
, "SLICE" },
4006 { config_parse_documentation
, "URL" },
4007 { config_parse_service_timeout
, "SECONDS" },
4008 { config_parse_failure_action
, "ACTION" },
4009 { config_parse_set_status
, "STATUS" },
4010 { config_parse_service_sockets
, "SOCKETS" },
4011 { config_parse_environ
, "ENVIRON" },
4013 { config_parse_syscall_filter
, "SYSCALLS" },
4014 { config_parse_syscall_archs
, "ARCHS" },
4015 { config_parse_syscall_errno
, "ERRNO" },
4016 { config_parse_address_families
, "FAMILIES" },
4018 { config_parse_cpu_shares
, "SHARES" },
4019 { config_parse_memory_limit
, "LIMIT" },
4020 { config_parse_device_allow
, "DEVICE" },
4021 { config_parse_device_policy
, "POLICY" },
4022 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4023 { config_parse_blockio_weight
, "WEIGHT" },
4024 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4025 { config_parse_long
, "LONG" },
4026 { config_parse_socket_service
, "SERVICE" },
4028 { config_parse_exec_selinux_context
, "LABEL" },
4030 { config_parse_job_mode
, "MODE" },
4031 { config_parse_job_mode_isolate
, "BOOLEAN" },
4032 { config_parse_personality
, "PERSONALITY" },
4035 const char *prev
= NULL
;
4040 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4041 const char *rvalue
= "OTHER", *lvalue
;
4045 const ConfigPerfItem
*p
;
4047 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4049 dot
= strchr(i
, '.');
4050 lvalue
= dot
? dot
+ 1 : i
;
4054 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4058 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4061 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4062 if (p
->parse
== table
[j
].callback
) {
4063 rvalue
= table
[j
].rvalue
;
4067 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);