1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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/>.
22 #include <linux/oom.h>
29 #include <sys/prctl.h>
30 #include <sys/mount.h>
34 #include <sys/resource.h>
38 #include "conf-parser.h"
39 #include "load-fragment.h"
42 #include "securebits.h"
44 #include "unit-name.h"
45 #include "bus-errors.h"
47 #include "path-util.h"
48 #include "syscall-list.h"
50 #ifndef HAVE_SYSV_COMPAT
51 int config_parse_warn_compat(
61 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename
, line
, lvalue
);
66 int config_parse_unit_deps(
76 UnitDependency d
= ltype
;
86 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
94 k
= unit_name_printf(u
, t
);
99 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
101 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename
, line
, k
, strerror(-r
));
109 int config_parse_unit_string_printf(
110 const char *filename
,
128 k
= unit_full_printf(u
, rvalue
);
132 r
= config_parse_string(filename
, line
, section
, lvalue
, ltype
, k
, data
, userdata
);
138 int config_parse_unit_strv_printf(
139 const char *filename
,
157 k
= unit_full_printf(u
, rvalue
);
161 r
= config_parse_strv(filename
, line
, section
, lvalue
, ltype
, k
, data
, userdata
);
167 int config_parse_unit_path_printf(
168 const char *filename
,
186 k
= unit_full_printf(u
, rvalue
);
190 r
= config_parse_path(filename
, line
, section
, lvalue
, ltype
, k
, data
, userdata
);
196 int config_parse_socket_listen(
197 const char *filename
,
206 SocketPort
*p
, *tail
;
216 p
= new0(SocketPort
, 1);
220 if (streq(lvalue
, "ListenFIFO")) {
221 p
->type
= SOCKET_FIFO
;
223 if (!(p
->path
= unit_full_printf(UNIT(s
), rvalue
))) {
228 path_kill_slashes(p
->path
);
230 } else if (streq(lvalue
, "ListenSpecial")) {
231 p
->type
= SOCKET_SPECIAL
;
233 if (!(p
->path
= unit_full_printf(UNIT(s
), rvalue
))) {
238 path_kill_slashes(p
->path
);
240 } else if (streq(lvalue
, "ListenMessageQueue")) {
242 p
->type
= SOCKET_MQUEUE
;
244 if (!(p
->path
= unit_full_printf(UNIT(s
), rvalue
))) {
249 path_kill_slashes(p
->path
);
251 } else if (streq(lvalue
, "ListenNetlink")) {
255 p
->type
= SOCKET_SOCKET
;
256 k
= unit_full_printf(UNIT(s
), rvalue
);
257 r
= socket_address_parse_netlink(&p
->address
, k
);
261 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename
, line
, rvalue
);
270 p
->type
= SOCKET_SOCKET
;
271 k
= unit_full_printf(UNIT(s
), rvalue
);
272 r
= socket_address_parse(&p
->address
, k
);
276 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename
, line
, rvalue
);
281 if (streq(lvalue
, "ListenStream"))
282 p
->address
.type
= SOCK_STREAM
;
283 else if (streq(lvalue
, "ListenDatagram"))
284 p
->address
.type
= SOCK_DGRAM
;
286 assert(streq(lvalue
, "ListenSequentialPacket"));
287 p
->address
.type
= SOCK_SEQPACKET
;
290 if (socket_address_family(&p
->address
) != AF_LOCAL
&& p
->address
.type
== SOCK_SEQPACKET
) {
291 log_error("[%s:%u] Address family not supported, ignoring: %s", filename
, line
, rvalue
);
300 LIST_FIND_TAIL(SocketPort
, port
, s
->ports
, tail
);
301 LIST_INSERT_AFTER(SocketPort
, port
, s
->ports
, tail
, p
);
303 LIST_PREPEND(SocketPort
, port
, s
->ports
, p
);
308 int config_parse_socket_bind(
309 const char *filename
,
319 SocketAddressBindIPv6Only b
;
328 if ((b
= socket_address_bind_ipv6_only_from_string(rvalue
)) < 0) {
331 if ((r
= parse_boolean(rvalue
)) < 0) {
332 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename
, line
, rvalue
);
336 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
338 s
->bind_ipv6_only
= b
;
343 int config_parse_exec_nice(
344 const char *filename
,
353 ExecContext
*c
= data
;
361 if (safe_atoi(rvalue
, &priority
) < 0) {
362 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename
, line
, rvalue
);
366 if (priority
< PRIO_MIN
|| priority
>= PRIO_MAX
) {
367 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename
, line
, rvalue
);
377 int config_parse_exec_oom_score_adjust(
378 const char *filename
,
387 ExecContext
*c
= data
;
395 if (safe_atoi(rvalue
, &oa
) < 0) {
396 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename
, line
, rvalue
);
400 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
401 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename
, line
, rvalue
);
405 c
->oom_score_adjust
= oa
;
406 c
->oom_score_adjust_set
= true;
411 int config_parse_exec(
412 const char *filename
,
421 ExecCommand
**e
= data
, *nce
;
431 /* We accept an absolute path as first argument, or
432 * alternatively an absolute prefixed with @ to allow
433 * overriding of argv[0]. */
441 bool honour_argv0
= false, ignore
= false;
447 rvalue
+= strspn(rvalue
, WHITESPACE
);
452 if (rvalue
[0] == '-') {
457 if (rvalue
[0] == '@') {
462 if (*rvalue
!= '/') {
463 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename
, line
, rvalue
);
468 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
469 if (strncmp(w
, ";", MAX(l
, 1U)) == 0)
475 n
= new(char*, k
+ !honour_argv0
);
480 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
481 if (strncmp(w
, ";", MAX(l
, 1U)) == 0)
484 if (honour_argv0
&& w
== rvalue
) {
487 path
= strndup(w
, l
);
493 if (!utf8_is_valid(path
)) {
494 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename
, line
, rvalue
);
502 c
= n
[k
++] = cunescape_length(w
, l
);
508 if (!utf8_is_valid(c
)) {
509 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename
, line
, rvalue
);
519 log_error("[%s:%u] Invalid command line, ignoring: %s", filename
, line
, rvalue
);
532 assert(path_is_absolute(path
));
534 nce
= new0(ExecCommand
, 1);
542 nce
->ignore
= ignore
;
544 path_kill_slashes(nce
->path
);
546 exec_command_append_list(e
, nce
);
562 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
563 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
565 int config_parse_socket_bindtodevice(
566 const char *filename
,
583 if (rvalue
[0] && !streq(rvalue
, "*")) {
584 if (!(n
= strdup(rvalue
)))
589 free(s
->bind_to_device
);
590 s
->bind_to_device
= n
;
595 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
596 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
598 int config_parse_exec_io_class(
599 const char *filename
,
608 ExecContext
*c
= data
;
616 if ((x
= ioprio_class_from_string(rvalue
)) < 0) {
617 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename
, line
, rvalue
);
621 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
622 c
->ioprio_set
= true;
627 int config_parse_exec_io_priority(
628 const char *filename
,
637 ExecContext
*c
= data
;
645 if (safe_atoi(rvalue
, &i
) < 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
646 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename
, line
, rvalue
);
650 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
651 c
->ioprio_set
= true;
656 int config_parse_exec_cpu_sched_policy(
657 const char *filename
,
667 ExecContext
*c
= data
;
675 if ((x
= sched_policy_from_string(rvalue
)) < 0) {
676 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename
, line
, rvalue
);
680 c
->cpu_sched_policy
= x
;
681 c
->cpu_sched_set
= true;
686 int config_parse_exec_cpu_sched_prio(
687 const char *filename
,
696 ExecContext
*c
= data
;
704 /* On Linux RR/FIFO have the same range */
705 if (safe_atoi(rvalue
, &i
) < 0 || i
< sched_get_priority_min(SCHED_RR
) || i
> sched_get_priority_max(SCHED_RR
)) {
706 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename
, line
, rvalue
);
710 c
->cpu_sched_priority
= i
;
711 c
->cpu_sched_set
= true;
716 int config_parse_exec_cpu_affinity(
717 const char *filename
,
726 ExecContext
*c
= data
;
736 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
741 if (!(t
= strndup(w
, l
)))
744 r
= safe_atou(t
, &cpu
);
748 if (!(c
->cpuset
= cpu_set_malloc(&c
->cpuset_ncpus
)))
751 if (r
< 0 || cpu
>= c
->cpuset_ncpus
) {
752 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename
, line
, rvalue
);
756 CPU_SET_S(cpu
, CPU_ALLOC_SIZE(c
->cpuset_ncpus
), c
->cpuset
);
762 int config_parse_exec_capabilities(
763 const char *filename
,
772 ExecContext
*c
= data
;
780 if (!(cap
= cap_from_text(rvalue
))) {
784 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename
, line
, rvalue
);
789 cap_free(c
->capabilities
);
790 c
->capabilities
= cap
;
795 int config_parse_exec_secure_bits(
796 const char *filename
,
805 ExecContext
*c
= data
;
815 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
816 if (first_word(w
, "keep-caps"))
817 c
->secure_bits
|= SECURE_KEEP_CAPS
;
818 else if (first_word(w
, "keep-caps-locked"))
819 c
->secure_bits
|= SECURE_KEEP_CAPS_LOCKED
;
820 else if (first_word(w
, "no-setuid-fixup"))
821 c
->secure_bits
|= SECURE_NO_SETUID_FIXUP
;
822 else if (first_word(w
, "no-setuid-fixup-locked"))
823 c
->secure_bits
|= SECURE_NO_SETUID_FIXUP_LOCKED
;
824 else if (first_word(w
, "noroot"))
825 c
->secure_bits
|= SECURE_NOROOT
;
826 else if (first_word(w
, "noroot-locked"))
827 c
->secure_bits
|= SECURE_NOROOT_LOCKED
;
829 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename
, line
, rvalue
);
837 int config_parse_bounding_set(
838 const char *filename
,
847 uint64_t *capability_bounding_set_drop
= data
;
859 if (rvalue
[0] == '~') {
864 /* Note that we store this inverted internally, since the
865 * kernel wants it like this. But we actually expose it
866 * non-inverted everywhere to have a fully normalized
869 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
878 r
= cap_from_name(t
, &cap
);
882 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename
, line
, rvalue
);
886 sum
|= ((uint64_t) 1ULL) << (uint64_t) cap
;
890 *capability_bounding_set_drop
|= sum
;
892 *capability_bounding_set_drop
|= ~sum
;
897 int config_parse_limit(
898 const char *filename
,
907 struct rlimit
**rl
= data
;
908 unsigned long long u
;
917 if (streq(rvalue
, "infinity"))
918 u
= (unsigned long long) RLIM_INFINITY
;
919 else if (safe_atollu(rvalue
, &u
) < 0) {
920 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename
, line
, rvalue
);
925 if (!(*rl
= new(struct rlimit
, 1)))
928 (*rl
)->rlim_cur
= (*rl
)->rlim_max
= (rlim_t
) u
;
932 int config_parse_unit_cgroup(
933 const char *filename
,
947 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
955 k
= unit_full_printf(u
, t
);
967 r
= unit_add_cgroup_from_text(u
, t
);
971 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename
, line
, rvalue
);
979 #ifdef HAVE_SYSV_COMPAT
980 int config_parse_sysv_priority(
981 const char *filename
,
990 int *priority
= data
;
998 if (safe_atoi(rvalue
, &i
) < 0 || i
< 0) {
999 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename
, line
, rvalue
);
1003 *priority
= (int) i
;
1008 int config_parse_fsck_passno(
1009 const char *filename
,
1011 const char *section
,
1026 if (safe_atoi(rvalue
, &i
) || i
< 0) {
1027 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename
, line
, rvalue
);
1035 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1037 int config_parse_kill_signal(
1038 const char *filename
,
1040 const char *section
,
1055 if ((r
= signal_from_string_try_harder(rvalue
)) <= 0) {
1056 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename
, line
, rvalue
);
1064 int config_parse_exec_mount_flags(
1065 const char *filename
,
1067 const char *section
,
1074 ExecContext
*c
= data
;
1078 unsigned long flags
= 0;
1085 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
1086 if (strncmp(w
, "shared", MAX(l
, 6U)) == 0)
1088 else if (strncmp(w
, "slave", MAX(l
, 5U)) == 0)
1090 else if (strncmp(w
, "private", MAX(l
, 7U)) == 0)
1091 flags
|= MS_PRIVATE
;
1093 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename
, line
, rvalue
);
1098 c
->mount_flags
= flags
;
1102 int config_parse_timer(
1103 const char *filename
,
1105 const char *section
,
1122 if ((b
= timer_base_from_string(lvalue
)) < 0) {
1123 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename
, line
, lvalue
);
1127 if (parse_usec(rvalue
, &u
) < 0) {
1128 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename
, line
, rvalue
);
1132 if (!(v
= new0(TimerValue
, 1)))
1138 LIST_PREPEND(TimerValue
, value
, t
->values
, v
);
1143 int config_parse_timer_unit(
1144 const char *filename
,
1146 const char *section
,
1163 dbus_error_init(&error
);
1165 if (endswith(rvalue
, ".timer")) {
1166 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename
, line
, rvalue
);
1170 r
= manager_load_unit(UNIT(t
)->manager
, rvalue
, NULL
, NULL
, &u
);
1172 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename
, line
, rvalue
, bus_error(&error
, r
));
1173 dbus_error_free(&error
);
1177 unit_ref_set(&t
->unit
, u
);
1182 int config_parse_path_spec(
1183 const char *filename
,
1185 const char *section
,
1201 if ((b
= path_type_from_string(lvalue
)) < 0) {
1202 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename
, line
, lvalue
);
1206 if (!path_is_absolute(rvalue
)) {
1207 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename
, line
, rvalue
);
1211 if (!(s
= new0(PathSpec
, 1)))
1214 if (!(s
->path
= strdup(rvalue
))) {
1219 path_kill_slashes(s
->path
);
1224 LIST_PREPEND(PathSpec
, spec
, p
->specs
, s
);
1229 int config_parse_path_unit(
1230 const char *filename
,
1232 const char *section
,
1249 dbus_error_init(&error
);
1251 if (endswith(rvalue
, ".path")) {
1252 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename
, line
, rvalue
);
1256 if ((r
= manager_load_unit(UNIT(t
)->manager
, rvalue
, NULL
, &error
, &u
)) < 0) {
1257 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename
, line
, rvalue
, bus_error(&error
, r
));
1258 dbus_error_free(&error
);
1262 unit_ref_set(&t
->unit
, u
);
1267 int config_parse_socket_service(
1268 const char *filename
,
1270 const char *section
,
1287 dbus_error_init(&error
);
1289 if (!endswith(rvalue
, ".service")) {
1290 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename
, line
, rvalue
);
1294 r
= manager_load_unit(UNIT(s
)->manager
, rvalue
, NULL
, &error
, &x
);
1296 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename
, line
, rvalue
, bus_error(&error
, r
));
1297 dbus_error_free(&error
);
1301 unit_ref_set(&s
->service
, x
);
1306 int config_parse_service_sockets(
1307 const char *filename
,
1309 const char *section
,
1326 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
1333 k
= unit_name_printf(UNIT(s
), t
);
1339 if (!endswith(k
, ".socket")) {
1340 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename
, line
, rvalue
);
1345 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1347 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename
, line
, k
, strerror(-r
));
1349 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1359 int config_parse_service_timeout(
1360 const char *filename
,
1362 const char *section
,
1369 Service
*s
= userdata
;
1377 r
= config_parse_usec(filename
, line
, section
, lvalue
, ltype
, rvalue
, data
, userdata
);
1382 if (streq(lvalue
, "TimeoutSec")) {
1383 s
->start_timeout_defined
= true;
1384 s
->timeout_stop_usec
= s
->timeout_start_usec
;
1385 } else if (streq(lvalue
, "TimeoutStartSec"))
1386 s
->start_timeout_defined
= true;
1391 int config_parse_unit_env_file(
1392 const char *filename
,
1394 const char *section
,
1401 char ***env
= data
, **k
;
1410 s
= unit_full_printf(u
, rvalue
);
1414 if (!path_is_absolute(s
[0] == '-' ? s
+ 1 : s
)) {
1415 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename
, line
, s
);
1420 k
= strv_append(*env
, s
);
1431 int config_parse_ip_tos(
1432 const char *filename
,
1434 const char *section
,
1441 int *ip_tos
= data
, x
;
1448 if ((x
= ip_tos_from_string(rvalue
)) < 0)
1449 if (safe_atoi(rvalue
, &x
) < 0) {
1450 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename
, line
, rvalue
);
1458 int config_parse_unit_condition_path(
1459 const char *filename
,
1461 const char *section
,
1468 ConditionType cond
= ltype
;
1470 bool trigger
, negate
;
1478 trigger
= rvalue
[0] == '|';
1482 negate
= rvalue
[0] == '!';
1486 if (!path_is_absolute(rvalue
)) {
1487 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename
, line
, rvalue
);
1491 c
= condition_new(cond
, rvalue
, trigger
, negate
);
1495 LIST_PREPEND(Condition
, conditions
, u
->conditions
, c
);
1499 int config_parse_unit_condition_string(
1500 const char *filename
,
1502 const char *section
,
1509 ConditionType cond
= ltype
;
1511 bool trigger
, negate
;
1519 if ((trigger
= rvalue
[0] == '|'))
1522 if ((negate
= rvalue
[0] == '!'))
1525 if (!(c
= condition_new(cond
, rvalue
, trigger
, negate
)))
1528 LIST_PREPEND(Condition
, conditions
, u
->conditions
, c
);
1532 int config_parse_unit_condition_null(
1533 const char *filename
,
1535 const char *section
,
1544 bool trigger
, negate
;
1552 if ((trigger
= rvalue
[0] == '|'))
1555 if ((negate
= rvalue
[0] == '!'))
1558 if ((b
= parse_boolean(rvalue
)) < 0) {
1559 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename
, line
, rvalue
);
1566 if (!(c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
)))
1569 LIST_PREPEND(Condition
, conditions
, u
->conditions
, c
);
1573 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
1574 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action
, start_limit_action
, StartLimitAction
, "Failed to parse start limit action specifier");
1576 int config_parse_unit_cgroup_attr(
1577 const char *filename
,
1579 const char *section
,
1595 l
= strv_split_quoted(rvalue
);
1599 if (strv_length(l
) != 2) {
1600 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1605 r
= unit_add_cgroup_attribute(u
, NULL
, l
[0], l
[1], NULL
);
1609 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1616 int config_parse_unit_cpu_shares(const char *filename
, unsigned line
, const char *section
, const char *lvalue
, int ltype
, const char *rvalue
, void *data
, void *userdata
) {
1627 if (safe_atolu(rvalue
, &ul
) < 0 || ul
< 1) {
1628 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename
, line
, rvalue
);
1632 if (asprintf(&t
, "%lu", ul
) < 0)
1635 r
= unit_add_cgroup_attribute(u
, "cpu", "cpu.shares", t
, NULL
);
1639 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1646 int config_parse_unit_memory_limit(const char *filename
, unsigned line
, const char *section
, const char *lvalue
, int ltype
, const char *rvalue
, void *data
, void *userdata
) {
1657 if (parse_bytes(rvalue
, &sz
) < 0 || sz
<= 0) {
1658 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename
, line
, rvalue
);
1662 if (asprintf(&t
, "%llu", (unsigned long long) sz
) < 0)
1665 r
= unit_add_cgroup_attribute(u
,
1667 streq(lvalue
, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1672 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1679 static int device_map(const char *controller
, const char *name
, const char *value
, char **ret
) {
1687 l
= strv_split_quoted(value
);
1691 assert(strv_length(l
) >= 1);
1693 if (streq(l
[0], "*")) {
1695 if (asprintf(ret
, "a *:*%s%s",
1696 isempty(l
[1]) ? "" : " ", strempty(l
[1])) < 0) {
1704 if (stat(l
[0], &st
) < 0) {
1705 log_warning("Couldn't stat device %s", l
[0]);
1710 if (!S_ISCHR(st
.st_mode
) && !S_ISBLK(st
.st_mode
)) {
1711 log_warning("%s is not a device.", l
[0]);
1716 if (asprintf(ret
, "%c %u:%u%s%s",
1717 S_ISCHR(st
.st_mode
) ? 'c' : 'b',
1718 major(st
.st_rdev
), minor(st
.st_rdev
),
1719 isempty(l
[1]) ? "" : " ", strempty(l
[1])) < 0) {
1730 int config_parse_unit_device_allow(const char *filename
, unsigned line
, const char *section
, const char *lvalue
, int ltype
, const char *rvalue
, void *data
, void *userdata
) {
1741 l
= strv_split_quoted(rvalue
);
1746 if (k
< 1 || k
> 2) {
1747 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename
, line
, rvalue
);
1752 if (!streq(l
[0], "*") && !path_startswith(l
[0], "/dev")) {
1753 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename
, line
, rvalue
);
1758 if (!isempty(l
[1]) && !in_charset(l
[1], "rwm")) {
1759 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename
, line
, rvalue
);
1765 r
= unit_add_cgroup_attribute(u
, "devices",
1766 streq(lvalue
, "DeviceAllow") ? "devices.allow" : "devices.deny",
1767 rvalue
, device_map
);
1770 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1777 static int blkio_map(const char *controller
, const char *name
, const char *value
, char **ret
) {
1787 l
= strv_split_quoted(value
);
1791 assert(strv_length(l
) == 2);
1793 if (stat(l
[0], &st
) < 0) {
1794 log_warning("Couldn't stat device %s", l
[0]);
1799 if (S_ISBLK(st
.st_mode
))
1801 else if (major(st
.st_dev
) != 0) {
1802 /* If this is not a device node then find the block
1803 * device this file is stored on */
1806 /* If this is a partition, try to get the originating
1808 block_get_whole_disk(d
, &d
);
1810 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l
[0]);
1815 if (asprintf(ret
, "%u:%u %s", major(d
), minor(d
), l
[1]) < 0) {
1824 int config_parse_unit_blkio_weight(const char *filename
, unsigned line
, const char *section
, const char *lvalue
, int ltype
, const char *rvalue
, void *data
, void *userdata
) {
1828 const char *device
= NULL
, *weight
;
1837 l
= strv_split_quoted(rvalue
);
1842 if (k
< 1 || k
> 2) {
1843 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename
, line
, rvalue
);
1855 if (device
&& !path_is_absolute(device
)) {
1856 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename
, line
, rvalue
);
1861 if (safe_atolu(weight
, &ul
) < 0 || ul
< 10 || ul
> 1000) {
1862 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename
, line
, rvalue
);
1868 r
= asprintf(&t
, "%s %lu", device
, ul
);
1870 r
= asprintf(&t
, "%lu", ul
);
1877 r
= unit_add_cgroup_attribute(u
, "blkio", "blkio.weight_device", t
, blkio_map
);
1879 r
= unit_add_cgroup_attribute(u
, "blkio", "blkio.weight", t
, NULL
);
1883 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1890 int config_parse_unit_blkio_bandwidth(const char *filename
, unsigned line
, const char *section
, const char *lvalue
, int ltype
, const char *rvalue
, void *data
, void *userdata
) {
1902 l
= strv_split_quoted(rvalue
);
1908 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename
, line
, rvalue
);
1913 if (!path_is_absolute(l
[0])) {
1914 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename
, line
, rvalue
);
1919 if (parse_bytes(l
[1], &bytes
) < 0 || bytes
<= 0) {
1920 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename
, line
, rvalue
);
1925 r
= asprintf(&t
, "%s %llu", l
[0], (unsigned long long) bytes
);
1931 r
= unit_add_cgroup_attribute(u
, "blkio",
1932 streq(lvalue
, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1937 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1944 int config_parse_unit_requires_mounts_for(
1945 const char *filename
,
1947 const char *section
,
1963 empty_before
= !u
->requires_mounts_for
;
1965 r
= config_parse_path_strv(filename
, line
, section
, lvalue
, ltype
, rvalue
, data
, userdata
);
1967 /* Make it easy to find units with requires_mounts set */
1968 if (empty_before
&& u
->requires_mounts_for
)
1969 LIST_PREPEND(Unit
, has_requires_mounts_for
, u
->manager
->has_requires_mounts_for
, u
);
1974 int config_parse_documentation(
1975 const char *filename
,
1977 const char *section
,
1993 r
= config_parse_unit_strv_printf(filename
, line
, section
, lvalue
, ltype
, rvalue
, data
, userdata
);
1997 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
1999 if (is_valid_documentation_url(*a
))
2002 log_error("[%s:%u] Invalid URL, ignoring: %s", filename
, line
, *a
);
2011 static void syscall_set(uint32_t *p
, int nr
) {
2012 p
[nr
>> 4] |= 1 << (nr
& 31);
2015 static void syscall_unset(uint32_t *p
, int nr
) {
2016 p
[nr
>> 4] &= ~(1 << (nr
& 31));
2019 int config_parse_syscall_filter(
2020 const char *filename
,
2022 const char *section
,
2029 ExecContext
*c
= data
;
2041 if (rvalue
[0] == '~') {
2046 if (!c
->syscall_filter
) {
2049 n
= (syscall_max() + 31) >> 4;
2050 c
->syscall_filter
= new(uint32_t, n
);
2051 if (!c
->syscall_filter
)
2054 memset(c
->syscall_filter
, invert
? 0xFF : 0, n
* sizeof(uint32_t));
2056 /* Add these by default */
2057 syscall_set(c
->syscall_filter
, __NR_execve
);
2058 syscall_set(c
->syscall_filter
, __NR_rt_sigreturn
);
2059 #ifdef __NR_sigreturn
2060 syscall_set(c
->syscall_filter
, __NR_sigreturn
);
2062 syscall_set(c
->syscall_filter
, __NR_exit_group
);
2063 syscall_set(c
->syscall_filter
, __NR_exit
);
2066 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
2074 id
= syscall_from_name(t
);
2078 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename
, line
, rvalue
);
2083 syscall_unset(c
->syscall_filter
, id
);
2085 syscall_set(c
->syscall_filter
, id
);
2088 c
->no_new_privileges
= true;
2093 #define FOLLOW_MAX 8
2095 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
2106 /* This will update the filename pointer if the loaded file is
2107 * reached by a symlink. The old string will be freed. */
2110 char *target
, *name
;
2112 if (c
++ >= FOLLOW_MAX
)
2115 path_kill_slashes(*filename
);
2117 /* Add the file name we are currently looking at to
2118 * the names of this unit, but only if it is a valid
2120 name
= path_get_file_name(*filename
);
2122 if (unit_name_is_valid(name
, true)) {
2124 id
= set_get(names
, name
);
2130 r
= set_put(names
, id
);
2138 /* Try to open the file name, but don't if its a symlink */
2139 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
2146 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2147 r
= readlink_and_make_absolute(*filename
, &target
);
2155 f
= fdopen(fd
, "re");
2158 close_nointr_nofail(fd
);
2167 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
2175 /* Let's try to add in all symlink names we found */
2176 while ((k
= set_steal_first(names
))) {
2178 /* First try to merge in the other name into our
2180 r
= unit_merge_by_name(*u
, k
);
2184 /* Hmm, we couldn't merge the other unit into
2185 * ours? Then let's try it the other way
2188 other
= manager_get_unit((*u
)->manager
, k
);
2192 r
= unit_merge(other
, *u
);
2195 return merge_by_names(u
, names
, NULL
);
2203 unit_choose_id(*u
, id
);
2211 static int load_from_path(Unit
*u
, const char *path
) {
2215 char *filename
= NULL
, *id
= NULL
;
2222 symlink_names
= set_new(string_hash_func
, string_compare_func
);
2226 if (path_is_absolute(path
)) {
2228 filename
= strdup(path
);
2234 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
2246 STRV_FOREACH(p
, u
->manager
->lookup_paths
.unit_path
) {
2248 /* Instead of opening the path right away, we manually
2249 * follow all symlinks and add their name to our unit
2250 * name set while doing so */
2251 filename
= path_make_absolute(path
, *p
);
2257 if (u
->manager
->unit_path_cache
&&
2258 !set_get(u
->manager
->unit_path_cache
, filename
))
2261 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
2270 /* Empty the symlink names for the next run */
2271 set_clear_free(symlink_names
);
2280 /* Hmm, no suitable file found? */
2286 r
= merge_by_names(&merged
, symlink_names
, id
);
2291 u
->load_state
= UNIT_MERGED
;
2296 if (fstat(fileno(f
), &st
) < 0) {
2301 if (null_or_empty(&st
))
2302 u
->load_state
= UNIT_MASKED
;
2304 /* Now, parse the file contents */
2305 r
= config_parse(filename
, f
, UNIT_VTABLE(u
)->sections
, config_item_perf_lookup
, (void*) load_fragment_gperf_lookup
, false, u
);
2309 u
->load_state
= UNIT_LOADED
;
2312 free(u
->fragment_path
);
2313 u
->fragment_path
= filename
;
2316 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
2318 if (u
->source_path
) {
2319 if (stat(u
->source_path
, &st
) >= 0)
2320 u
->source_mtime
= timespec_load(&st
.st_mtim
);
2322 u
->source_mtime
= 0;
2328 set_free_free(symlink_names
);
2337 int unit_load_fragment(Unit
*u
) {
2343 assert(u
->load_state
== UNIT_STUB
);
2346 /* First, try to find the unit under its id. We always look
2347 * for unit files in the default directories, to make it easy
2348 * to override things by placing things in /etc/systemd/system */
2349 r
= load_from_path(u
, u
->id
);
2353 /* Try to find an alias we can load this with */
2354 if (u
->load_state
== UNIT_STUB
)
2355 SET_FOREACH(t
, u
->names
, i
) {
2360 r
= load_from_path(u
, t
);
2364 if (u
->load_state
!= UNIT_STUB
)
2368 /* And now, try looking for it under the suggested (originally linked) path */
2369 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
2371 r
= load_from_path(u
, u
->fragment_path
);
2375 if (u
->load_state
== UNIT_STUB
) {
2376 /* Hmm, this didn't work? Then let's get rid
2377 * of the fragment path stored for us, so that
2378 * we don't point to an invalid location. */
2379 free(u
->fragment_path
);
2380 u
->fragment_path
= NULL
;
2384 /* Look for a template */
2385 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
2388 k
= unit_name_template(u
->id
);
2392 r
= load_from_path(u
, k
);
2398 if (u
->load_state
== UNIT_STUB
)
2399 SET_FOREACH(t
, u
->names
, i
) {
2404 k
= unit_name_template(t
);
2408 r
= load_from_path(u
, k
);
2414 if (u
->load_state
!= UNIT_STUB
)
2422 void unit_dump_config_items(FILE *f
) {
2423 static const struct {
2424 const ConfigParserCallback callback
;
2427 { config_parse_int
, "INTEGER" },
2428 { config_parse_unsigned
, "UNSIGNED" },
2429 { config_parse_bytes_size
, "SIZE" },
2430 { config_parse_bool
, "BOOLEAN" },
2431 { config_parse_string
, "STRING" },
2432 { config_parse_path
, "PATH" },
2433 { config_parse_unit_path_printf
, "PATH" },
2434 { config_parse_strv
, "STRING [...]" },
2435 { config_parse_exec_nice
, "NICE" },
2436 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
2437 { config_parse_exec_io_class
, "IOCLASS" },
2438 { config_parse_exec_io_priority
, "IOPRIORITY" },
2439 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
2440 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
2441 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
2442 { config_parse_mode
, "MODE" },
2443 { config_parse_unit_env_file
, "FILE" },
2444 { config_parse_output
, "OUTPUT" },
2445 { config_parse_input
, "INPUT" },
2446 { config_parse_facility
, "FACILITY" },
2447 { config_parse_level
, "LEVEL" },
2448 { config_parse_exec_capabilities
, "CAPABILITIES" },
2449 { config_parse_exec_secure_bits
, "SECUREBITS" },
2450 { config_parse_bounding_set
, "BOUNDINGSET" },
2451 { config_parse_limit
, "LIMIT" },
2452 { config_parse_unit_cgroup
, "CGROUP [...]" },
2453 { config_parse_unit_deps
, "UNIT [...]" },
2454 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
2455 { config_parse_service_type
, "SERVICETYPE" },
2456 { config_parse_service_restart
, "SERVICERESTART" },
2457 #ifdef HAVE_SYSV_COMPAT
2458 { config_parse_sysv_priority
, "SYSVPRIORITY" },
2460 { config_parse_warn_compat
, "NOTSUPPORTED" },
2462 { config_parse_kill_mode
, "KILLMODE" },
2463 { config_parse_kill_signal
, "SIGNAL" },
2464 { config_parse_socket_listen
, "SOCKET [...]" },
2465 { config_parse_socket_bind
, "SOCKETBIND" },
2466 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
2467 { config_parse_usec
, "SECONDS" },
2468 { config_parse_nsec
, "NANOSECONDS" },
2469 { config_parse_path_strv
, "PATH [...]" },
2470 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
2471 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
2472 { config_parse_unit_string_printf
, "STRING" },
2473 { config_parse_timer
, "TIMER" },
2474 { config_parse_timer_unit
, "NAME" },
2475 { config_parse_path_spec
, "PATH" },
2476 { config_parse_path_unit
, "UNIT" },
2477 { config_parse_notify_access
, "ACCESS" },
2478 { config_parse_ip_tos
, "TOS" },
2479 { config_parse_unit_condition_path
, "CONDITION" },
2480 { config_parse_unit_condition_string
, "CONDITION" },
2481 { config_parse_unit_condition_null
, "CONDITION" },
2484 const char *prev
= NULL
;
2489 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
2490 const char *rvalue
= "OTHER", *lvalue
;
2494 const ConfigPerfItem
*p
;
2496 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
2498 dot
= strchr(i
, '.');
2499 lvalue
= dot
? dot
+ 1 : i
;
2503 if (!prev
|| strncmp(prev
, i
, prefix_len
+1) != 0) {
2507 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
2510 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
2511 if (p
->parse
== table
[j
].callback
) {
2512 rvalue
= table
[j
].rvalue
;
2516 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);