1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
6 Copyright 2012 Holger Hans Peter Freyther
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <linux/oom.h>
31 #include <sys/resource.h>
35 #include "alloc-util.h"
36 #include "bus-error.h"
37 #include "bus-internal.h"
40 #include "capability-util.h"
42 #include "conf-parser.h"
43 #include "cpu-set-util.h"
45 #include "errno-list.h"
49 #include "hexdecoct.h"
52 #include "journal-util.h"
53 #include "load-fragment.h"
56 #include "mount-util.h"
57 #include "parse-util.h"
58 #include "path-util.h"
59 #include "process-util.h"
60 #include "rlimit-util.h"
62 #include "seccomp-util.h"
64 #include "securebits.h"
65 #include "securebits-util.h"
66 #include "signal-util.h"
67 #include "socket-protocol-list.h"
68 #include "stat-util.h"
69 #include "string-util.h"
71 #include "unit-name.h"
72 #include "unit-printf.h"
74 #include "user-util.h"
78 DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode
, collect_mode
, CollectMode
, "Failed to parse garbage collection mode");
80 int config_parse_unit_deps(
85 unsigned section_line
,
92 UnitDependency d
= ltype
;
102 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
105 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_RETAIN_ESCAPE
);
111 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
115 r
= unit_name_printf(u
, word
, &k
);
117 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
121 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
123 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
129 int config_parse_obsolete_unit_deps(
131 const char *filename
,
134 unsigned section_line
,
141 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
142 "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue
, unit_dependency_to_string(ltype
));
144 return config_parse_unit_deps(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, data
, userdata
);
147 int config_parse_unit_string_printf(
149 const char *filename
,
152 unsigned section_line
,
159 _cleanup_free_
char *k
= NULL
;
168 r
= unit_full_printf(u
, rvalue
, &k
);
170 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
174 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
177 int config_parse_unit_strv_printf(
179 const char *filename
,
182 unsigned section_line
,
190 _cleanup_free_
char *k
= NULL
;
198 r
= unit_full_printf(u
, rvalue
, &k
);
200 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
204 return config_parse_strv(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
207 int config_parse_unit_path_printf(
209 const char *filename
,
212 unsigned section_line
,
219 _cleanup_free_
char *k
= NULL
;
229 /* Let's not bother with anything that is too long */
230 if (strlen(rvalue
) >= PATH_MAX
) {
231 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
232 "%s value too long%s.",
233 lvalue
, fatal
? "" : ", ignoring");
234 return fatal
? -ENAMETOOLONG
: 0;
237 r
= unit_full_printf(u
, rvalue
, &k
);
239 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
240 "Failed to resolve unit specifiers in \"%s\"%s: %m",
241 rvalue
, fatal
? "" : ", ignoring");
242 return fatal
? -ENOEXEC
: 0;
245 return config_parse_path(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
248 int config_parse_unit_path_strv_printf(
250 const char *filename
,
253 unsigned section_line
,
270 if (isempty(rvalue
)) {
276 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
278 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
284 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
285 "Invalid syntax, ignoring: %s", rvalue
);
289 r
= unit_full_printf(u
, word
, &k
);
291 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
292 "Failed to resolve unit specifiers on \"%s\", ignoring: %m", word
);
296 if (!utf8_is_valid(k
)) {
297 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
301 if (!path_is_absolute(k
)) {
302 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
303 "Symlink path is not absolute: %s", k
);
307 path_kill_slashes(k
);
316 int config_parse_socket_listen(const char *unit
,
317 const char *filename
,
320 unsigned section_line
,
327 _cleanup_free_ SocketPort
*p
= NULL
;
339 if (isempty(rvalue
)) {
340 /* An empty assignment removes all ports */
341 socket_free_ports(s
);
345 p
= new0(SocketPort
, 1);
349 if (ltype
!= SOCKET_SOCKET
) {
352 r
= unit_full_printf(UNIT(s
), rvalue
, &p
->path
);
354 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
358 path_kill_slashes(p
->path
);
360 } else if (streq(lvalue
, "ListenNetlink")) {
361 _cleanup_free_
char *k
= NULL
;
363 p
->type
= SOCKET_SOCKET
;
364 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
366 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
370 r
= socket_address_parse_netlink(&p
->address
, k
);
372 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
377 _cleanup_free_
char *k
= NULL
;
379 p
->type
= SOCKET_SOCKET
;
380 r
= unit_full_printf(UNIT(s
), rvalue
, &k
);
382 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
386 r
= socket_address_parse_and_warn(&p
->address
, k
);
388 if (r
!= -EAFNOSUPPORT
)
389 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address value, ignoring: %s", rvalue
);
393 if (streq(lvalue
, "ListenStream"))
394 p
->address
.type
= SOCK_STREAM
;
395 else if (streq(lvalue
, "ListenDatagram"))
396 p
->address
.type
= SOCK_DGRAM
;
398 assert(streq(lvalue
, "ListenSequentialPacket"));
399 p
->address
.type
= SOCK_SEQPACKET
;
402 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
403 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address family not supported, ignoring: %s", rvalue
);
409 p
->auxiliary_fds
= NULL
;
410 p
->n_auxiliary_fds
= 0;
413 LIST_FIND_TAIL(port
, s
->ports
, tail
);
414 LIST_INSERT_AFTER(port
, s
->ports
, tail
, p
);
421 int config_parse_socket_protocol(const char *unit
,
422 const char *filename
,
425 unsigned section_line
,
441 r
= socket_protocol_from_name(rvalue
);
443 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid socket protocol, ignoring: %s", rvalue
);
445 } else if (!IN_SET(r
, IPPROTO_UDPLITE
, IPPROTO_SCTP
)) {
446 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Socket protocol not supported, ignoring: %s", rvalue
);
450 s
->socket_protocol
= r
;
455 int config_parse_socket_bind(const char *unit
,
456 const char *filename
,
459 unsigned section_line
,
467 SocketAddressBindIPv6Only b
;
476 b
= parse_socket_address_bind_ipv6_only_or_bool(rvalue
);
478 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue
);
482 s
->bind_ipv6_only
= b
;
487 int config_parse_exec_nice(
489 const char *filename
,
492 unsigned section_line
,
499 ExecContext
*c
= data
;
507 r
= parse_nice(rvalue
, &priority
);
510 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Nice priority out of range, ignoring: %s", rvalue
);
512 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse nice priority, ignoring: %s", rvalue
);
523 int config_parse_exec_oom_score_adjust(const char* unit
,
524 const char *filename
,
527 unsigned section_line
,
534 ExecContext
*c
= data
;
542 r
= safe_atoi(rvalue
, &oa
);
544 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
548 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
549 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "OOM score adjust value out of range, ignoring: %s", rvalue
);
553 c
->oom_score_adjust
= oa
;
554 c
->oom_score_adjust_set
= true;
559 int config_parse_exec(
561 const char *filename
,
564 unsigned section_line
,
571 ExecCommand
**e
= data
;
583 rvalue
+= strspn(rvalue
, WHITESPACE
);
585 if (isempty(rvalue
)) {
586 /* An empty assignment resets the list */
587 *e
= exec_command_free_list(*e
);
593 _cleanup_free_
char *path
= NULL
, *firstword
= NULL
;
594 ExecCommandFlags flags
= 0;
595 bool ignore
= false, separate_argv0
= false;
596 _cleanup_free_ ExecCommand
*nce
= NULL
;
597 _cleanup_strv_free_
char **n
= NULL
;
598 size_t nlen
= 0, nbufsize
= 0;
603 r
= extract_first_word_and_warn(&p
, &firstword
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
609 /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
610 * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
611 * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
612 * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
613 * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
614 * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
615 * other sandboxing, with some special exceptions for changing UID.
617 * The idea is that '!!' may be used to write services that can take benefit of systemd's
618 * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
619 * privilege dropping within the daemon if the kernel does not offer that. */
621 if (*f
== '-' && !(flags
& EXEC_COMMAND_IGNORE_FAILURE
)) {
622 flags
|= EXEC_COMMAND_IGNORE_FAILURE
;
624 } else if (*f
== '@' && !separate_argv0
)
625 separate_argv0
= true;
626 else if (*f
== '+' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
627 flags
|= EXEC_COMMAND_FULLY_PRIVILEGED
;
628 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_NO_SETUID
|EXEC_COMMAND_AMBIENT_MAGIC
)))
629 flags
|= EXEC_COMMAND_NO_SETUID
;
630 else if (*f
== '!' && !(flags
& (EXEC_COMMAND_FULLY_PRIVILEGED
|EXEC_COMMAND_AMBIENT_MAGIC
))) {
631 flags
&= ~EXEC_COMMAND_NO_SETUID
;
632 flags
|= EXEC_COMMAND_AMBIENT_MAGIC
;
638 r
= unit_full_printf(u
, f
, &path
);
640 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
641 "Failed to resolve unit specifiers on %s%s: %m",
642 f
, ignore
? ", ignoring" : "");
643 return ignore
? 0 : -ENOEXEC
;
647 /* First word is either "-" or "@" with no command. */
648 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
649 "Empty path in command line%s: \"%s\"",
650 ignore
? ", ignoring" : "", rvalue
);
651 return ignore
? 0 : -ENOEXEC
;
653 if (!string_is_safe(path
)) {
654 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
655 "Executable path contains special characters%s: %s",
656 ignore
? ", ignoring" : "", rvalue
);
657 return ignore
? 0 : -ENOEXEC
;
659 if (!path_is_absolute(path
)) {
660 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
661 "Executable path is not absolute%s: %s",
662 ignore
? ", ignoring" : "", rvalue
);
663 return ignore
? 0 : -ENOEXEC
;
665 if (endswith(path
, "/")) {
666 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
667 "Executable path specifies a directory%s: %s",
668 ignore
? ", ignoring" : "", rvalue
);
669 return ignore
? 0 : -ENOEXEC
;
672 if (!separate_argv0
) {
675 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
685 path_kill_slashes(path
);
687 while (!isempty(p
)) {
688 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
690 /* Check explicitly for an unquoted semicolon as
691 * command separator token. */
692 if (p
[0] == ';' && (!p
[1] || strchr(WHITESPACE
, p
[1]))) {
694 p
+= strspn(p
, WHITESPACE
);
699 /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
700 * extract_first_word() would return the same for all of those. */
701 if (p
[0] == '\\' && p
[1] == ';' && (!p
[2] || strchr(WHITESPACE
, p
[2]))) {
705 p
+= strspn(p
, WHITESPACE
);
707 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
718 r
= extract_first_word_and_warn(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_CUNESCAPE
, unit
, filename
, line
, rvalue
);
722 return ignore
? 0 : -ENOEXEC
;
724 r
= unit_full_printf(u
, word
, &resolved
);
726 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
727 "Failed to resolve unit specifiers on %s%s: %m",
728 word
, ignore
? ", ignoring" : "");
729 return ignore
? 0 : -ENOEXEC
;
732 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
735 n
[nlen
++] = TAKE_PTR(resolved
);
740 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
741 "Empty executable name or zeroeth argument%s: %s",
742 ignore
? ", ignoring" : "", rvalue
);
743 return ignore
? 0 : -ENOEXEC
;
746 nce
= new0(ExecCommand
, 1);
750 nce
->argv
= TAKE_PTR(n
);
751 nce
->path
= TAKE_PTR(path
);
754 exec_command_append_list(e
, nce
);
756 /* Do not _cleanup_free_ these. */
765 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
766 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
768 int config_parse_socket_bindtodevice(
770 const char *filename
,
773 unsigned section_line
,
788 if (rvalue
[0] && !streq(rvalue
, "*")) {
789 if (!ifname_valid(rvalue
)) {
790 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface name is invalid, ignoring: %s", rvalue
);
800 free(s
->bind_to_device
);
801 s
->bind_to_device
= n
;
806 int config_parse_exec_input(
808 const char *filename
,
811 unsigned section_line
,
818 ExecContext
*c
= data
;
829 n
= startswith(rvalue
, "fd:");
831 _cleanup_free_
char *resolved
= NULL
;
833 r
= unit_full_printf(u
, n
, &resolved
);
835 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
837 if (isempty(resolved
))
838 resolved
= mfree(resolved
);
839 else if (!fdname_is_valid(resolved
)) {
840 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name: %s", resolved
);
844 free_and_replace(c
->stdio_fdname
[STDIN_FILENO
], resolved
);
846 ei
= EXEC_INPUT_NAMED_FD
;
848 } else if ((n
= startswith(rvalue
, "file:"))) {
849 _cleanup_free_
char *resolved
= NULL
;
851 r
= unit_full_printf(u
, n
, &resolved
);
853 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
855 if (!path_is_absolute(resolved
)) {
856 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
860 if (!path_is_normalized(resolved
)) {
861 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name: %s", resolved
);
865 free_and_replace(c
->stdio_file
[STDIN_FILENO
], resolved
);
867 ei
= EXEC_INPUT_FILE
;
870 ei
= exec_input_from_string(rvalue
);
872 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse input specifier, ignoring: %s", rvalue
);
881 int config_parse_exec_input_text(
883 const char *filename
,
886 unsigned section_line
,
893 _cleanup_free_
char *unescaped
= NULL
, *resolved
= NULL
;
894 ExecContext
*c
= data
;
905 if (isempty(rvalue
)) {
906 /* Reset if the empty string is assigned */
907 c
->stdin_data
= mfree(c
->stdin_data
);
908 c
->stdin_data_size
= 0;
912 r
= cunescape(rvalue
, 0, &unescaped
);
914 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode C escaped text: %s", rvalue
);
916 r
= unit_full_printf(u
, unescaped
, &resolved
);
918 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", unescaped
);
920 sz
= strlen(resolved
);
921 if (c
->stdin_data_size
+ sz
+ 1 < c
->stdin_data_size
|| /* check for overflow */
922 c
->stdin_data_size
+ sz
+ 1 > EXEC_STDIN_DATA_MAX
) {
923 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c
->stdin_data_size
+ sz
, (size_t) EXEC_STDIN_DATA_MAX
);
927 p
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
+ 1);
931 *((char*) mempcpy((char*) p
+ c
->stdin_data_size
, resolved
, sz
)) = '\n';
934 c
->stdin_data_size
+= sz
+ 1;
939 int config_parse_exec_input_data(
941 const char *filename
,
944 unsigned section_line
,
951 _cleanup_free_
void *p
= NULL
;
952 ExecContext
*c
= data
;
962 if (isempty(rvalue
)) {
963 /* Reset if the empty string is assigned */
964 c
->stdin_data
= mfree(c
->stdin_data
);
965 c
->stdin_data_size
= 0;
969 r
= unbase64mem(rvalue
, (size_t) -1, &p
, &sz
);
971 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to decode base64 data, ignoring: %s", rvalue
);
975 if (c
->stdin_data_size
+ sz
< c
->stdin_data_size
|| /* check for overflow */
976 c
->stdin_data_size
+ sz
> EXEC_STDIN_DATA_MAX
) {
977 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Standard input data too large (%zu), maximum of %zu permitted, ignoring.", c
->stdin_data_size
+ sz
, (size_t) EXEC_STDIN_DATA_MAX
);
981 q
= realloc(c
->stdin_data
, c
->stdin_data_size
+ sz
);
985 memcpy((uint8_t*) q
+ c
->stdin_data_size
, p
, sz
);
988 c
->stdin_data_size
+= sz
;
993 int config_parse_exec_output(
995 const char *filename
,
998 unsigned section_line
,
1005 _cleanup_free_
char *resolved
= NULL
;
1007 ExecContext
*c
= data
;
1018 n
= startswith(rvalue
, "fd:");
1020 r
= unit_full_printf(u
, n
, &resolved
);
1022 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1024 if (isempty(resolved
))
1025 resolved
= mfree(resolved
);
1026 else if (!fdname_is_valid(resolved
)) {
1027 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name: %s", resolved
);
1031 eo
= EXEC_OUTPUT_NAMED_FD
;
1033 } else if ((n
= startswith(rvalue
, "file:"))) {
1035 r
= unit_full_printf(u
, n
, &resolved
);
1037 return log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s: %m", n
);
1039 if (!path_is_absolute(resolved
)) {
1040 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires an absolute path name: %s", resolved
);
1044 if (!path_is_normalized(resolved
)) {
1045 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "file: requires a normalized path name, ignoring: %s", resolved
);
1049 eo
= EXEC_OUTPUT_FILE
;
1052 eo
= exec_output_from_string(rvalue
);
1054 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse output specifier, ignoring: %s", rvalue
);
1059 if (streq(lvalue
, "StandardOutput")) {
1060 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1061 free_and_replace(c
->stdio_fdname
[STDOUT_FILENO
], resolved
);
1063 free_and_replace(c
->stdio_file
[STDOUT_FILENO
], resolved
);
1068 assert(streq(lvalue
, "StandardError"));
1070 if (eo
== EXEC_OUTPUT_NAMED_FD
)
1071 free_and_replace(c
->stdio_fdname
[STDERR_FILENO
], resolved
);
1073 free_and_replace(c
->stdio_file
[STDERR_FILENO
], resolved
);
1081 int config_parse_exec_io_class(const char *unit
,
1082 const char *filename
,
1084 const char *section
,
1085 unsigned section_line
,
1092 ExecContext
*c
= data
;
1100 x
= ioprio_class_from_string(rvalue
);
1102 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue
);
1106 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
1107 c
->ioprio_set
= true;
1112 int config_parse_exec_io_priority(const char *unit
,
1113 const char *filename
,
1115 const char *section
,
1116 unsigned section_line
,
1123 ExecContext
*c
= data
;
1131 r
= ioprio_parse_priority(rvalue
, &i
);
1133 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IO priority, ignoring: %s", rvalue
);
1137 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
1138 c
->ioprio_set
= true;
1143 int config_parse_exec_cpu_sched_policy(const char *unit
,
1144 const char *filename
,
1146 const char *section
,
1147 unsigned section_line
,
1155 ExecContext
*c
= data
;
1163 x
= sched_policy_from_string(rvalue
);
1165 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1169 c
->cpu_sched_policy
= x
;
1170 /* Moving to or from real-time policy? We need to adjust the priority */
1171 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
1172 c
->cpu_sched_set
= true;
1177 int config_parse_exec_cpu_sched_prio(const char *unit
,
1178 const char *filename
,
1180 const char *section
,
1181 unsigned section_line
,
1188 ExecContext
*c
= data
;
1196 r
= safe_atoi(rvalue
, &i
);
1198 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue
);
1202 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
1203 min
= sched_get_priority_min(c
->cpu_sched_policy
);
1204 max
= sched_get_priority_max(c
->cpu_sched_policy
);
1206 if (i
< min
|| i
> max
) {
1207 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue
);
1211 c
->cpu_sched_priority
= i
;
1212 c
->cpu_sched_set
= true;
1217 int config_parse_exec_cpu_affinity(const char *unit
,
1218 const char *filename
,
1220 const char *section
,
1221 unsigned section_line
,
1228 ExecContext
*c
= data
;
1229 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
1237 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
1242 /* An empty assignment resets the CPU list */
1243 c
->cpuset
= cpu_set_mfree(c
->cpuset
);
1244 c
->cpuset_ncpus
= 0;
1249 c
->cpuset
= TAKE_PTR(cpuset
);
1250 c
->cpuset_ncpus
= (unsigned) ncpus
;
1254 if (c
->cpuset_ncpus
< (unsigned) ncpus
) {
1255 CPU_OR_S(CPU_ALLOC_SIZE(c
->cpuset_ncpus
), cpuset
, c
->cpuset
, cpuset
);
1256 CPU_FREE(c
->cpuset
);
1257 c
->cpuset
= TAKE_PTR(cpuset
);
1258 c
->cpuset_ncpus
= (unsigned) ncpus
;
1262 CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus
), c
->cpuset
, c
->cpuset
, cpuset
);
1267 int config_parse_exec_secure_bits(const char *unit
,
1268 const char *filename
,
1270 const char *section
,
1271 unsigned section_line
,
1278 ExecContext
*c
= data
;
1286 if (isempty(rvalue
)) {
1287 /* An empty assignment resets the field */
1292 r
= secure_bits_from_string(rvalue
);
1296 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1297 "Invalid syntax, ignoring: %s", rvalue
);
1306 int config_parse_capability_set(
1308 const char *filename
,
1310 const char *section
,
1311 unsigned section_line
,
1318 uint64_t *capability_set
= data
;
1319 uint64_t sum
= 0, initial
= 0;
1320 bool invert
= false;
1328 if (rvalue
[0] == '~') {
1333 if (streq(lvalue
, "CapabilityBoundingSet"))
1334 initial
= CAP_ALL
; /* initialized to all bits on */
1335 /* else "AmbientCapabilities" initialized to all bits off */
1337 r
= capability_set_from_string(rvalue
, &sum
);
1341 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse word: %s", rvalue
);
1345 if (sum
== 0 || *capability_set
== initial
)
1346 /* "", "~" or uninitialized data -> replace */
1347 *capability_set
= invert
? ~sum
: sum
;
1349 /* previous data -> merge */
1351 *capability_set
&= ~sum
;
1353 *capability_set
|= sum
;
1359 int config_parse_limit(
1361 const char *filename
,
1363 const char *section
,
1364 unsigned section_line
,
1371 struct rlimit
**rl
= data
, d
= {};
1379 r
= rlimit_parse(ltype
, rvalue
, &d
);
1381 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue
);
1385 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse resource value, ignoring: %s", rvalue
);
1392 rl
[ltype
] = newdup(struct rlimit
, &d
, 1);
1400 #if HAVE_SYSV_COMPAT
1401 int config_parse_sysv_priority(const char *unit
,
1402 const char *filename
,
1404 const char *section
,
1405 unsigned section_line
,
1412 int *priority
= data
;
1420 r
= safe_atoi(rvalue
, &i
);
1421 if (r
< 0 || i
< 0) {
1422 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SysV start priority, ignoring: %s", rvalue
);
1426 *priority
= (int) i
;
1431 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode
, exec_utmp_mode
, ExecUtmpMode
, "Failed to parse utmp mode");
1432 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1434 int config_parse_exec_mount_flags(
1436 const char *filename
,
1438 const char *section
,
1439 unsigned section_line
,
1447 ExecContext
*c
= data
;
1455 r
= mount_propagation_flags_from_string(rvalue
, &c
->mount_flags
);
1457 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse mount flag %s, ignoring.", rvalue
);
1462 int config_parse_exec_selinux_context(
1464 const char *filename
,
1466 const char *section
,
1467 unsigned section_line
,
1474 ExecContext
*c
= data
;
1485 if (isempty(rvalue
)) {
1486 c
->selinux_context
= mfree(c
->selinux_context
);
1487 c
->selinux_context_ignore
= false;
1491 if (rvalue
[0] == '-') {
1497 r
= unit_full_printf(u
, rvalue
, &k
);
1499 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1500 "Failed to resolve specifiers%s: %m",
1501 ignore
? ", ignoring" : "");
1502 return ignore
? 0 : -ENOEXEC
;
1505 free(c
->selinux_context
);
1506 c
->selinux_context
= k
;
1507 c
->selinux_context_ignore
= ignore
;
1512 int config_parse_exec_apparmor_profile(
1514 const char *filename
,
1516 const char *section
,
1517 unsigned section_line
,
1524 ExecContext
*c
= data
;
1535 if (isempty(rvalue
)) {
1536 c
->apparmor_profile
= mfree(c
->apparmor_profile
);
1537 c
->apparmor_profile_ignore
= false;
1541 if (rvalue
[0] == '-') {
1547 r
= unit_full_printf(u
, rvalue
, &k
);
1549 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1550 "Failed to resolve specifiers%s: %m",
1551 ignore
? ", ignoring" : "");
1552 return ignore
? 0 : -ENOEXEC
;
1555 free(c
->apparmor_profile
);
1556 c
->apparmor_profile
= k
;
1557 c
->apparmor_profile_ignore
= ignore
;
1562 int config_parse_exec_smack_process_label(
1564 const char *filename
,
1566 const char *section
,
1567 unsigned section_line
,
1574 ExecContext
*c
= data
;
1585 if (isempty(rvalue
)) {
1586 c
->smack_process_label
= mfree(c
->smack_process_label
);
1587 c
->smack_process_label_ignore
= false;
1591 if (rvalue
[0] == '-') {
1597 r
= unit_full_printf(u
, rvalue
, &k
);
1599 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1600 "Failed to resolve specifiers%s: %m",
1601 ignore
? ", ignoring" : "");
1602 return ignore
? 0 : -ENOEXEC
;
1605 free(c
->smack_process_label
);
1606 c
->smack_process_label
= k
;
1607 c
->smack_process_label_ignore
= ignore
;
1612 int config_parse_timer(const char *unit
,
1613 const char *filename
,
1615 const char *section
,
1616 unsigned section_line
,
1627 CalendarSpec
*c
= NULL
;
1629 _cleanup_free_
char *k
= NULL
;
1637 if (isempty(rvalue
)) {
1638 /* Empty assignment resets list */
1639 timer_free_values(t
);
1643 b
= timer_base_from_string(lvalue
);
1645 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer base, ignoring: %s", lvalue
);
1649 r
= unit_full_printf(u
, rvalue
, &k
);
1651 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue
);
1655 if (b
== TIMER_CALENDAR
) {
1656 if (calendar_spec_from_string(k
, &c
) < 0) {
1657 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse calendar specification, ignoring: %s", k
);
1661 if (parse_sec(k
, &usec
) < 0) {
1662 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse timer value, ignoring: %s", k
);
1667 v
= new0(TimerValue
, 1);
1669 calendar_spec_free(c
);
1675 v
->calendar_spec
= c
;
1677 LIST_PREPEND(value
, t
->values
, v
);
1682 int config_parse_trigger_unit(
1684 const char *filename
,
1686 const char *section
,
1687 unsigned section_line
,
1694 _cleanup_free_
char *p
= NULL
;
1704 if (!hashmap_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
1705 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Multiple units to trigger specified, ignoring: %s", rvalue
);
1709 r
= unit_name_printf(u
, rvalue
, &p
);
1711 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1715 type
= unit_name_to_type(p
);
1717 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit type not valid, ignoring: %s", rvalue
);
1720 if (unit_has_name(u
, p
)) {
1721 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Units cannot trigger themselves, ignoring: %s", rvalue
);
1725 r
= unit_add_two_dependencies_by_name(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, p
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1727 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add trigger on %s, ignoring: %m", p
);
1734 int config_parse_path_spec(const char *unit
,
1735 const char *filename
,
1737 const char *section
,
1738 unsigned section_line
,
1748 _cleanup_free_
char *k
= NULL
;
1756 if (isempty(rvalue
)) {
1757 /* Empty assignment clears list */
1762 b
= path_type_from_string(lvalue
);
1764 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse path type, ignoring: %s", lvalue
);
1768 r
= unit_full_printf(UNIT(p
), rvalue
, &k
);
1770 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
1774 if (!path_is_absolute(k
)) {
1775 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path is not absolute, ignoring: %s", k
);
1779 s
= new0(PathSpec
, 1);
1784 s
->path
= path_kill_slashes(k
);
1789 LIST_PREPEND(spec
, p
->specs
, s
);
1794 int config_parse_socket_service(
1796 const char *filename
,
1798 const char *section
,
1799 unsigned section_line
,
1806 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1807 _cleanup_free_
char *p
= NULL
;
1817 r
= unit_name_printf(UNIT(s
), rvalue
, &p
);
1819 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers: %s", rvalue
);
1823 if (!endswith(p
, ".service")) {
1824 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type service: %s", rvalue
);
1828 r
= manager_load_unit(UNIT(s
)->manager
, p
, NULL
, &error
, &x
);
1830 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load unit %s: %s", rvalue
, bus_error_message(&error
, r
));
1834 unit_ref_set(&s
->service
, UNIT(s
), x
);
1839 int config_parse_fdname(
1841 const char *filename
,
1843 const char *section
,
1844 unsigned section_line
,
1851 _cleanup_free_
char *p
= NULL
;
1860 if (isempty(rvalue
)) {
1861 s
->fdname
= mfree(s
->fdname
);
1865 r
= unit_full_printf(UNIT(s
), rvalue
, &p
);
1867 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
1871 if (!fdname_is_valid(p
)) {
1872 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid file descriptor name, ignoring: %s", p
);
1876 return free_and_replace(s
->fdname
, p
);
1879 int config_parse_service_sockets(
1881 const char *filename
,
1883 const char *section
,
1884 unsigned section_line
,
1902 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
1904 r
= extract_first_word(&p
, &word
, NULL
, 0);
1910 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Trailing garbage in sockets, ignoring: %s", rvalue
);
1914 r
= unit_name_printf(UNIT(s
), word
, &k
);
1916 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %m");
1920 if (!endswith(k
, ".socket")) {
1921 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Unit must be of type socket, ignoring: %s", k
);
1925 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1927 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1929 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1931 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add dependency on %s, ignoring: %m", k
);
1937 int config_parse_bus_name(
1939 const char *filename
,
1941 const char *section
,
1942 unsigned section_line
,
1949 _cleanup_free_
char *k
= NULL
;
1958 r
= unit_full_printf(u
, rvalue
, &k
);
1960 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue
);
1964 if (!service_name_is_valid(k
)) {
1965 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid bus name %s, ignoring.", k
);
1969 return config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, k
, data
, userdata
);
1972 int config_parse_service_timeout(
1974 const char *filename
,
1976 const char *section
,
1977 unsigned section_line
,
1984 Service
*s
= userdata
;
1993 /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
1995 r
= parse_sec(rvalue
, &usec
);
1997 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2001 /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
2002 * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
2003 * all other timeouts. */
2005 usec
= USEC_INFINITY
;
2007 if (!streq(lvalue
, "TimeoutStopSec")) {
2008 s
->start_timeout_defined
= true;
2009 s
->timeout_start_usec
= usec
;
2012 if (!streq(lvalue
, "TimeoutStartSec"))
2013 s
->timeout_stop_usec
= usec
;
2018 int config_parse_sec_fix_0(
2020 const char *filename
,
2022 const char *section
,
2023 unsigned section_line
,
2030 usec_t
*usec
= data
;
2038 /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
2039 * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
2042 r
= parse_sec_fix_0(rvalue
, usec
);
2044 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s= parameter, ignoring: %s", lvalue
, rvalue
);
2051 int config_parse_user_group(
2053 const char *filename
,
2055 const char *section
,
2056 unsigned section_line
,
2063 char **user
= data
, *n
;
2072 if (isempty(rvalue
))
2075 _cleanup_free_
char *k
= NULL
;
2077 r
= unit_full_printf(u
, rvalue
, &k
);
2079 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", rvalue
);
2083 if (!valid_user_group_name_or_id(k
)) {
2084 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2097 int config_parse_user_group_strv(
2099 const char *filename
,
2101 const char *section
,
2102 unsigned section_line
,
2109 char ***users
= data
;
2119 if (isempty(rvalue
)) {
2120 *users
= strv_free(*users
);
2126 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2128 r
= extract_first_word(&p
, &word
, NULL
, 0);
2134 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax: %s", rvalue
);
2138 r
= unit_full_printf(u
, word
, &k
);
2140 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers in %s: %m", word
);
2144 if (!valid_user_group_name_or_id(k
)) {
2145 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid user/group name or numeric ID: %s", k
);
2149 r
= strv_push(users
, k
);
2159 int config_parse_working_directory(
2161 const char *filename
,
2163 const char *section
,
2164 unsigned section_line
,
2171 ExecContext
*c
= data
;
2182 if (rvalue
[0] == '-') {
2188 if (streq(rvalue
, "~")) {
2189 c
->working_directory_home
= true;
2190 c
->working_directory
= mfree(c
->working_directory
);
2192 _cleanup_free_
char *k
= NULL
;
2194 r
= unit_full_printf(u
, rvalue
, &k
);
2196 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2197 "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
2198 rvalue
, missing_ok
? ", ignoring" : "");
2199 return missing_ok
? 0 : -ENOEXEC
;
2202 path_kill_slashes(k
);
2204 if (!utf8_is_valid(k
)) {
2205 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2206 return missing_ok
? 0 : -ENOEXEC
;
2209 if (!path_is_absolute(k
)) {
2210 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2211 "Working directory path '%s' is not absolute%s.",
2212 rvalue
, missing_ok
? ", ignoring" : "");
2213 return missing_ok
? 0 : -ENOEXEC
;
2216 c
->working_directory_home
= false;
2217 free_and_replace(c
->working_directory
, k
);
2220 c
->working_directory_missing_ok
= missing_ok
;
2224 int config_parse_unit_env_file(const char *unit
,
2225 const char *filename
,
2227 const char *section
,
2228 unsigned section_line
,
2237 _cleanup_free_
char *n
= NULL
;
2245 if (isempty(rvalue
)) {
2246 /* Empty assignment frees the list */
2247 *env
= strv_free(*env
);
2251 r
= unit_full_printf(u
, rvalue
, &n
);
2253 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2257 if (!path_is_absolute(n
[0] == '-' ? n
+ 1 : n
)) {
2258 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path '%s' is not absolute, ignoring.", n
);
2262 r
= strv_extend(env
, n
);
2269 int config_parse_environ(
2271 const char *filename
,
2273 const char *section
,
2274 unsigned section_line
,
2291 if (isempty(rvalue
)) {
2292 /* Empty assignment resets the list */
2293 *env
= strv_free(*env
);
2297 for (p
= rvalue
;; ) {
2298 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2300 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2306 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2307 "Invalid syntax, ignoring: %s", rvalue
);
2312 r
= unit_full_printf(u
, word
, &k
);
2314 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2315 "Failed to resolve specifiers, ignoring: %s", word
);
2321 if (!env_assignment_is_valid(k
)) {
2322 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2323 "Invalid environment assignment, ignoring: %s", k
);
2327 r
= strv_env_replace(env
, k
);
2335 int config_parse_pass_environ(
2337 const char *filename
,
2339 const char *section
,
2340 unsigned section_line
,
2347 const char *whole_rvalue
= rvalue
;
2348 _cleanup_strv_free_
char **n
= NULL
;
2349 size_t nlen
= 0, nbufsize
= 0;
2350 char*** passenv
= data
;
2359 if (isempty(rvalue
)) {
2360 /* Empty assignment resets the list */
2361 *passenv
= strv_free(*passenv
);
2366 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2368 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_QUOTES
);
2374 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2375 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2380 r
= unit_full_printf(u
, word
, &k
);
2382 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2383 "Failed to resolve specifiers, ignoring: %s", word
);
2389 if (!env_name_is_valid(k
)) {
2390 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2391 "Invalid environment name for %s, ignoring: %s", lvalue
, k
);
2395 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2398 n
[nlen
++] = TAKE_PTR(k
);
2403 r
= strv_extend_strv(passenv
, n
, true);
2411 int config_parse_unset_environ(
2413 const char *filename
,
2415 const char *section
,
2416 unsigned section_line
,
2423 _cleanup_strv_free_
char **n
= NULL
;
2424 const char *whole_rvalue
= rvalue
;
2425 size_t nlen
= 0, nbufsize
= 0;
2426 char*** unsetenv
= data
;
2435 if (isempty(rvalue
)) {
2436 /* Empty assignment resets the list */
2437 *unsetenv
= strv_free(*unsetenv
);
2442 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2444 r
= extract_first_word(&rvalue
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2450 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2451 "Trailing garbage in %s, ignoring: %s", lvalue
, whole_rvalue
);
2456 r
= unit_full_printf(u
, word
, &k
);
2458 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2459 "Failed to resolve specifiers, ignoring: %s", word
);
2465 if (!env_assignment_is_valid(k
) && !env_name_is_valid(k
)) {
2466 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
2467 "Invalid environment name or assignment %s, ignoring: %s", lvalue
, k
);
2471 if (!GREEDY_REALLOC(n
, nbufsize
, nlen
+ 2))
2474 n
[nlen
++] = TAKE_PTR(k
);
2479 r
= strv_extend_strv(unsetenv
, n
, true);
2487 int config_parse_log_extra_fields(
2489 const char *filename
,
2491 const char *section
,
2492 unsigned section_line
,
2499 ExecContext
*c
= data
;
2509 if (isempty(rvalue
)) {
2510 exec_context_free_log_extra_fields(c
);
2514 for (p
= rvalue
;; ) {
2515 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
2519 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_QUOTES
);
2525 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2529 r
= unit_full_printf(u
, word
, &k
);
2531 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s, ignoring field: %m", word
);
2535 eq
= strchr(k
, '=');
2537 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field lacks '=' character, ignoring field: %s", k
);
2541 if (!journal_field_valid(k
, eq
-k
, false)) {
2542 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Log field name is invalid, ignoring field: %s", k
);
2546 t
= reallocarray(c
->log_extra_fields
, c
->n_log_extra_fields
+1, sizeof(struct iovec
));
2550 c
->log_extra_fields
= t
;
2551 c
->log_extra_fields
[c
->n_log_extra_fields
++] = IOVEC_MAKE_STRING(k
);
2559 int config_parse_ip_tos(const char *unit
,
2560 const char *filename
,
2562 const char *section
,
2563 unsigned section_line
,
2570 int *ip_tos
= data
, x
;
2577 x
= ip_tos_from_string(rvalue
);
2579 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue
);
2587 int config_parse_unit_condition_path(
2589 const char *filename
,
2591 const char *section
,
2592 unsigned section_line
,
2599 _cleanup_free_
char *p
= NULL
;
2600 Condition
**list
= data
, *c
;
2601 ConditionType t
= ltype
;
2602 bool trigger
, negate
;
2611 if (isempty(rvalue
)) {
2612 /* Empty assignment resets the list */
2613 *list
= condition_free_list(*list
);
2617 trigger
= rvalue
[0] == '|';
2621 negate
= rvalue
[0] == '!';
2625 r
= unit_full_printf(u
, rvalue
, &p
);
2627 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2631 if (!path_is_absolute(p
)) {
2632 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Path in condition not absolute, ignoring: %s", p
);
2636 c
= condition_new(t
, p
, trigger
, negate
);
2640 LIST_PREPEND(conditions
, *list
, c
);
2644 int config_parse_unit_condition_string(
2646 const char *filename
,
2648 const char *section
,
2649 unsigned section_line
,
2656 _cleanup_free_
char *s
= NULL
;
2657 Condition
**list
= data
, *c
;
2658 ConditionType t
= ltype
;
2659 bool trigger
, negate
;
2668 if (isempty(rvalue
)) {
2669 /* Empty assignment resets the list */
2670 *list
= condition_free_list(*list
);
2674 trigger
= rvalue
[0] == '|';
2678 negate
= rvalue
[0] == '!';
2682 r
= unit_full_printf(u
, rvalue
, &s
);
2684 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers, ignoring: %s", rvalue
);
2688 c
= condition_new(t
, s
, trigger
, negate
);
2692 LIST_PREPEND(conditions
, *list
, c
);
2696 int config_parse_unit_condition_null(
2698 const char *filename
,
2700 const char *section
,
2701 unsigned section_line
,
2708 Condition
**list
= data
, *c
;
2709 bool trigger
, negate
;
2717 if (isempty(rvalue
)) {
2718 /* Empty assignment resets the list */
2719 *list
= condition_free_list(*list
);
2723 trigger
= rvalue
[0] == '|';
2727 negate
= rvalue
[0] == '!';
2731 b
= parse_boolean(rvalue
);
2733 log_syntax(unit
, LOG_ERR
, filename
, line
, b
, "Failed to parse boolean value in condition, ignoring: %s", rvalue
);
2740 c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
);
2744 LIST_PREPEND(conditions
, *list
, c
);
2748 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
2749 DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action
, emergency_action
, EmergencyAction
, "Failed to parse failure action specifier");
2751 int config_parse_unit_requires_mounts_for(
2753 const char *filename
,
2755 const char *section
,
2756 unsigned section_line
,
2772 for (p
= rvalue
;; ) {
2773 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
;
2775 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2781 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2782 "Invalid syntax, ignoring: %s", rvalue
);
2786 if (!utf8_is_valid(word
)) {
2787 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, rvalue
);
2791 r
= unit_full_printf(u
, word
, &resolved
);
2793 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit name \"%s\", ignoring: %m", word
);
2797 r
= unit_require_mounts_for(u
, resolved
, UNIT_DEPENDENCY_FILE
);
2799 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to add required mount \"%s\", ignoring: %m", resolved
);
2805 int config_parse_documentation(const char *unit
,
2806 const char *filename
,
2808 const char *section
,
2809 unsigned section_line
,
2825 if (isempty(rvalue
)) {
2826 /* Empty assignment resets the list */
2827 u
->documentation
= strv_free(u
->documentation
);
2831 r
= config_parse_unit_strv_printf(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2832 rvalue
, data
, userdata
);
2836 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2838 if (documentation_url_is_valid(*a
))
2841 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid URL, ignoring: %s", *a
);
2852 int config_parse_syscall_filter(
2854 const char *filename
,
2856 const char *section
,
2857 unsigned section_line
,
2864 ExecContext
*c
= data
;
2866 bool invert
= false;
2875 if (isempty(rvalue
)) {
2876 /* Empty assignment resets the list */
2877 c
->syscall_filter
= hashmap_free(c
->syscall_filter
);
2878 c
->syscall_whitelist
= false;
2882 if (rvalue
[0] == '~') {
2887 if (!c
->syscall_filter
) {
2888 c
->syscall_filter
= hashmap_new(NULL
);
2889 if (!c
->syscall_filter
)
2893 /* Allow everything but the ones listed */
2894 c
->syscall_whitelist
= false;
2896 /* Allow nothing but the ones listed */
2897 c
->syscall_whitelist
= true;
2899 /* Accept default syscalls if we are on a whitelist */
2900 r
= seccomp_parse_syscall_filter("@default", -1, c
->syscall_filter
, SECCOMP_PARSE_WHITELIST
);
2908 _cleanup_free_
char *word
= NULL
, *name
= NULL
;
2911 r
= extract_first_word(&p
, &word
, NULL
, 0);
2917 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
2921 r
= parse_syscall_and_errno(word
, &name
, &num
);
2923 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse syscall:errno, ignoring: %s", word
);
2927 r
= seccomp_parse_syscall_filter_full(name
, num
, c
->syscall_filter
,
2928 SECCOMP_PARSE_LOG
|SECCOMP_PARSE_PERMISSIVE
|(invert
? SECCOMP_PARSE_INVERT
: 0)|(c
->syscall_whitelist
? SECCOMP_PARSE_WHITELIST
: 0),
2929 unit
, filename
, line
);
2937 int config_parse_syscall_archs(
2939 const char *filename
,
2941 const char *section
,
2942 unsigned section_line
,
2953 if (isempty(rvalue
)) {
2954 *archs
= set_free(*archs
);
2958 r
= set_ensure_allocated(archs
, NULL
);
2962 for (p
= rvalue
;;) {
2963 _cleanup_free_
char *word
= NULL
;
2966 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
2972 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2973 "Invalid syntax, ignoring: %s", rvalue
);
2977 r
= seccomp_arch_from_string(word
, &a
);
2979 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
2980 "Failed to parse system call architecture \"%s\", ignoring: %m", word
);
2984 r
= set_put(*archs
, UINT32_TO_PTR(a
+ 1));
2990 int config_parse_syscall_errno(
2992 const char *filename
,
2994 const char *section
,
2995 unsigned section_line
,
3002 ExecContext
*c
= data
;
3009 if (isempty(rvalue
)) {
3010 /* Empty assignment resets to KILL */
3011 c
->syscall_errno
= 0;
3015 e
= parse_errno(rvalue
);
3017 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse error number, ignoring: %s", rvalue
);
3021 c
->syscall_errno
= e
;
3025 int config_parse_address_families(
3027 const char *filename
,
3029 const char *section
,
3030 unsigned section_line
,
3037 ExecContext
*c
= data
;
3038 bool invert
= false;
3046 if (isempty(rvalue
)) {
3047 /* Empty assignment resets the list */
3048 c
->address_families
= set_free(c
->address_families
);
3049 c
->address_families_whitelist
= false;
3053 if (rvalue
[0] == '~') {
3058 if (!c
->address_families
) {
3059 c
->address_families
= set_new(NULL
);
3060 if (!c
->address_families
)
3063 c
->address_families_whitelist
= !invert
;
3066 for (p
= rvalue
;;) {
3067 _cleanup_free_
char *word
= NULL
;
3070 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3076 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3077 "Invalid syntax, ignoring: %s", rvalue
);
3081 af
= af_from_name(word
);
3083 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3084 "Failed to parse address family \"%s\", ignoring: %m", word
);
3088 /* If we previously wanted to forbid an address family and now
3089 * we want to allow it, then just remove it from the list.
3091 if (!invert
== c
->address_families_whitelist
) {
3092 r
= set_put(c
->address_families
, INT_TO_PTR(af
));
3096 set_remove(c
->address_families
, INT_TO_PTR(af
));
3100 int config_parse_restrict_namespaces(
3102 const char *filename
,
3104 const char *section
,
3105 unsigned section_line
,
3112 ExecContext
*c
= data
;
3113 bool invert
= false;
3116 if (isempty(rvalue
)) {
3117 /* Reset to the default. */
3118 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3122 if (rvalue
[0] == '~') {
3127 r
= parse_boolean(rvalue
);
3129 c
->restrict_namespaces
= 0;
3131 c
->restrict_namespaces
= NAMESPACE_FLAGS_ALL
;
3133 /* Not a boolean argument, in this case it's a list of namespace types. */
3135 r
= namespace_flag_from_string_many(rvalue
, &c
->restrict_namespaces
);
3137 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse namespace type string, ignoring: %s", rvalue
);
3143 c
->restrict_namespaces
= (~c
->restrict_namespaces
) & NAMESPACE_FLAGS_ALL
;
3149 int config_parse_unit_slice(
3151 const char *filename
,
3153 const char *section
,
3154 unsigned section_line
,
3161 _cleanup_free_
char *k
= NULL
;
3162 Unit
*u
= userdata
, *slice
= NULL
;
3170 r
= unit_name_printf(u
, rvalue
, &k
);
3172 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue
);
3176 r
= manager_load_unit(u
->manager
, k
, NULL
, NULL
, &slice
);
3178 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to load slice unit %s. Ignoring.", k
);
3182 r
= unit_set_slice(u
, slice
);
3184 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to assign slice %s to unit %s. Ignoring.", slice
->id
, u
->id
);
3191 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy
, cgroup_device_policy
, CGroupDevicePolicy
, "Failed to parse device policy");
3193 int config_parse_cpu_weight(
3195 const char *filename
,
3197 const char *section
,
3198 unsigned section_line
,
3205 uint64_t *weight
= data
;
3212 r
= cg_weight_parse(rvalue
, weight
);
3214 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU weight '%s' invalid. Ignoring.", rvalue
);
3221 int config_parse_cpu_shares(
3223 const char *filename
,
3225 const char *section
,
3226 unsigned section_line
,
3233 uint64_t *shares
= data
;
3240 r
= cg_cpu_shares_parse(rvalue
, shares
);
3242 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU shares '%s' invalid. Ignoring.", rvalue
);
3249 int config_parse_cpu_quota(
3251 const char *filename
,
3253 const char *section
,
3254 unsigned section_line
,
3261 CGroupContext
*c
= data
;
3268 if (isempty(rvalue
)) {
3269 c
->cpu_quota_per_sec_usec
= USEC_INFINITY
;
3273 r
= parse_percent_unbounded(rvalue
);
3275 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "CPU quota '%s' invalid. Ignoring.", rvalue
);
3279 c
->cpu_quota_per_sec_usec
= ((usec_t
) r
* USEC_PER_SEC
) / 100U;
3283 int config_parse_memory_limit(
3285 const char *filename
,
3287 const char *section
,
3288 unsigned section_line
,
3295 CGroupContext
*c
= data
;
3296 uint64_t bytes
= CGROUP_LIMIT_MAX
;
3299 if (!isempty(rvalue
) && !streq(rvalue
, "infinity")) {
3301 r
= parse_percent(rvalue
);
3303 r
= parse_size(rvalue
, 1024, &bytes
);
3305 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Memory limit '%s' invalid. Ignoring.", rvalue
);
3309 bytes
= physical_memory_scale(r
, 100U);
3311 if (bytes
>= UINT64_MAX
||
3312 (bytes
<= 0 && !streq(lvalue
, "MemorySwapMax"))) {
3313 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Memory limit '%s' out of range. Ignoring.", rvalue
);
3318 if (streq(lvalue
, "MemoryLow"))
3319 c
->memory_low
= bytes
;
3320 else if (streq(lvalue
, "MemoryHigh"))
3321 c
->memory_high
= bytes
;
3322 else if (streq(lvalue
, "MemoryMax"))
3323 c
->memory_max
= bytes
;
3324 else if (streq(lvalue
, "MemorySwapMax"))
3325 c
->memory_swap_max
= bytes
;
3326 else if (streq(lvalue
, "MemoryLimit"))
3327 c
->memory_limit
= bytes
;
3334 int config_parse_tasks_max(
3336 const char *filename
,
3338 const char *section
,
3339 unsigned section_line
,
3346 uint64_t *tasks_max
= data
, v
;
3350 if (isempty(rvalue
)) {
3351 *tasks_max
= u
->manager
->default_tasks_max
;
3355 if (streq(rvalue
, "infinity")) {
3356 *tasks_max
= CGROUP_LIMIT_MAX
;
3360 r
= parse_percent(rvalue
);
3362 r
= safe_atou64(rvalue
, &v
);
3364 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Maximum tasks value '%s' invalid. Ignoring.", rvalue
);
3368 v
= system_tasks_max_scale(r
, 100U);
3370 if (v
<= 0 || v
>= UINT64_MAX
) {
3371 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue
);
3379 int config_parse_delegate(
3381 const char *filename
,
3383 const char *section
,
3384 unsigned section_line
,
3391 CGroupContext
*c
= data
;
3394 /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
3395 * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
3396 * mask to delegate. */
3398 if (isempty(rvalue
)) {
3400 c
->delegate_controllers
= 0;
3404 r
= parse_boolean(rvalue
);
3406 const char *p
= rvalue
;
3407 CGroupMask mask
= 0;
3410 _cleanup_free_
char *word
= NULL
;
3411 CGroupController cc
;
3413 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3419 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
3423 cc
= cgroup_controller_from_string(word
);
3425 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid controller name '%s', ignoring", rvalue
);
3429 mask
|= CGROUP_CONTROLLER_TO_MASK(cc
);
3433 c
->delegate_controllers
|= mask
;
3437 c
->delegate_controllers
= _CGROUP_MASK_ALL
;
3439 c
->delegate
= false;
3440 c
->delegate_controllers
= 0;
3446 int config_parse_device_allow(
3448 const char *filename
,
3450 const char *section
,
3451 unsigned section_line
,
3458 _cleanup_free_
char *path
= NULL
, *t
= NULL
;
3459 CGroupContext
*c
= data
;
3460 CGroupDeviceAllow
*a
;
3461 const char *m
= NULL
;
3465 if (isempty(rvalue
)) {
3466 while (c
->device_allow
)
3467 cgroup_context_free_device_allow(c
, c
->device_allow
);
3472 r
= unit_full_printf(userdata
, rvalue
, &t
);
3474 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3475 "Failed to resolve specifiers in %s, ignoring: %m",
3480 n
= strcspn(t
, WHITESPACE
);
3482 path
= strndup(t
, n
);
3486 if (!is_deviceallow_pattern(path
) &&
3487 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3488 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3492 m
= t
+ n
+ strspn(t
+ n
, WHITESPACE
);
3496 if (!in_charset(m
, "rwm")) {
3497 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device rights '%s'. Ignoring.", m
);
3501 a
= new0(CGroupDeviceAllow
, 1);
3505 a
->path
= TAKE_PTR(path
);
3506 a
->r
= !!strchr(m
, 'r');
3507 a
->w
= !!strchr(m
, 'w');
3508 a
->m
= !!strchr(m
, 'm');
3510 LIST_PREPEND(device_allow
, c
->device_allow
, a
);
3514 int config_parse_io_weight(
3516 const char *filename
,
3518 const char *section
,
3519 unsigned section_line
,
3526 uint64_t *weight
= data
;
3533 r
= cg_weight_parse(rvalue
, weight
);
3535 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", rvalue
);
3542 int config_parse_io_device_weight(
3544 const char *filename
,
3546 const char *section
,
3547 unsigned section_line
,
3554 _cleanup_free_
char *path
= NULL
;
3555 CGroupIODeviceWeight
*w
;
3556 CGroupContext
*c
= data
;
3566 if (isempty(rvalue
)) {
3567 while (c
->io_device_weights
)
3568 cgroup_context_free_io_device_weight(c
, c
->io_device_weights
);
3573 n
= strcspn(rvalue
, WHITESPACE
);
3574 weight
= rvalue
+ n
;
3575 weight
+= strspn(weight
, WHITESPACE
);
3577 if (isempty(weight
)) {
3578 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3582 path
= strndup(rvalue
, n
);
3586 if (!path_startswith(path
, "/dev") &&
3587 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3588 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3592 r
= cg_weight_parse(weight
, &u
);
3594 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO weight '%s' invalid. Ignoring.", weight
);
3598 assert(u
!= CGROUP_WEIGHT_INVALID
);
3600 w
= new0(CGroupIODeviceWeight
, 1);
3604 w
->path
= TAKE_PTR(path
);
3608 LIST_PREPEND(device_weights
, c
->io_device_weights
, w
);
3612 int config_parse_io_limit(
3614 const char *filename
,
3616 const char *section
,
3617 unsigned section_line
,
3624 _cleanup_free_
char *path
= NULL
;
3625 CGroupIODeviceLimit
*l
= NULL
, *t
;
3626 CGroupContext
*c
= data
;
3627 CGroupIOLimitType type
;
3637 type
= cgroup_io_limit_type_from_string(lvalue
);
3640 if (isempty(rvalue
)) {
3641 LIST_FOREACH(device_limits
, l
, c
->io_device_limits
)
3642 l
->limits
[type
] = cgroup_io_limit_defaults
[type
];
3646 n
= strcspn(rvalue
, WHITESPACE
);
3648 limit
+= strspn(limit
, WHITESPACE
);
3651 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3655 path
= strndup(rvalue
, n
);
3659 if (!path_startswith(path
, "/dev") &&
3660 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3661 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3665 if (streq("infinity", limit
)) {
3666 num
= CGROUP_LIMIT_MAX
;
3668 r
= parse_size(limit
, 1000, &num
);
3669 if (r
< 0 || num
<= 0) {
3670 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IO Limit '%s' invalid. Ignoring.", rvalue
);
3675 LIST_FOREACH(device_limits
, t
, c
->io_device_limits
) {
3676 if (path_equal(path
, t
->path
)) {
3683 CGroupIOLimitType ttype
;
3685 l
= new0(CGroupIODeviceLimit
, 1);
3689 l
->path
= TAKE_PTR(path
);
3690 for (ttype
= 0; ttype
< _CGROUP_IO_LIMIT_TYPE_MAX
; ttype
++)
3691 l
->limits
[ttype
] = cgroup_io_limit_defaults
[ttype
];
3693 LIST_PREPEND(device_limits
, c
->io_device_limits
, l
);
3696 l
->limits
[type
] = num
;
3701 int config_parse_blockio_weight(
3703 const char *filename
,
3705 const char *section
,
3706 unsigned section_line
,
3713 uint64_t *weight
= data
;
3720 r
= cg_blkio_weight_parse(rvalue
, weight
);
3722 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", rvalue
);
3729 int config_parse_blockio_device_weight(
3731 const char *filename
,
3733 const char *section
,
3734 unsigned section_line
,
3741 _cleanup_free_
char *path
= NULL
;
3742 CGroupBlockIODeviceWeight
*w
;
3743 CGroupContext
*c
= data
;
3753 if (isempty(rvalue
)) {
3754 while (c
->blockio_device_weights
)
3755 cgroup_context_free_blockio_device_weight(c
, c
->blockio_device_weights
);
3760 n
= strcspn(rvalue
, WHITESPACE
);
3761 weight
= rvalue
+ n
;
3762 weight
+= strspn(weight
, WHITESPACE
);
3764 if (isempty(weight
)) {
3765 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected block device and device weight. Ignoring.");
3769 path
= strndup(rvalue
, n
);
3773 if (!path_startswith(path
, "/dev") &&
3774 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3775 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3779 r
= cg_blkio_weight_parse(weight
, &u
);
3781 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO weight '%s' invalid. Ignoring.", weight
);
3785 assert(u
!= CGROUP_BLKIO_WEIGHT_INVALID
);
3787 w
= new0(CGroupBlockIODeviceWeight
, 1);
3791 w
->path
= TAKE_PTR(path
);
3795 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, w
);
3799 int config_parse_blockio_bandwidth(
3801 const char *filename
,
3803 const char *section
,
3804 unsigned section_line
,
3811 _cleanup_free_
char *path
= NULL
;
3812 CGroupBlockIODeviceBandwidth
*b
= NULL
, *t
;
3813 CGroupContext
*c
= data
;
3814 const char *bandwidth
;
3824 read
= streq("BlockIOReadBandwidth", lvalue
);
3826 if (isempty(rvalue
)) {
3827 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
3828 b
->rbps
= CGROUP_LIMIT_MAX
;
3829 b
->wbps
= CGROUP_LIMIT_MAX
;
3834 n
= strcspn(rvalue
, WHITESPACE
);
3835 bandwidth
= rvalue
+ n
;
3836 bandwidth
+= strspn(bandwidth
, WHITESPACE
);
3839 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
3843 path
= strndup(rvalue
, n
);
3847 if (!path_startswith(path
, "/dev") &&
3848 !path_startswith(path
, "/run/systemd/inaccessible/")) {
3849 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid device node path '%s'. Ignoring.", path
);
3853 r
= parse_size(bandwidth
, 1000, &bytes
);
3854 if (r
< 0 || bytes
<= 0) {
3855 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue
);
3859 LIST_FOREACH(device_bandwidths
, t
, c
->blockio_device_bandwidths
) {
3860 if (path_equal(path
, t
->path
)) {
3867 b
= new0(CGroupBlockIODeviceBandwidth
, 1);
3871 b
->path
= TAKE_PTR(path
);
3872 b
->rbps
= CGROUP_LIMIT_MAX
;
3873 b
->wbps
= CGROUP_LIMIT_MAX
;
3875 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, b
);
3886 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode
, job_mode
, JobMode
, "Failed to parse job mode");
3888 int config_parse_job_mode_isolate(
3890 const char *filename
,
3892 const char *section
,
3893 unsigned section_line
,
3907 r
= parse_boolean(rvalue
);
3909 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse boolean, ignoring: %s", rvalue
);
3913 log_notice("%s is deprecated. Please use OnFailureJobMode= instead", lvalue
);
3915 *m
= r
? JOB_ISOLATE
: JOB_REPLACE
;
3919 DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode
, exec_preserve_mode
, ExecPreserveMode
, "Failed to parse runtime directory preserve mode");
3921 int config_parse_exec_directories(
3923 const char *filename
,
3925 const char *section
,
3926 unsigned section_line
,
3943 if (isempty(rvalue
)) {
3944 /* Empty assignment resets the list */
3945 *rt
= strv_free(*rt
);
3949 for (p
= rvalue
;;) {
3950 _cleanup_free_
char *word
= NULL
, *k
= NULL
;
3952 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
);
3956 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3957 "Invalid syntax, ignoring: %s", rvalue
);
3963 r
= unit_full_printf(u
, word
, &k
);
3965 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
3966 "Failed to resolve specifiers in \"%s\", ignoring: %m", word
);
3970 if (!path_is_normalized(k
) || path_is_absolute(k
)) {
3971 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
3972 "%s= path is not valid, ignoring assignment: %s", lvalue
, rvalue
);
3976 r
= strv_push(rt
, k
);
3983 int config_parse_set_status(
3985 const char *filename
,
3987 const char *section
,
3988 unsigned section_line
,
3996 const char *word
, *state
;
3998 ExitStatusSet
*status_set
= data
;
4005 /* Empty assignment resets the list */
4006 if (isempty(rvalue
)) {
4007 exit_status_set_free(status_set
);
4011 FOREACH_WORD(word
, l
, rvalue
, state
) {
4012 _cleanup_free_
char *temp
;
4016 temp
= strndup(word
, l
);
4020 r
= safe_atoi(temp
, &val
);
4022 val
= signal_from_string_try_harder(temp
);
4025 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse value, ignoring: %s", word
);
4028 set
= &status_set
->signal
;
4030 if (val
< 0 || val
> 255) {
4031 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Value %d is outside range 0-255, ignoring", val
);
4034 set
= &status_set
->status
;
4037 r
= set_ensure_allocated(set
, NULL
);
4041 r
= set_put(*set
, INT_TO_PTR(val
));
4043 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Unable to store: %s", word
);
4047 if (!isempty(state
))
4048 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Trailing garbage, ignoring.");
4053 int config_parse_namespace_path_strv(
4055 const char *filename
,
4057 const char *section
,
4058 unsigned section_line
,
4075 if (isempty(rvalue
)) {
4076 /* Empty assignment resets the list */
4077 *sv
= strv_free(*sv
);
4083 _cleanup_free_
char *word
= NULL
, *resolved
= NULL
, *joined
= NULL
;
4085 bool ignore_enoent
= false, shall_prefix
= false;
4087 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
4093 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
4097 if (!utf8_is_valid(word
)) {
4098 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, word
);
4103 if (startswith(w
, "-")) {
4104 ignore_enoent
= true;
4107 if (startswith(w
, "+")) {
4108 shall_prefix
= true;
4112 r
= unit_full_printf(u
, w
, &resolved
);
4114 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s: %m", word
);
4118 if (!path_is_absolute(resolved
)) {
4119 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
4123 path_kill_slashes(resolved
);
4125 joined
= strjoin(ignore_enoent
? "-" : "",
4126 shall_prefix
? "+" : "",
4129 r
= strv_push(sv
, joined
);
4139 int config_parse_temporary_filesystems(
4141 const char *filename
,
4143 const char *section
,
4144 unsigned section_line
,
4152 ExecContext
*c
= data
;
4161 if (isempty(rvalue
)) {
4162 /* Empty assignment resets the list */
4163 temporary_filesystem_free_many(c
->temporary_filesystems
, c
->n_temporary_filesystems
);
4164 c
->temporary_filesystems
= NULL
;
4165 c
->n_temporary_filesystems
= 0;
4171 _cleanup_free_
char *word
= NULL
, *path
= NULL
, *resolved
= NULL
;
4174 r
= extract_first_word(&cur
, &word
, NULL
, EXTRACT_QUOTES
);
4180 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract first word, ignoring: %s", rvalue
);
4185 r
= extract_first_word(&w
, &path
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
4191 r
= unit_full_printf(u
, path
, &resolved
);
4193 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to resolve specifiers in %s, ignoring: %m", word
);
4197 if (!path_is_absolute(resolved
)) {
4198 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute path, ignoring: %s", resolved
);
4202 path_kill_slashes(resolved
);
4204 r
= temporary_filesystem_add(&c
->temporary_filesystems
, &c
->n_temporary_filesystems
, path
, w
);
4208 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse mount options, ignoring: %s", word
);
4216 int config_parse_bind_paths(
4218 const char *filename
,
4220 const char *section
,
4221 unsigned section_line
,
4228 ExecContext
*c
= data
;
4238 if (isempty(rvalue
)) {
4239 /* Empty assignment resets the list */
4240 bind_mount_free_many(c
->bind_mounts
, c
->n_bind_mounts
);
4241 c
->bind_mounts
= NULL
;
4242 c
->n_bind_mounts
= 0;
4248 _cleanup_free_
char *source
= NULL
, *destination
= NULL
;
4249 _cleanup_free_
char *sresolved
= NULL
, *dresolved
= NULL
;
4250 char *s
= NULL
, *d
= NULL
;
4251 bool rbind
= true, ignore_enoent
= false;
4253 r
= extract_first_word(&p
, &source
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4259 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4263 r
= unit_full_printf(u
, source
, &sresolved
);
4265 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4266 "Failed to resolved specifiers in \"%s\", ignoring: %m", source
);
4272 ignore_enoent
= true;
4276 if (!utf8_is_valid(s
)) {
4277 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, s
);
4280 if (!path_is_absolute(s
)) {
4281 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute source path, ignoring: %s", s
);
4285 path_kill_slashes(s
);
4287 /* Optionally, the destination is specified. */
4288 if (p
&& p
[-1] == ':') {
4289 r
= extract_first_word(&p
, &destination
, ":" WHITESPACE
, EXTRACT_QUOTES
|EXTRACT_DONT_COALESCE_SEPARATORS
);
4293 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4297 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Missing argument after ':': %s", rvalue
);
4301 r
= unit_full_printf(u
, destination
, &dresolved
);
4303 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
4304 "Failed to resolved specifiers in \"%s\", ignoring: %m", destination
);
4308 if (!utf8_is_valid(dresolved
)) {
4309 log_syntax_invalid_utf8(unit
, LOG_ERR
, filename
, line
, dresolved
);
4312 if (!path_is_absolute(dresolved
)) {
4313 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not an absolute destination path, ignoring: %s", dresolved
);
4317 d
= path_kill_slashes(dresolved
);
4319 /* Optionally, there's also a short option string specified */
4320 if (p
&& p
[-1] == ':') {
4321 _cleanup_free_
char *options
= NULL
;
4323 r
= extract_first_word(&p
, &options
, NULL
, EXTRACT_QUOTES
);
4327 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse %s: %s", lvalue
, rvalue
);
4331 if (isempty(options
) || streq(options
, "rbind"))
4333 else if (streq(options
, "norbind"))
4336 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid option string, ignoring setting: %s", options
);
4343 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
4347 .read_only
= !!strstr(lvalue
, "ReadOnly"),
4349 .ignore_enoent
= ignore_enoent
,
4358 int config_parse_no_new_privileges(
4360 const char *filename
,
4362 const char *section
,
4363 unsigned section_line
,
4370 ExecContext
*c
= data
;
4378 k
= parse_boolean(rvalue
);
4380 log_syntax(unit
, LOG_ERR
, filename
, line
, k
, "Failed to parse boolean value, ignoring: %s", rvalue
);
4384 c
->no_new_privileges
= k
;
4389 int config_parse_protect_home(
4391 const char *filename
,
4393 const char *section
,
4394 unsigned section_line
,
4401 ExecContext
*c
= data
;
4409 /* Our enum shall be a superset of booleans, hence first try
4410 * to parse as boolean, and then as enum */
4412 h
= parse_protect_home_or_bool(rvalue
);
4414 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect home value, ignoring: %s", rvalue
);
4418 c
->protect_home
= h
;
4423 int config_parse_protect_system(
4425 const char *filename
,
4427 const char *section
,
4428 unsigned section_line
,
4435 ExecContext
*c
= data
;
4443 /* Our enum shall be a superset of booleans, hence first try
4444 * to parse as boolean, and then as enum */
4446 s
= parse_protect_system_or_bool(rvalue
);
4448 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse protect system value, ignoring: %s", rvalue
);
4452 c
->protect_system
= s
;
4457 DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode
, exec_keyring_mode
, ExecKeyringMode
, "Failed to parse keyring mode");
4459 int config_parse_job_timeout_sec(
4461 const char *filename
,
4463 const char *section
,
4464 unsigned section_line
,
4480 r
= parse_sec_fix_0(rvalue
, &usec
);
4482 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue
);
4486 /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
4487 * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
4490 if (!u
->job_running_timeout_set
)
4491 u
->job_running_timeout
= usec
;
4493 u
->job_timeout
= usec
;
4498 int config_parse_job_running_timeout_sec(
4500 const char *filename
,
4502 const char *section
,
4503 unsigned section_line
,
4519 r
= parse_sec_fix_0(rvalue
, &usec
);
4521 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue
);
4525 u
->job_running_timeout
= usec
;
4526 u
->job_running_timeout_set
= true;
4531 #define FOLLOW_MAX 8
4533 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
4544 /* This will update the filename pointer if the loaded file is
4545 * reached by a symlink. The old string will be freed. */
4548 char *target
, *name
;
4550 if (c
++ >= FOLLOW_MAX
)
4553 path_kill_slashes(*filename
);
4555 /* Add the file name we are currently looking at to
4556 * the names of this unit, but only if it is a valid
4558 name
= basename(*filename
);
4559 if (unit_name_is_valid(name
, UNIT_NAME_ANY
)) {
4561 id
= set_get(names
, name
);
4567 r
= set_consume(names
, id
);
4573 /* Try to open the file name, but don't if its a symlink */
4574 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
4581 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
4582 r
= readlink_and_make_absolute(*filename
, &target
);
4590 f
= fdopen(fd
, "re");
4602 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
4610 /* Let's try to add in all symlink names we found */
4611 while ((k
= set_steal_first(names
))) {
4613 /* First try to merge in the other name into our
4615 r
= unit_merge_by_name(*u
, k
);
4619 /* Hmm, we couldn't merge the other unit into
4620 * ours? Then let's try it the other way
4623 /* If the symlink name we are looking at is unit template, then
4624 we must search for instance of this template */
4625 if (unit_name_is_valid(k
, UNIT_NAME_TEMPLATE
) && (*u
)->instance
) {
4626 _cleanup_free_
char *instance
= NULL
;
4628 r
= unit_name_replace_instance(k
, (*u
)->instance
, &instance
);
4632 other
= manager_get_unit((*u
)->manager
, instance
);
4634 other
= manager_get_unit((*u
)->manager
, k
);
4639 r
= unit_merge(other
, *u
);
4642 return merge_by_names(u
, names
, NULL
);
4650 unit_choose_id(*u
, id
);
4658 static int load_from_path(Unit
*u
, const char *path
) {
4659 _cleanup_set_free_free_ Set
*symlink_names
= NULL
;
4660 _cleanup_fclose_
FILE *f
= NULL
;
4661 _cleanup_free_
char *filename
= NULL
;
4670 symlink_names
= set_new(&string_hash_ops
);
4674 if (path_is_absolute(path
)) {
4676 filename
= strdup(path
);
4680 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4682 filename
= mfree(filename
);
4690 STRV_FOREACH(p
, u
->manager
->lookup_paths
.search_path
) {
4692 /* Instead of opening the path right away, we manually
4693 * follow all symlinks and add their name to our unit
4694 * name set while doing so */
4695 filename
= path_make_absolute(path
, *p
);
4699 if (u
->manager
->unit_path_cache
&&
4700 !set_get(u
->manager
->unit_path_cache
, filename
))
4703 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
4706 filename
= mfree(filename
);
4708 /* ENOENT means that the file is missing or is a dangling symlink.
4709 * ENOTDIR means that one of paths we expect to be is a directory
4710 * is not a directory, we should just ignore that.
4711 * EACCES means that the directory or file permissions are wrong.
4714 log_debug_errno(r
, "Cannot access \"%s\": %m", filename
);
4715 else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
))
4718 /* Empty the symlink names for the next run */
4719 set_clear_free(symlink_names
);
4724 /* Hmm, no suitable file found? */
4727 if (!unit_type_may_alias(u
->type
) && set_size(symlink_names
) > 1) {
4728 log_unit_warning(u
, "Unit type of %s does not support alias names, refusing loading via symlink.", u
->id
);
4733 r
= merge_by_names(&merged
, symlink_names
, id
);
4738 u
->load_state
= UNIT_MERGED
;
4742 if (fstat(fileno(f
), &st
) < 0)
4745 if (null_or_empty(&st
)) {
4746 u
->load_state
= UNIT_MASKED
;
4747 u
->fragment_mtime
= 0;
4749 u
->load_state
= UNIT_LOADED
;
4750 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
4752 /* Now, parse the file contents */
4753 r
= config_parse(u
->id
, filename
, f
,
4754 UNIT_VTABLE(u
)->sections
,
4755 config_item_perf_lookup
, load_fragment_gperf_lookup
,
4756 CONFIG_PARSE_ALLOW_INCLUDE
, u
);
4761 free_and_replace(u
->fragment_path
, filename
);
4763 if (u
->source_path
) {
4764 if (stat(u
->source_path
, &st
) >= 0)
4765 u
->source_mtime
= timespec_load(&st
.st_mtim
);
4767 u
->source_mtime
= 0;
4773 int unit_load_fragment(Unit
*u
) {
4779 assert(u
->load_state
== UNIT_STUB
);
4783 u
->load_state
= UNIT_LOADED
;
4787 /* First, try to find the unit under its id. We always look
4788 * for unit files in the default directories, to make it easy
4789 * to override things by placing things in /etc/systemd/system */
4790 r
= load_from_path(u
, u
->id
);
4794 /* Try to find an alias we can load this with */
4795 if (u
->load_state
== UNIT_STUB
) {
4796 SET_FOREACH(t
, u
->names
, i
) {
4801 r
= load_from_path(u
, t
);
4805 if (u
->load_state
!= UNIT_STUB
)
4810 /* And now, try looking for it under the suggested (originally linked) path */
4811 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
4813 r
= load_from_path(u
, u
->fragment_path
);
4817 if (u
->load_state
== UNIT_STUB
)
4818 /* Hmm, this didn't work? Then let's get rid
4819 * of the fragment path stored for us, so that
4820 * we don't point to an invalid location. */
4821 u
->fragment_path
= mfree(u
->fragment_path
);
4824 /* Look for a template */
4825 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
4826 _cleanup_free_
char *k
= NULL
;
4828 r
= unit_name_template(u
->id
, &k
);
4832 r
= load_from_path(u
, k
);
4835 log_unit_notice(u
, "Unit configuration has fatal error, unit will not be started.");
4839 if (u
->load_state
== UNIT_STUB
) {
4840 SET_FOREACH(t
, u
->names
, i
) {
4841 _cleanup_free_
char *z
= NULL
;
4846 r
= unit_name_template(t
, &z
);
4850 r
= load_from_path(u
, z
);
4854 if (u
->load_state
!= UNIT_STUB
)
4863 void unit_dump_config_items(FILE *f
) {
4864 static const struct {
4865 const ConfigParserCallback callback
;
4868 #if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
4869 { config_parse_warn_compat
, "NOTSUPPORTED" },
4871 { config_parse_int
, "INTEGER" },
4872 { config_parse_unsigned
, "UNSIGNED" },
4873 { config_parse_iec_size
, "SIZE" },
4874 { config_parse_iec_uint64
, "SIZE" },
4875 { config_parse_si_size
, "SIZE" },
4876 { config_parse_bool
, "BOOLEAN" },
4877 { config_parse_string
, "STRING" },
4878 { config_parse_path
, "PATH" },
4879 { config_parse_unit_path_printf
, "PATH" },
4880 { config_parse_strv
, "STRING [...]" },
4881 { config_parse_exec_nice
, "NICE" },
4882 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
4883 { config_parse_exec_io_class
, "IOCLASS" },
4884 { config_parse_exec_io_priority
, "IOPRIORITY" },
4885 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
4886 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
4887 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
4888 { config_parse_mode
, "MODE" },
4889 { config_parse_unit_env_file
, "FILE" },
4890 { config_parse_exec_output
, "OUTPUT" },
4891 { config_parse_exec_input
, "INPUT" },
4892 { config_parse_log_facility
, "FACILITY" },
4893 { config_parse_log_level
, "LEVEL" },
4894 { config_parse_exec_secure_bits
, "SECUREBITS" },
4895 { config_parse_capability_set
, "BOUNDINGSET" },
4896 { config_parse_limit
, "LIMIT" },
4897 { config_parse_unit_deps
, "UNIT [...]" },
4898 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
4899 { config_parse_service_type
, "SERVICETYPE" },
4900 { config_parse_service_restart
, "SERVICERESTART" },
4901 #if HAVE_SYSV_COMPAT
4902 { config_parse_sysv_priority
, "SYSVPRIORITY" },
4904 { config_parse_kill_mode
, "KILLMODE" },
4905 { config_parse_signal
, "SIGNAL" },
4906 { config_parse_socket_listen
, "SOCKET [...]" },
4907 { config_parse_socket_bind
, "SOCKETBIND" },
4908 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
4909 { config_parse_sec
, "SECONDS" },
4910 { config_parse_nsec
, "NANOSECONDS" },
4911 { config_parse_namespace_path_strv
, "PATH [...]" },
4912 { config_parse_bind_paths
, "PATH[:PATH[:OPTIONS]] [...]" },
4913 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
4914 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
4915 { config_parse_unit_string_printf
, "STRING" },
4916 { config_parse_trigger_unit
, "UNIT" },
4917 { config_parse_timer
, "TIMER" },
4918 { config_parse_path_spec
, "PATH" },
4919 { config_parse_notify_access
, "ACCESS" },
4920 { config_parse_ip_tos
, "TOS" },
4921 { config_parse_unit_condition_path
, "CONDITION" },
4922 { config_parse_unit_condition_string
, "CONDITION" },
4923 { config_parse_unit_condition_null
, "CONDITION" },
4924 { config_parse_unit_slice
, "SLICE" },
4925 { config_parse_documentation
, "URL" },
4926 { config_parse_service_timeout
, "SECONDS" },
4927 { config_parse_emergency_action
, "ACTION" },
4928 { config_parse_set_status
, "STATUS" },
4929 { config_parse_service_sockets
, "SOCKETS" },
4930 { config_parse_environ
, "ENVIRON" },
4932 { config_parse_syscall_filter
, "SYSCALLS" },
4933 { config_parse_syscall_archs
, "ARCHS" },
4934 { config_parse_syscall_errno
, "ERRNO" },
4935 { config_parse_address_families
, "FAMILIES" },
4936 { config_parse_restrict_namespaces
, "NAMESPACES" },
4938 { config_parse_cpu_shares
, "SHARES" },
4939 { config_parse_cpu_weight
, "WEIGHT" },
4940 { config_parse_memory_limit
, "LIMIT" },
4941 { config_parse_device_allow
, "DEVICE" },
4942 { config_parse_device_policy
, "POLICY" },
4943 { config_parse_io_limit
, "LIMIT" },
4944 { config_parse_io_weight
, "WEIGHT" },
4945 { config_parse_io_device_weight
, "DEVICEWEIGHT" },
4946 { config_parse_blockio_bandwidth
, "BANDWIDTH" },
4947 { config_parse_blockio_weight
, "WEIGHT" },
4948 { config_parse_blockio_device_weight
, "DEVICEWEIGHT" },
4949 { config_parse_long
, "LONG" },
4950 { config_parse_socket_service
, "SERVICE" },
4952 { config_parse_exec_selinux_context
, "LABEL" },
4954 { config_parse_job_mode
, "MODE" },
4955 { config_parse_job_mode_isolate
, "BOOLEAN" },
4956 { config_parse_personality
, "PERSONALITY" },
4959 const char *prev
= NULL
;
4964 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
4965 const char *rvalue
= "OTHER", *lvalue
;
4969 const ConfigPerfItem
*p
;
4971 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
4973 dot
= strchr(i
, '.');
4974 lvalue
= dot
? dot
+ 1 : i
;
4978 if (!prev
|| !strneq(prev
, i
, prefix_len
+1)) {
4982 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
4985 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
4986 if (p
->parse
== table
[j
].callback
) {
4987 rvalue
= table
[j
].rvalue
;
4991 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);