2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
5 Copyright 2012 Holger Hans Peter Freyther
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/oom.h>
30 #include <sys/resource.h>
34 #include "alloc-util.h"
35 #include "bus-error.h"
36 #include "bus-internal.h"
39 #include "capability-util.h"
41 #include "conf-parser.h"
42 #include "cpu-set-util.h"
44 #include "errno-list.h"
49 #include "load-fragment.h"
52 #include "parse-util.h"
53 #include "path-util.h"
54 #include "process-util.h"
55 #include "rlimit-util.h"
57 #include "seccomp-util.h"
59 #include "securebits.h"
60 #include "signal-util.h"
61 #include "stat-util.h"
62 #include "string-util.h"
64 #include "unit-name.h"
65 #include "unit-printf.h"
70 int config_parse_warn_compat(
75 unsigned section_line
,
81 Disabled reason
= ltype
;
84 case DISABLED_CONFIGURATION
:
85 log_syntax(unit
, LOG_DEBUG
, filename
, line
, 0,
86 "Support for option %s= has been disabled at compile time and it is ignored", lvalue
);
89 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
90 "Support for option %s= has been removed and it is ignored", lvalue
);
92 case DISABLED_EXPERIMENTAL
:
93 log_syntax(unit
, LOG_INFO
, filename
, line
, 0,
94 "Support for option %s= has not yet been enabled and it is ignored", lvalue
);
101 int config_parse_unit_deps(
103 const char *filename
,
106 unsigned section_line
,
113 UnitDependency d
= ltype
;
123 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
126 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
132 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
136 r
= unit_name_printf(u
, word
, &k
);
138 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
142 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
144 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
150 int config_parse_obsolete_unit_deps(
152 const char *filename
,
155 unsigned section_line
,
162 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
163 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
165 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
168 int config_parse_unit_string_printf(
170 const char *filename
,
173 unsigned section_line
,
180 _cleanup_free_
char *k
= NULL
;
189 r
= unit_full_printf(u
, rvalue
, &k
);
191 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
195 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
198 int config_parse_unit_strv_printf(
200 const char *filename
,
203 unsigned section_line
,
211 _cleanup_free_
char *k
= NULL
;
219 r
= unit_full_printf(u
, rvalue
, &k
);
221 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
225 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
228 int config_parse_unit_path_printf(
230 const char *filename
,
233 unsigned section_line
,
240 _cleanup_free_
char *k
= NULL
;
249 r
= unit_full_printf(u
, rvalue
, &k
);
251 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
255 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
258 int config_parse_unit_path_strv_printf(
260 const char *filename
,
263 unsigned section_line
,
271 const char *word
, *state
;
281 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
282 _cleanup_free_
char *k
= NULL
;
288 r
= unit_full_printf(u
, t
, &k
);
290 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", t
);
294 if (!utf8_is_valid(k
)) {
295 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
299 if (!path_is_absolute(k
)) {
300 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Symlink path %s is not absolute, ignoring: %m", k
);
304 path_kill_slashes(k
);
313 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, ignoring.");
318 int config_parse_socket_listen(const char *unit
,
319 const char *filename
,
322 unsigned section_line
,
329 _cleanup_free_ SocketPort
*p
= NULL
;
341 if (isempty(rvalue
)) {
342 /* An empty assignment removes all ports */
343 socket_free_ports(s
);
347 p
= new0(SocketPort
, 1);
351 if (ltype
!= SOCKET_SOCKET
) {
354 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
356 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
360 path_kill_slashes(p
->path
);
362 } else if (streq(lvalue
, "ListenNetlink")) {
363 _cleanup_free_
char *k
= NULL
;
365 p
->type
= SOCKET_SOCKET
;
366 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
368 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
372 r
= socket_address_parse_netlink(&p
->address
, k
);
374 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
379 _cleanup_free_
char *k
= NULL
;
381 p
->type
= SOCKET_SOCKET
;
382 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
384 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
388 r
= socket_address_parse_and_warn(&p
->address
, k
);
390 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
394 if (streq(lvalue
, "ListenStream"))
395 p
->address
.type
= SOCK_STREAM
;
396 else if (streq(lvalue
, "ListenDatagram"))
397 p
->address
.type
= SOCK_DGRAM
;
399 assert(streq(lvalue
, "ListenSequentialPacket"));
400 p
->address
.type
= SOCK_SEQPACKET
;
403 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
404 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
410 p
->auxiliary_fds
= NULL
;
411 p
->n_auxiliary_fds
= 0;
415 LIST_FIND_TAIL(port
, s
->ports
, tail
);
416 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
418 LIST_PREPEND(port
, s
->ports
, p
);
424 int config_parse_socket_protocol(const char *unit
,
425 const char *filename
,
428 unsigned section_line
,
443 if (streq(rvalue
, "udplite"))
444 s
->socket_protocol
= IPPROTO_UDPLITE
;
445 else if (streq(rvalue
, "sctp"))
446 s
->socket_protocol
= IPPROTO_SCTP
;
448 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
455 int config_parse_socket_bind(const char *unit
,
456 const char *filename
,
459 unsigned section_line
,
467 SocketAddressBindIPv6Only b
;
476 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
480 r
= parse_boolean(rvalue
);
482 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
486 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
488 s
->bind_ipv6_only
= b
;
493 int config_parse_exec_nice(const char *unit
,
494 const char *filename
,
497 unsigned section_line
,
504 ExecContext
*c
= data
;
512 r
= safe_atoi(rvalue
, &priority
);
514 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
518 if (priority
< PRIO_MIN
|| priority
>= PRIO_MAX
) {
519 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Nice priority out of range, ignoring: %s", rvalue
);
529 int config_parse_exec_oom_score_adjust(const char* unit
,
530 const char *filename
,
533 unsigned section_line
,
540 ExecContext
*c
= data
;
548 r
= safe_atoi(rvalue
, &oa
);
550 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
554 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
555 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
559 c
->oom_score_adjust
= oa
;
560 c
->oom_score_adjust_set
= true;
565 int config_parse_exec(
567 const char *filename
,
570 unsigned section_line
,
577 ExecCommand
**e
= data
;
588 rvalue
+= strspn(rvalue
, WHITESPACE
);
590 if (isempty(rvalue
)) {
591 /* An empty assignment resets the list */
592 *e
= exec_command_free_list(*e
);
598 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
599 bool separate_argv0
= false, ignore
= false;
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(
737 const char *filename
,
740 unsigned section_line
,
755 if (rvalue
[0] && !streq(rvalue
, "*")) {
756 if (!ifname_valid(rvalue
)) {
757 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
767 free(s
->bind_to_device
);
768 s
->bind_to_device
= n
;
773 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
774 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
776 int config_parse_exec_io_class(const char *unit
,
777 const char *filename
,
780 unsigned section_line
,
787 ExecContext
*c
= data
;
795 x
= ioprio_class_from_string(rvalue
);
797 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
801 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
802 c
->ioprio_set
= true;
807 int config_parse_exec_io_priority(const char *unit
,
808 const char *filename
,
811 unsigned section_line
,
818 ExecContext
*c
= data
;
826 r
= safe_atoi(rvalue
, &i
);
827 if (r
< 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
828 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
832 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
833 c
->ioprio_set
= true;
838 int config_parse_exec_cpu_sched_policy(const char *unit
,
839 const char *filename
,
842 unsigned section_line
,
850 ExecContext
*c
= data
;
858 x
= sched_policy_from_string(rvalue
);
860 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
864 c
->cpu_sched_policy
= x
;
865 /* Moving to or from real-time policy? We need to adjust the priority */
866 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
867 c
->cpu_sched_set
= true;
872 int config_parse_exec_cpu_sched_prio(const char *unit
,
873 const char *filename
,
876 unsigned section_line
,
883 ExecContext
*c
= data
;
891 r
= safe_atoi(rvalue
, &i
);
893 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
897 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
898 min
= sched_get_priority_min(c
->cpu_sched_policy
);
899 max
= sched_get_priority_max(c
->cpu_sched_policy
);
901 if (i
< min
|| i
> max
) {
902 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
906 c
->cpu_sched_priority
= i
;
907 c
->cpu_sched_set
= true;
912 int config_parse_exec_cpu_affinity(const char *unit
,
913 const char *filename
,
916 unsigned section_line
,
923 ExecContext
*c
= data
;
924 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
932 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
940 /* An empty assignment resets the CPU list */
946 c
->cpuset_ncpus
= ncpus
;
951 int config_parse_exec_secure_bits(const char *unit
,
952 const char *filename
,
955 unsigned section_line
,
962 ExecContext
*c
= data
;
964 const char *word
, *state
;
971 if (isempty(rvalue
)) {
972 /* An empty assignment resets the field */
977 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
978 if (first_word(word
, "keep-caps"))
979 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS
;
980 else if (first_word(word
, "keep-caps-locked"))
981 c
->secure_bits
|= 1<<SECURE_KEEP_CAPS_LOCKED
;
982 else if (first_word(word
, "no-setuid-fixup"))
983 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP
;
984 else if (first_word(word
, "no-setuid-fixup-locked"))
985 c
->secure_bits
|= 1<<SECURE_NO_SETUID_FIXUP_LOCKED
;
986 else if (first_word(word
, "noroot"))
987 c
->secure_bits
|= 1<<SECURE_NOROOT
;
988 else if (first_word(word
, "noroot-locked"))
989 c
->secure_bits
|= 1<<SECURE_NOROOT_LOCKED
;
991 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse secure bits, ignoring: %s", rvalue
);
996 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid syntax, garbage at the end, ignoring.");
1001 int config_parse_capability_set(
1003 const char *filename
,
1005 const char *section
,
1006 unsigned section_line
,
1013 uint64_t *capability_set
= data
;
1014 uint64_t sum
= 0, initial
= 0;
1015 bool invert
= false;
1023 if (rvalue
[0] == '~') {
1028 if (strcmp(lvalue
, "CapabilityBoundingSet") == 0)
1029 initial
= CAP_ALL
; /* initialized to all bits on */
1030 /* else "AmbientCapabilities" initialized to all bits off */
1034 _cleanup_free_
char *word
= NULL
;
1037 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
1043 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word, ignoring: %s", rvalue
);
1047 cap
= capability_from_name(word
);
1049 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word
);
1053 sum
|= ((uint64_t) UINT64_C(1)) << (uint64_t) cap
;
1056 sum
= invert
? ~sum
: sum
;
1058 if (sum
== 0 || *capability_set
== initial
)
1059 /* "" or uninitialized data -> replace */
1060 *capability_set
= sum
;
1062 /* previous data -> merge */
1063 *capability_set
|= sum
;
1068 int config_parse_limit(
1070 const char *filename
,
1072 const char *section
,
1073 unsigned section_line
,
1080 struct rlimit
**rl
= data
, d
= {};
1088 r
= rlimit_parse(ltype
, rvalue
, &d
);
1090 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1094 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1101 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1109 #ifdef HAVE_SYSV_COMPAT
1110 int config_parse_sysv_priority(const char *unit
,
1111 const char *filename
,
1113 const char *section
,
1114 unsigned section_line
,
1121 int *priority
= data
;
1129 r
= safe_atoi(rvalue
, &i
);
1130 if (r
< 0 || i
< 0) {
1131 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1135 *priority
= (int) i
;
1140 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1141 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1143 int config_parse_exec_mount_flags(const char *unit
,
1144 const char *filename
,
1146 const char *section
,
1147 unsigned section_line
,
1155 unsigned long flags
= 0;
1156 ExecContext
*c
= data
;
1163 if (streq(rvalue
, "shared"))
1165 else if (streq(rvalue
, "slave"))
1167 else if (streq(rvalue
, "private"))
1170 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1174 c
->mount_flags
= flags
;
1179 int config_parse_exec_selinux_context(
1181 const char *filename
,
1183 const char *section
,
1184 unsigned section_line
,
1191 ExecContext
*c
= data
;
1202 if (isempty(rvalue
)) {
1203 c
->selinux_context
= mfree(c
->selinux_context
);
1204 c
->selinux_context_ignore
= false;
1208 if (rvalue
[0] == '-') {
1214 r
= unit_name_printf(u
, rvalue
, &k
);
1216 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1220 free(c
->selinux_context
);
1221 c
->selinux_context
= k
;
1222 c
->selinux_context_ignore
= ignore
;
1227 int config_parse_exec_apparmor_profile(
1229 const char *filename
,
1231 const char *section
,
1232 unsigned section_line
,
1239 ExecContext
*c
= data
;
1250 if (isempty(rvalue
)) {
1251 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1252 c
->apparmor_profile_ignore
= false;
1256 if (rvalue
[0] == '-') {
1262 r
= unit_name_printf(u
, rvalue
, &k
);
1264 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1268 free(c
->apparmor_profile
);
1269 c
->apparmor_profile
= k
;
1270 c
->apparmor_profile_ignore
= ignore
;
1275 int config_parse_exec_smack_process_label(
1277 const char *filename
,
1279 const char *section
,
1280 unsigned section_line
,
1287 ExecContext
*c
= data
;
1298 if (isempty(rvalue
)) {
1299 c
->smack_process_label
= mfree(c
->smack_process_label
);
1300 c
->smack_process_label_ignore
= false;
1304 if (rvalue
[0] == '-') {
1310 r
= unit_name_printf(u
, rvalue
, &k
);
1312 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1316 free(c
->smack_process_label
);
1317 c
->smack_process_label
= k
;
1318 c
->smack_process_label_ignore
= ignore
;
1323 int config_parse_timer(const char *unit
,
1324 const char *filename
,
1326 const char *section
,
1327 unsigned section_line
,
1338 CalendarSpec
*c
= NULL
;
1345 if (isempty(rvalue
)) {
1346 /* Empty assignment resets list */
1347 timer_free_values(t
);
1351 b
= timer_base_from_string(lvalue
);
1353 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1357 if (b
== TIMER_CALENDAR
) {
1358 if (calendar_spec_from_string(rvalue
, &c
) < 0) {
1359 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", rvalue
);
1363 if (parse_sec(rvalue
, &u
) < 0) {
1364 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", rvalue
);
1369 v
= new0(TimerValue
, 1);
1371 calendar_spec_free(c
);
1377 v
->calendar_spec
= c
;
1379 LIST_PREPEND(value
, t
->values
, v
);
1384 int config_parse_trigger_unit(
1386 const char *filename
,
1388 const char *section
,
1389 unsigned section_line
,
1396 _cleanup_free_
char *p
= NULL
;
1406 if (!set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1407 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1411 r
= unit_name_printf(u
, rvalue
, &p
);
1413 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1417 type
= unit_name_to_type(p
);
1419 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1423 if (type
== u
->type
) {
1424 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trigger cannot be of same type, ignoring: %s", rvalue
);
1428 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true);
1430 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1437 int config_parse_path_spec(const char *unit
,
1438 const char *filename
,
1440 const char *section
,
1441 unsigned section_line
,
1451 _cleanup_free_
char *k
= NULL
;
1459 if (isempty(rvalue
)) {
1460 /* Empty assignment clears list */
1465 b
= path_type_from_string(lvalue
);
1467 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1471 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1473 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1477 if (!path_is_absolute(k
)) {
1478 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1482 s
= new0(PathSpec
, 1);
1487 s
->path
= path_kill_slashes(k
);
1492 LIST_PREPEND(spec
, p
->specs
, s
);
1497 int config_parse_socket_service(
1499 const char *filename
,
1501 const char *section
,
1502 unsigned section_line
,
1509 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1510 _cleanup_free_
char *p
= NULL
;
1520 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1522 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1526 if (!endswith(p
, ".service")) {
1527 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1531 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1533 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1537 unit_ref_set(&s
->service
, x
);
1542 int config_parse_fdname(
1544 const char *filename
,
1546 const char *section
,
1547 unsigned section_line
,
1554 _cleanup_free_
char *p
= NULL
;
1563 if (isempty(rvalue
)) {
1564 s
->fdname
= mfree(s
->fdname
);
1568 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1570 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1574 if (!fdname_is_valid(p
)) {
1575 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1586 int config_parse_service_sockets(
1588 const char *filename
,
1590 const char *section
,
1591 unsigned section_line
,
1609 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1611 r
= extract_first_word(&p
, &word
, NULL
, 0);
1617 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1621 r
= unit_name_printf(UNIT(s
), word
, &k
);
1623 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1627 if (!endswith(k
, ".socket")) {
1628 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1632 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1634 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1636 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1638 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1644 int config_parse_bus_name(
1646 const char *filename
,
1648 const char *section
,
1649 unsigned section_line
,
1656 _cleanup_free_
char *k
= NULL
;
1665 r
= unit_full_printf(u
, rvalue
, &k
);
1667 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1671 if (!service_name_is_valid(k
)) {
1672 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1676 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1679 int config_parse_service_timeout(
1681 const char *filename
,
1683 const char *section
,
1684 unsigned section_line
,
1691 Service
*s
= userdata
;
1700 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1702 r
= parse_sec(rvalue
, &usec
);
1704 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1708 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
1709 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
1710 * all other timeouts. */
1712 usec
= USEC_INFINITY
;
1714 if (!streq(lvalue
, "TimeoutStopSec")) {
1715 s
->start_timeout_defined
= true;
1716 s
->timeout_start_usec
= usec
;
1719 if (!streq(lvalue
, "TimeoutStartSec"))
1720 s
->timeout_stop_usec
= usec
;
1725 int config_parse_sec_fix_0(
1727 const char *filename
,
1729 const char *section
,
1730 unsigned section_line
,
1737 usec_t
*usec
= data
;
1745 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
1746 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
1749 r
= parse_sec(rvalue
, usec
);
1751 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
1756 *usec
= USEC_INFINITY
;
1761 int config_parse_busname_service(
1763 const char *filename
,
1765 const char *section
,
1766 unsigned section_line
,
1773 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1777 _cleanup_free_
char *p
= NULL
;
1784 r
= unit_name_printf(UNIT(n
), rvalue
, &p
);
1786 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1790 if (!endswith(p
, ".service")) {
1791 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service, ignoring: %s", rvalue
);
1795 r
= manager_load_unit(UNIT(n
)->manager
, p
, NULL
, &error
, &x
);
1797 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s, ignoring: %s", rvalue
, bus_error_message(&error
, r
));
1801 unit_ref_set(&n
->service
, x
);
1806 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world
, bus_policy_access
, BusPolicyAccess
, "Failed to parse bus name policy access");
1808 int config_parse_bus_policy(
1810 const char *filename
,
1812 const char *section
,
1813 unsigned section_line
,
1820 _cleanup_free_ BusNamePolicy
*p
= NULL
;
1821 _cleanup_free_
char *id_str
= NULL
;
1822 BusName
*busname
= data
;
1830 p
= new0(BusNamePolicy
, 1);
1834 if (streq(lvalue
, "AllowUser"))
1835 p
->type
= BUSNAME_POLICY_TYPE_USER
;
1836 else if (streq(lvalue
, "AllowGroup"))
1837 p
->type
= BUSNAME_POLICY_TYPE_GROUP
;
1839 assert_not_reached("Unknown lvalue");
1841 id_str
= strdup(rvalue
);
1845 access_str
= strpbrk(id_str
, WHITESPACE
);
1847 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy value '%s'", rvalue
);
1853 access_str
+= strspn(access_str
, WHITESPACE
);
1855 p
->access
= bus_policy_access_from_string(access_str
);
1856 if (p
->access
< 0) {
1857 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid busname policy access type '%s'", access_str
);
1864 LIST_PREPEND(policy
, busname
->policy
, p
);
1870 int config_parse_working_directory(
1872 const char *filename
,
1874 const char *section
,
1875 unsigned section_line
,
1882 ExecContext
*c
= data
;
1893 if (rvalue
[0] == '-') {
1899 if (streq(rvalue
, "~")) {
1900 c
->working_directory_home
= true;
1901 c
->working_directory
= mfree(c
->working_directory
);
1903 _cleanup_free_
char *k
= NULL
;
1905 r
= unit_full_printf(u
, rvalue
, &k
);
1907 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue
);
1911 path_kill_slashes(k
);
1913 if (!utf8_is_valid(k
)) {
1914 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
1918 if (!path_is_absolute(k
)) {
1919 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue
);
1923 free(c
->working_directory
);
1924 c
->working_directory
= k
;
1927 c
->working_directory_home
= false;
1930 c
->working_directory_missing_ok
= missing_ok
;
1934 int config_parse_unit_env_file(const char *unit
,
1935 const char *filename
,
1937 const char *section
,
1938 unsigned section_line
,
1947 _cleanup_free_
char *n
= NULL
;
1955 if (isempty(rvalue
)) {
1956 /* Empty assignment frees the list */
1957 *env
= strv_free(*env
);
1961 r
= unit_full_printf(u
, rvalue
, &n
);
1963 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1967 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
1968 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
1972 r
= strv_extend(env
, n
);
1979 int config_parse_environ(const char *unit
,
1980 const char *filename
,
1982 const char *section
,
1983 unsigned section_line
,
1992 const char *word
, *state
;
1994 _cleanup_free_
char *k
= NULL
;
2002 if (isempty(rvalue
)) {
2003 /* Empty assignment resets the list */
2004 *env
= strv_free(*env
);
2009 r
= unit_full_printf(u
, rvalue
, &k
);
2011 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2022 FOREACH_WORD_QUOTED(word
, l
, k
, state
) {
2023 _cleanup_free_
char *n
= NULL
;
2026 r
= cunescape_length(word
, l
, 0, &n
);
2028 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Couldn't unescape assignment, ignoring: %s", rvalue
);
2032 if (!env_assignment_is_valid(n
)) {
2033 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid environment assignment, ignoring: %s", rvalue
);
2037 x
= strv_env_set(*env
, n
);
2044 if (!isempty(state
))
2045 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2050 int config_parse_pass_environ(const char *unit
,
2051 const char *filename
,
2053 const char *section
,
2054 unsigned section_line
,
2061 const char *whole_rvalue
= rvalue
;
2062 char*** passenv
= data
;
2063 _cleanup_strv_free_
char **n
= NULL
;
2064 size_t nlen
= 0, nbufsize
= 0;
2072 if (isempty(rvalue
)) {
2073 /* Empty assignment resets the list */
2074 *passenv
= strv_free(*passenv
);
2079 _cleanup_free_
char *word
= NULL
;
2081 r
= extract_first_word(&rvalue
, &word
, WHITESPACE
, EXTRACT_QUOTES
);
2087 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2088 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2092 if (!env_name_is_valid(word
)) {
2093 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
2094 "Invalid environment name for %s, ignoring: %s", lvalue
, word
);
2098 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2106 r
= strv_extend_strv(passenv
, n
, true);
2114 int config_parse_ip_tos(const char *unit
,
2115 const char *filename
,
2117 const char *section
,
2118 unsigned section_line
,
2125 int *ip_tos
= data
, x
;
2132 x
= ip_tos_from_string(rvalue
);
2134 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2142 int config_parse_unit_condition_path(
2144 const char *filename
,
2146 const char *section
,
2147 unsigned section_line
,
2154 _cleanup_free_
char *p
= NULL
;
2155 Condition
**list
= data
, *c
;
2156 ConditionType t
= ltype
;
2157 bool trigger
, negate
;
2166 if (isempty(rvalue
)) {
2167 /* Empty assignment resets the list */
2168 *list
= condition_free_list(*list
);
2172 trigger
= rvalue
[0] == '|';
2176 negate
= rvalue
[0] == '!';
2180 r
= unit_full_printf(u
, rvalue
, &p
);
2182 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2186 if (!path_is_absolute(p
)) {
2187 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2191 c
= condition_new(t
, p
, trigger
, negate
);
2195 LIST_PREPEND(conditions
, *list
, c
);
2199 int config_parse_unit_condition_string(
2201 const char *filename
,
2203 const char *section
,
2204 unsigned section_line
,
2211 _cleanup_free_
char *s
= NULL
;
2212 Condition
**list
= data
, *c
;
2213 ConditionType t
= ltype
;
2214 bool trigger
, negate
;
2223 if (isempty(rvalue
)) {
2224 /* Empty assignment resets the list */
2225 *list
= condition_free_list(*list
);
2229 trigger
= rvalue
[0] == '|';
2233 negate
= rvalue
[0] == '!';
2237 r
= unit_full_printf(u
, rvalue
, &s
);
2239 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2243 c
= condition_new(t
, s
, trigger
, negate
);
2247 LIST_PREPEND(conditions
, *list
, c
);
2251 int config_parse_unit_condition_null(
2253 const char *filename
,
2255 const char *section
,
2256 unsigned section_line
,
2263 Condition
**list
= data
, *c
;
2264 bool trigger
, negate
;
2272 if (isempty(rvalue
)) {
2273 /* Empty assignment resets the list */
2274 *list
= condition_free_list(*list
);
2278 trigger
= rvalue
[0] == '|';
2282 negate
= rvalue
[0] == '!';
2286 b
= parse_boolean(rvalue
);
2288 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2295 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2299 LIST_PREPEND(conditions
, *list
, c
);
2303 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2304 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action
, failure_action
, FailureAction
, "Failed to parse failure action specifier");
2306 int config_parse_unit_requires_mounts_for(
2308 const char *filename
,
2310 const char *section
,
2311 unsigned section_line
,
2319 const char *word
, *state
;
2327 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2329 _cleanup_free_
char *n
;
2331 n
= strndup(word
, l
);
2335 if (!utf8_is_valid(n
)) {
2336 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2340 r
= unit_require_mounts_for(u
, n
);
2342 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount for, ignoring: %s", rvalue
);
2346 if (!isempty(state
))
2347 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2352 int config_parse_documentation(const char *unit
,
2353 const char *filename
,
2355 const char *section
,
2356 unsigned section_line
,
2372 if (isempty(rvalue
)) {
2373 /* Empty assignment resets the list */
2374 u
->documentation
= strv_free(u
->documentation
);
2378 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2379 rvalue
, data
, userdata
);
2383 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2385 if (documentation_url_is_valid(*a
))
2388 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2399 static int syscall_filter_parse_one(
2401 const char *filename
,
2410 const SystemCallFilterSet
*set
;
2412 for (set
= syscall_filter_sets
; set
->set_name
; set
++)
2413 if (streq(set
->set_name
, t
)) {
2416 NULSTR_FOREACH(sys
, set
->value
) {
2417 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, sys
, false);
2426 id
= seccomp_syscall_resolve_name(t
);
2429 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call, ignoring: %s", t
);
2433 /* If we previously wanted to forbid a syscall and now
2434 * we want to allow it, then remove it from the list
2436 if (!invert
== c
->syscall_whitelist
) {
2437 r
= set_put(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2443 set_remove(c
->syscall_filter
, INT_TO_PTR(id
+ 1));
2448 int config_parse_syscall_filter(
2450 const char *filename
,
2452 const char *section
,
2453 unsigned section_line
,
2460 ExecContext
*c
= data
;
2462 bool invert
= false;
2463 const char *word
, *state
;
2472 if (isempty(rvalue
)) {
2473 /* Empty assignment resets the list */
2474 c
->syscall_filter
= set_free(c
->syscall_filter
);
2475 c
->syscall_whitelist
= false;
2479 if (rvalue
[0] == '~') {
2484 if (!c
->syscall_filter
) {
2485 c
->syscall_filter
= set_new(NULL
);
2486 if (!c
->syscall_filter
)
2490 /* Allow everything but the ones listed */
2491 c
->syscall_whitelist
= false;
2493 /* Allow nothing but the ones listed */
2494 c
->syscall_whitelist
= true;
2496 /* Accept default syscalls if we are on a whitelist */
2497 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, false, "@default", false);
2503 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2504 _cleanup_free_
char *t
= NULL
;
2506 t
= strndup(word
, l
);
2510 r
= syscall_filter_parse_one(unit
, filename
, line
, c
, invert
, t
, true);
2514 if (!isempty(state
))
2515 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2517 /* Turn on NNP, but only if it wasn't configured explicitly
2518 * before, and only if we are in user mode. */
2519 if (!c
->no_new_privileges_set
&& MANAGER_IS_USER(u
->manager
))
2520 c
->no_new_privileges
= true;
2525 int config_parse_syscall_archs(
2527 const char *filename
,
2529 const char *section
,
2530 unsigned section_line
,
2538 const char *word
, *state
;
2542 if (isempty(rvalue
)) {
2543 *archs
= set_free(*archs
);
2547 r
= set_ensure_allocated(archs
, NULL
);
2551 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2552 _cleanup_free_
char *t
= NULL
;
2555 t
= strndup(word
, l
);
2559 r
= seccomp_arch_from_string(t
, &a
);
2561 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse system call architecture, ignoring: %s", t
);
2565 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2571 if (!isempty(state
))
2572 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2577 int config_parse_syscall_errno(
2579 const char *filename
,
2581 const char *section
,
2582 unsigned section_line
,
2589 ExecContext
*c
= data
;
2596 if (isempty(rvalue
)) {
2597 /* Empty assignment resets to KILL */
2598 c
->syscall_errno
= 0;
2602 e
= errno_from_name(rvalue
);
2604 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
2608 c
->syscall_errno
= e
;
2612 int config_parse_address_families(
2614 const char *filename
,
2616 const char *section
,
2617 unsigned section_line
,
2624 ExecContext
*c
= data
;
2625 bool invert
= false;
2626 const char *word
, *state
;
2634 if (isempty(rvalue
)) {
2635 /* Empty assignment resets the list */
2636 c
->address_families
= set_free(c
->address_families
);
2637 c
->address_families_whitelist
= false;
2641 if (rvalue
[0] == '~') {
2646 if (!c
->address_families
) {
2647 c
->address_families
= set_new(NULL
);
2648 if (!c
->address_families
)
2651 c
->address_families_whitelist
= !invert
;
2654 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
2655 _cleanup_free_
char *t
= NULL
;
2658 t
= strndup(word
, l
);
2662 af
= af_from_name(t
);
2664 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse address family, ignoring: %s", t
);
2668 /* If we previously wanted to forbid an address family and now
2669 * we want to allow it, then remove it from the list
2671 if (!invert
== c
->address_families_whitelist
) {
2672 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
2678 set_remove(c
->address_families
, INT_TO_PTR(af
));
2680 if (!isempty(state
))
2681 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
2687 int config_parse_unit_slice(
2689 const char *filename
,
2691 const char *section
,
2692 unsigned section_line
,
2699 _cleanup_free_
char *k
= NULL
;
2700 Unit
*u
= userdata
, *slice
= NULL
;
2708 r
= unit_name_printf(u
, rvalue
, &k
);
2710 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
2714 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
2716 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
2720 r
= unit_set_slice(u
, slice
);
2722 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
2729 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
2731 int config_parse_cpu_shares(
2733 const char *filename
,
2735 const char *section
,
2736 unsigned section_line
,
2743 uint64_t *shares
= data
;
2750 r
= cg_cpu_shares_parse(rvalue
, shares
);
2752 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
2759 int config_parse_cpu_quota(
2761 const char *filename
,
2763 const char *section
,
2764 unsigned section_line
,
2771 CGroupContext
*c
= data
;
2778 if (isempty(rvalue
)) {
2779 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
2783 if (!endswith(rvalue
, "%")) {
2784 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue
);
2788 if (sscanf(rvalue
, "%lf%%", &percent
) != 1 || percent
<= 0) {
2789 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU quota '%s' invalid. Ignoring.", rvalue
);
2793 c
->cpu_quota_per_sec_usec
= (usec_t
) (percent
* USEC_PER_SEC
/ 100);
2798 int config_parse_memory_limit(
2800 const char *filename
,
2802 const char *section
,
2803 unsigned section_line
,
2810 CGroupContext
*c
= data
;
2811 uint64_t bytes
= CGROUP_LIMIT_MAX
;
2814 if (!isempty(rvalue
) && !streq(rvalue
, "infinity") && !streq(rvalue
, "max")) {
2815 r
= parse_size(rvalue
, 1024, &bytes
);
2816 if (r
< 0 || bytes
< 1) {
2817 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
2822 if (streq(lvalue
, "MemoryLow"))
2823 c
->memory_low
= bytes
;
2824 else if (streq(lvalue
, "MemoryHigh"))
2825 c
->memory_high
= bytes
;
2826 else if (streq(lvalue
, "MemoryMax"))
2827 c
->memory_max
= bytes
;
2829 c
->memory_limit
= bytes
;
2834 int config_parse_tasks_max(
2836 const char *filename
,
2838 const char *section
,
2839 unsigned section_line
,
2846 uint64_t *tasks_max
= data
, u
;
2849 if (isempty(rvalue
) || streq(rvalue
, "infinity")) {
2850 *tasks_max
= (uint64_t) -1;
2854 r
= safe_atou64(rvalue
, &u
);
2855 if (r
< 0 || u
< 1) {
2856 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
2864 int config_parse_device_allow(
2866 const char *filename
,
2868 const char *section
,
2869 unsigned section_line
,
2876 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
2877 CGroupContext
*c
= data
;
2878 CGroupDeviceAllow
*a
;
2879 const char *m
= NULL
;
2883 if (isempty(rvalue
)) {
2884 while (c
->device_allow
)
2885 cgroup_context_free_device_allow(c
, c
->device_allow
);
2890 r
= unit_full_printf(userdata
, rvalue
, &t
);
2892 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2893 "Failed to resolve specifiers in %s, ignoring: %m",
2897 n
= strcspn(t
, WHITESPACE
);
2899 path
= strndup(t
, n
);
2903 if (!startswith(path
, "/dev/") &&
2904 !startswith(path
, "block-") &&
2905 !startswith(path
, "char-")) {
2906 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
2910 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
2914 if (!in_charset(m
, "rwm")) {
2915 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
2919 a
= new0(CGroupDeviceAllow
, 1);
2925 a
->r
= !!strchr(m
, 'r');
2926 a
->w
= !!strchr(m
, 'w');
2927 a
->m
= !!strchr(m
, 'm');
2929 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
2933 int config_parse_io_weight(
2935 const char *filename
,
2937 const char *section
,
2938 unsigned section_line
,
2945 uint64_t *weight
= data
;
2952 r
= cg_weight_parse(rvalue
, weight
);
2954 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
2961 int config_parse_io_device_weight(
2963 const char *filename
,
2965 const char *section
,
2966 unsigned section_line
,
2973 _cleanup_free_
char *path
= NULL
;
2974 CGroupIODeviceWeight
*w
;
2975 CGroupContext
*c
= data
;
2985 if (isempty(rvalue
)) {
2986 while (c
->io_device_weights
)
2987 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
2992 n
= strcspn(rvalue
, WHITESPACE
);
2993 weight
= rvalue
+ n
;
2994 weight
+= strspn(weight
, WHITESPACE
);
2996 if (isempty(weight
)) {
2997 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3001 path
= strndup(rvalue
, n
);
3005 if (!path_startswith(path
, "/dev")) {
3006 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3010 r
= cg_weight_parse(weight
, &u
);
3012 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3016 assert(u
!= CGROUP_WEIGHT_INVALID
);
3018 w
= new0(CGroupIODeviceWeight
, 1);
3027 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3031 int config_parse_io_limit(
3033 const char *filename
,
3035 const char *section
,
3036 unsigned section_line
,
3043 _cleanup_free_
char *path
= NULL
;
3044 CGroupIODeviceLimit
*l
= NULL
, *t
;
3045 CGroupContext
*c
= data
;
3046 CGroupIOLimitType type
;
3056 type
= cgroup_io_limit_type_from_string(lvalue
);
3059 if (isempty(rvalue
)) {
3060 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3061 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3065 n
= strcspn(rvalue
, WHITESPACE
);
3067 limit
+= strspn(limit
, WHITESPACE
);
3070 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3074 path
= strndup(rvalue
, n
);
3078 if (!path_startswith(path
, "/dev")) {
3079 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3083 if (streq("max", limit
)) {
3084 num
= CGROUP_LIMIT_MAX
;
3086 r
= parse_size(limit
, 1000, &num
);
3087 if (r
< 0 || num
<= 0) {
3088 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3093 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3094 if (path_equal(path
, t
->path
)) {
3101 CGroupIOLimitType ttype
;
3103 l
= new0(CGroupIODeviceLimit
, 1);
3109 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3110 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3112 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3115 l
->limits
[type
] = num
;
3120 int config_parse_blockio_weight(
3122 const char *filename
,
3124 const char *section
,
3125 unsigned section_line
,
3132 uint64_t *weight
= data
;
3139 r
= cg_blkio_weight_parse(rvalue
, weight
);
3141 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3148 int config_parse_blockio_device_weight(
3150 const char *filename
,
3152 const char *section
,
3153 unsigned section_line
,
3160 _cleanup_free_
char *path
= NULL
;
3161 CGroupBlockIODeviceWeight
*w
;
3162 CGroupContext
*c
= data
;
3172 if (isempty(rvalue
)) {
3173 while (c
->blockio_device_weights
)
3174 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3179 n
= strcspn(rvalue
, WHITESPACE
);
3180 weight
= rvalue
+ n
;
3181 weight
+= strspn(weight
, WHITESPACE
);
3183 if (isempty(weight
)) {
3184 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3188 path
= strndup(rvalue
, n
);
3192 if (!path_startswith(path
, "/dev")) {
3193 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3197 r
= cg_blkio_weight_parse(weight
, &u
);
3199 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3203 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3205 w
= new0(CGroupBlockIODeviceWeight
, 1);
3214 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3218 int config_parse_blockio_bandwidth(
3220 const char *filename
,
3222 const char *section
,
3223 unsigned section_line
,
3230 _cleanup_free_
char *path
= NULL
;
3231 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3232 CGroupContext
*c
= data
;
3233 const char *bandwidth
;
3243 read
= streq("BlockIOReadBandwidth", lvalue
);
3245 if (isempty(rvalue
)) {
3246 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3247 b
->rbps
= CGROUP_LIMIT_MAX
;
3248 b
->wbps
= CGROUP_LIMIT_MAX
;
3253 n
= strcspn(rvalue
, WHITESPACE
);
3254 bandwidth
= rvalue
+ n
;
3255 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3258 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3262 path
= strndup(rvalue
, n
);
3266 if (!path_startswith(path
, "/dev")) {
3267 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3271 r
= parse_size(bandwidth
, 1000, &bytes
);
3272 if (r
< 0 || bytes
<= 0) {
3273 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3277 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3278 if (path_equal(path
, t
->path
)) {
3285 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3291 b
->rbps
= CGROUP_LIMIT_MAX
;
3292 b
->wbps
= CGROUP_LIMIT_MAX
;
3294 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3305 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3307 int config_parse_job_mode_isolate(
3309 const char *filename
,
3311 const char *section
,
3312 unsigned section_line
,
3326 r
= parse_boolean(rvalue
);
3328 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3332 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3336 int config_parse_runtime_directory(
3338 const char *filename
,
3340 const char *section
,
3341 unsigned section_line
,
3350 const char *word
, *state
;
3359 if (isempty(rvalue
)) {
3360 /* Empty assignment resets the list */
3361 *rt
= strv_free(*rt
);
3365 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
3366 _cleanup_free_
char *t
= NULL
, *n
= NULL
;
3368 t
= strndup(word
, l
);
3372 r
= unit_name_printf(u
, t
, &n
);
3374 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
3378 if (!filename_is_valid(n
)) {
3379 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue
);
3383 r
= strv_push(rt
, n
);
3389 if (!isempty(state
))
3390 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3395 int config_parse_set_status(
3397 const char *filename
,
3399 const char *section
,
3400 unsigned section_line
,
3408 const char *word
, *state
;
3410 ExitStatusSet
*status_set
= data
;
3417 /* Empty assignment resets the list */
3418 if (isempty(rvalue
)) {
3419 exit_status_set_free(status_set
);
3423 FOREACH_WORD(word
, l
, rvalue
, state
) {
3424 _cleanup_free_
char *temp
;
3428 temp
= strndup(word
, l
);
3432 r
= safe_atoi(temp
, &val
);
3434 val
= signal_from_string_try_harder(temp
);
3437 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
3440 set
= &status_set
->signal
;
3442 if (val
< 0 || val
> 255) {
3443 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
3446 set
= &status_set
->status
;
3449 r
= set_ensure_allocated(set
, NULL
);
3453 r
= set_put(*set
, INT_TO_PTR(val
));
3455 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
3459 if (!isempty(state
))
3460 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
3465 int config_parse_namespace_path_strv(
3467 const char *filename
,
3469 const char *section
,
3470 unsigned section_line
,
3487 if (isempty(rvalue
)) {
3488 /* Empty assignment resets the list */
3489 *sv
= strv_free(*sv
);
3493 prev
= cur
= rvalue
;
3495 _cleanup_free_
char *word
= NULL
;
3498 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
3504 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage, ignoring: %s", prev
);
3508 if (!utf8_is_valid(word
)) {
3509 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
3514 offset
= word
[0] == '-';
3515 if (!path_is_absolute(word
+ offset
)) {
3516 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", word
);
3521 path_kill_slashes(word
+ offset
);
3523 r
= strv_push(sv
, word
);
3534 int config_parse_no_new_privileges(
3536 const char *filename
,
3538 const char *section
,
3539 unsigned section_line
,
3546 ExecContext
*c
= data
;
3554 k
= parse_boolean(rvalue
);
3556 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
3560 c
->no_new_privileges
= !!k
;
3561 c
->no_new_privileges_set
= true;
3566 int config_parse_protect_home(
3568 const char *filename
,
3570 const char *section
,
3571 unsigned section_line
,
3578 ExecContext
*c
= data
;
3586 /* Our enum shall be a superset of booleans, hence first try
3587 * to parse as as boolean, and then as enum */
3589 k
= parse_boolean(rvalue
);
3591 c
->protect_home
= PROTECT_HOME_YES
;
3593 c
->protect_home
= PROTECT_HOME_NO
;
3597 h
= protect_home_from_string(rvalue
);
3599 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
3603 c
->protect_home
= h
;
3609 int config_parse_protect_system(
3611 const char *filename
,
3613 const char *section
,
3614 unsigned section_line
,
3621 ExecContext
*c
= data
;
3629 /* Our enum shall be a superset of booleans, hence first try
3630 * to parse as as boolean, and then as enum */
3632 k
= parse_boolean(rvalue
);
3634 c
->protect_system
= PROTECT_SYSTEM_YES
;
3636 c
->protect_system
= PROTECT_SYSTEM_NO
;
3640 s
= protect_system_from_string(rvalue
);
3642 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
3646 c
->protect_system
= s
;
3652 #define FOLLOW_MAX 8
3654 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
3665 /* This will update the filename pointer if the loaded file is
3666 * reached by a symlink. The old string will be freed. */
3669 char *target
, *name
;
3671 if (c
++ >= FOLLOW_MAX
)
3674 path_kill_slashes(*filename
);
3676 /* Add the file name we are currently looking at to
3677 * the names of this unit, but only if it is a valid
3679 name
= basename(*filename
);
3680 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
3682 id
= set_get(names
, name
);
3688 r
= set_consume(names
, id
);
3694 /* Try to open the file name, but don't if its a symlink */
3695 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
3702 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3703 r
= readlink_and_make_absolute(*filename
, &target
);
3711 f
= fdopen(fd
, "re");
3723 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
3731 /* Let's try to add in all symlink names we found */
3732 while ((k
= set_steal_first(names
))) {
3734 /* First try to merge in the other name into our
3736 r
= unit_merge_by_name(*u
, k
);
3740 /* Hmm, we couldn't merge the other unit into
3741 * ours? Then let's try it the other way
3744 /* If the symlink name we are looking at is unit template, then
3745 we must search for instance of this template */
3746 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
)) {
3747 _cleanup_free_
char *instance
= NULL
;
3749 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
3753 other
= manager_get_unit((*u
)->manager
, instance
);
3755 other
= manager_get_unit((*u
)->manager
, k
);
3760 r
= unit_merge(other
, *u
);
3763 return merge_by_names(u
, names
, NULL
);
3771 unit_choose_id(*u
, id
);
3779 static int load_from_path(Unit
*u
, const char *path
) {
3780 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
3781 _cleanup_fclose_
FILE *f
= NULL
;
3782 _cleanup_free_
char *filename
= NULL
;
3791 symlink_names
= set_new(&string_hash_ops
);
3795 if (path_is_absolute(path
)) {
3797 filename
= strdup(path
);
3801 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3803 filename
= mfree(filename
);
3811 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
3813 /* Instead of opening the path right away, we manually
3814 * follow all symlinks and add their name to our unit
3815 * name set while doing so */
3816 filename
= path_make_absolute(path
, *p
);
3820 if (u
->manager
->unit_path_cache
&&
3821 !set_get(u
->manager
->unit_path_cache
, filename
))
3824 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
3827 filename
= mfree(filename
);
3831 /* Empty the symlink names for the next run */
3832 set_clear_free(symlink_names
);
3837 /* Hmm, no suitable file found? */
3840 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
3841 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
3846 r
= merge_by_names(&merged
, symlink_names
, id
);
3851 u
->load_state
= UNIT_MERGED
;
3855 if (fstat(fileno(f
), &st
) < 0)
3858 if (null_or_empty(&st
)) {
3859 u
->load_state
= UNIT_MASKED
;
3860 u
->fragment_mtime
= 0;
3862 u
->load_state
= UNIT_LOADED
;
3863 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
3865 /* Now, parse the file contents */
3866 r
= config_parse(u
->id
, filename
, f
,
3867 UNIT_VTABLE(u
)->sections
,
3868 config_item_perf_lookup
, load_fragment_gperf_lookup
,
3869 false, true, false, u
);
3874 free(u
->fragment_path
);
3875 u
->fragment_path
= filename
;
3878 if (u
->source_path
) {
3879 if (stat(u
->source_path
, &st
) >= 0)
3880 u
->source_mtime
= timespec_load(&st
.st_mtim
);
3882 u
->source_mtime
= 0;
3888 int unit_load_fragment(Unit
*u
) {
3894 assert(u
->load_state
== UNIT_STUB
);
3898 u
->load_state
= UNIT_LOADED
;
3902 /* First, try to find the unit under its id. We always look
3903 * for unit files in the default directories, to make it easy
3904 * to override things by placing things in /etc/systemd/system */
3905 r
= load_from_path(u
, u
->id
);
3909 /* Try to find an alias we can load this with */
3910 if (u
->load_state
== UNIT_STUB
) {
3911 SET_FOREACH(t
, u
->names
, i
) {
3916 r
= load_from_path(u
, t
);
3920 if (u
->load_state
!= UNIT_STUB
)
3925 /* And now, try looking for it under the suggested (originally linked) path */
3926 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
3928 r
= load_from_path(u
, u
->fragment_path
);
3932 if (u
->load_state
== UNIT_STUB
)
3933 /* Hmm, this didn't work? Then let's get rid
3934 * of the fragment path stored for us, so that
3935 * we don't point to an invalid location. */
3936 u
->fragment_path
= mfree(u
->fragment_path
);
3939 /* Look for a template */
3940 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
3941 _cleanup_free_
char *k
= NULL
;
3943 r
= unit_name_template(u
->id
, &k
);
3947 r
= load_from_path(u
, k
);
3951 if (u
->load_state
== UNIT_STUB
) {
3952 SET_FOREACH(t
, u
->names
, i
) {
3953 _cleanup_free_
char *z
= NULL
;
3958 r
= unit_name_template(t
, &z
);
3962 r
= load_from_path(u
, z
);
3966 if (u
->load_state
!= UNIT_STUB
)
3975 void unit_dump_config_items(FILE *f
) {
3976 static const struct {
3977 const ConfigParserCallback callback
;
3980 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3981 { config_parse_warn_compat
, "NOTSUPPORTED" },
3983 { config_parse_int
, "INTEGER" },
3984 { config_parse_unsigned
, "UNSIGNED" },
3985 { config_parse_iec_size
, "SIZE" },
3986 { config_parse_iec_uint64
, "SIZE" },
3987 { config_parse_si_size
, "SIZE" },
3988 { config_parse_bool
, "BOOLEAN" },
3989 { config_parse_string
, "STRING" },
3990 { config_parse_path
, "PATH" },
3991 { config_parse_unit_path_printf
, "PATH" },
3992 { config_parse_strv
, "STRING [...]" },
3993 { config_parse_exec_nice
, "NICE" },
3994 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
3995 { config_parse_exec_io_class
, "IOCLASS" },
3996 { config_parse_exec_io_priority
, "IOPRIORITY" },
3997 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
3998 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
3999 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4000 { config_parse_mode
, "MODE" },
4001 { config_parse_unit_env_file
, "FILE" },
4002 { config_parse_output
, "OUTPUT" },
4003 { config_parse_input
, "INPUT" },
4004 { config_parse_log_facility
, "FACILITY" },
4005 { config_parse_log_level
, "LEVEL" },
4006 { config_parse_exec_secure_bits
, "SECUREBITS" },
4007 { config_parse_capability_set
, "BOUNDINGSET" },
4008 { config_parse_limit
, "LIMIT" },
4009 { config_parse_unit_deps
, "UNIT [...]" },
4010 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4011 { config_parse_service_type
, "SERVICETYPE" },
4012 { config_parse_service_restart
, "SERVICERESTART" },
4013 #ifdef HAVE_SYSV_COMPAT
4014 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4016 { config_parse_kill_mode
, "KILLMODE" },
4017 { config_parse_signal
, "SIGNAL" },
4018 { config_parse_socket_listen
, "SOCKET [...]" },
4019 { config_parse_socket_bind
, "SOCKETBIND" },
4020 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4021 { config_parse_sec
, "SECONDS" },
4022 { config_parse_nsec
, "NANOSECONDS" },
4023 { config_parse_namespace_path_strv
, "PATH [...]" },
4024 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4025 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4026 { config_parse_unit_string_printf
, "STRING" },
4027 { config_parse_trigger_unit
, "UNIT" },
4028 { config_parse_timer
, "TIMER" },
4029 { config_parse_path_spec
, "PATH" },
4030 { config_parse_notify_access
, "ACCESS" },
4031 { config_parse_ip_tos
, "TOS" },
4032 { config_parse_unit_condition_path
, "CONDITION" },
4033 { config_parse_unit_condition_string
, "CONDITION" },
4034 { config_parse_unit_condition_null
, "CONDITION" },
4035 { config_parse_unit_slice
, "SLICE" },
4036 { config_parse_documentation
, "URL" },
4037 { config_parse_service_timeout
, "SECONDS" },
4038 { config_parse_failure_action
, "ACTION" },
4039 { config_parse_set_status
, "STATUS" },
4040 { config_parse_service_sockets
, "SOCKETS" },
4041 { config_parse_environ
, "ENVIRON" },
4043 { config_parse_syscall_filter
, "SYSCALLS" },
4044 { config_parse_syscall_archs
, "ARCHS" },
4045 { config_parse_syscall_errno
, "ERRNO" },
4046 { config_parse_address_families
, "FAMILIES" },
4048 { config_parse_cpu_shares
, "SHARES" },
4049 { config_parse_memory_limit
, "LIMIT" },
4050 { config_parse_device_allow
, "DEVICE" },
4051 { config_parse_device_policy
, "POLICY" },
4052 { config_parse_io_limit
, "LIMIT" },
4053 { config_parse_io_weight
, "WEIGHT" },
4054 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4055 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4056 { config_parse_blockio_weight
, "WEIGHT" },
4057 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4058 { config_parse_long
, "LONG" },
4059 { config_parse_socket_service
, "SERVICE" },
4061 { config_parse_exec_selinux_context
, "LABEL" },
4063 { config_parse_job_mode
, "MODE" },
4064 { config_parse_job_mode_isolate
, "BOOLEAN" },
4065 { config_parse_personality
, "PERSONALITY" },
4068 const char *prev
= NULL
;
4073 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4074 const char *rvalue
= "OTHER", *lvalue
;
4078 const ConfigPerfItem
*p
;
4080 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4082 dot
= strchr(i
, '.');
4083 lvalue
= dot
? dot
+ 1 : i
;
4087 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4091 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4094 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4095 if (p
->parse
== table
[j
].callback
) {
4096 rvalue
= table
[j
].rvalue
;
4100 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);