1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2012 Holger Hans Peter Freyther
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/oom.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
35 #include <sys/resource.h>
39 #include "conf-parser.h"
40 #include "load-fragment.h"
43 #include "securebits.h"
45 #include "unit-name.h"
46 #include "unit-printf.h"
47 #include "bus-errors.h"
49 #include "path-util.h"
50 #include "syscall-list.h"
52 #ifndef HAVE_SYSV_COMPAT
53 int config_parse_warn_compat(
63 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename
, line
, lvalue
);
68 int config_parse_unit_deps(
78 UnitDependency d
= ltype
;
88 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
89 char _cleanup_free_
*t
= NULL
, *k
= NULL
;
96 k
= unit_name_printf(u
, t
);
100 r
= unit_add_dependency_by_name(u
, d
, k
, NULL
, true);
102 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
103 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 b
= socket_address_bind_ipv6_only_from_string(rvalue
);
332 r
= parse_boolean(rvalue
);
334 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename
, line
, rvalue
);
338 s
->bind_ipv6_only
= r
? SOCKET_ADDRESS_IPV6_ONLY
: SOCKET_ADDRESS_BOTH
;
340 s
->bind_ipv6_only
= b
;
345 int config_parse_exec_nice(
346 const char *filename
,
355 ExecContext
*c
= data
;
363 if (safe_atoi(rvalue
, &priority
) < 0) {
364 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename
, line
, rvalue
);
368 if (priority
< PRIO_MIN
|| priority
>= PRIO_MAX
) {
369 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename
, line
, rvalue
);
379 int config_parse_exec_oom_score_adjust(
380 const char *filename
,
389 ExecContext
*c
= data
;
397 if (safe_atoi(rvalue
, &oa
) < 0) {
398 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename
, line
, rvalue
);
402 if (oa
< OOM_SCORE_ADJ_MIN
|| oa
> OOM_SCORE_ADJ_MAX
) {
403 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename
, line
, rvalue
);
407 c
->oom_score_adjust
= oa
;
408 c
->oom_score_adjust_set
= true;
413 int config_parse_exec(
414 const char *filename
,
423 ExecCommand
**e
= data
, *nce
;
433 /* We accept an absolute path as first argument, or
434 * alternatively an absolute prefixed with @ to allow
435 * overriding of argv[0]. */
444 bool honour_argv0
= false, ignore
= false;
450 rvalue
+= strspn(rvalue
, WHITESPACE
);
455 for (i
= 0; i
< 2; i
++) {
456 if (rvalue
[0] == '-' && !ignore
) {
461 if (rvalue
[0] == '@' && !honour_argv0
) {
467 if (*rvalue
!= '/') {
468 log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
469 filename
, line
, rvalue
);
474 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
475 if (strncmp(w
, ";", MAX(l
, 1U)) == 0)
481 n
= new(char*, k
+ !honour_argv0
);
486 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
487 if (strncmp(w
, ";", MAX(l
, 1U)) == 0)
489 else if (strncmp(w
, "\\;", MAX(l
, 1U)) == 0)
492 if (honour_argv0
&& w
== rvalue
) {
495 path
= strndup(w
, l
);
501 if (!utf8_is_valid(path
)) {
502 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename
, line
, rvalue
);
510 c
= n
[k
++] = cunescape_length(w
, l
);
516 if (!utf8_is_valid(c
)) {
517 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename
, line
, rvalue
);
527 log_error("[%s:%u] Invalid command line, ignoring: %s", filename
, line
, rvalue
);
540 assert(path_is_absolute(path
));
542 nce
= new0(ExecCommand
, 1);
550 nce
->ignore
= ignore
;
552 path_kill_slashes(nce
->path
);
554 exec_command_append_list(e
, nce
);
570 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type
, service_type
, ServiceType
, "Failed to parse service type");
571 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart
, service_restart
, ServiceRestart
, "Failed to parse service restart specifier");
573 int config_parse_socket_bindtodevice(
574 const char *filename
,
591 if (rvalue
[0] && !streq(rvalue
, "*")) {
592 if (!(n
= strdup(rvalue
)))
597 free(s
->bind_to_device
);
598 s
->bind_to_device
= n
;
603 DEFINE_CONFIG_PARSE_ENUM(config_parse_output
, exec_output
, ExecOutput
, "Failed to parse output specifier");
604 DEFINE_CONFIG_PARSE_ENUM(config_parse_input
, exec_input
, ExecInput
, "Failed to parse input specifier");
606 int config_parse_exec_io_class(
607 const char *filename
,
616 ExecContext
*c
= data
;
624 x
= ioprio_class_from_string(rvalue
);
626 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename
, line
, rvalue
);
630 c
->ioprio
= IOPRIO_PRIO_VALUE(x
, IOPRIO_PRIO_DATA(c
->ioprio
));
631 c
->ioprio_set
= true;
636 int config_parse_exec_io_priority(
637 const char *filename
,
646 ExecContext
*c
= data
;
654 if (safe_atoi(rvalue
, &i
) < 0 || i
< 0 || i
>= IOPRIO_BE_NR
) {
655 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename
, line
, rvalue
);
659 c
->ioprio
= IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c
->ioprio
), i
);
660 c
->ioprio_set
= true;
665 int config_parse_exec_cpu_sched_policy(
666 const char *filename
,
676 ExecContext
*c
= data
;
684 x
= sched_policy_from_string(rvalue
);
686 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename
, line
, rvalue
);
690 c
->cpu_sched_policy
= x
;
691 /* Moving to or from real-time policy? We need to adjust the priority */
692 c
->cpu_sched_priority
= CLAMP(c
->cpu_sched_priority
, sched_get_priority_min(x
), sched_get_priority_max(x
));
693 c
->cpu_sched_set
= true;
698 int config_parse_exec_cpu_sched_prio(
699 const char *filename
,
708 ExecContext
*c
= data
;
716 if (safe_atoi(rvalue
, &i
) < 0) {
717 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename
, line
, rvalue
);
722 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
723 min
= sched_get_priority_min(c
->cpu_sched_policy
);
724 max
= sched_get_priority_max(c
->cpu_sched_policy
);
726 if (i
< min
|| i
> max
) {
727 log_error("[%s:%u] CPU scheduling priority is out of range, ignoring: %s", filename
, line
, rvalue
);
731 c
->cpu_sched_priority
= i
;
732 c
->cpu_sched_set
= true;
737 int config_parse_exec_cpu_affinity(
738 const char *filename
,
747 ExecContext
*c
= data
;
757 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
758 char _cleanup_free_
*t
= NULL
;
766 r
= safe_atou(t
, &cpu
);
769 c
->cpuset
= cpu_set_malloc(&c
->cpuset_ncpus
);
774 if (r
< 0 || cpu
>= c
->cpuset_ncpus
) {
775 log_error("[%s:%u] Failed to parse CPU affinity %s, ignoring: %s",
776 filename
, line
, t
, rvalue
);
780 CPU_SET_S(cpu
, CPU_ALLOC_SIZE(c
->cpuset_ncpus
), c
->cpuset
);
786 int config_parse_exec_capabilities(
787 const char *filename
,
796 ExecContext
*c
= data
;
804 if (!(cap
= cap_from_text(rvalue
))) {
808 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename
, line
, rvalue
);
813 cap_free(c
->capabilities
);
814 c
->capabilities
= cap
;
819 int config_parse_exec_secure_bits(
820 const char *filename
,
829 ExecContext
*c
= data
;
839 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
840 if (first_word(w
, "keep-caps"))
841 c
->secure_bits
|= SECURE_KEEP_CAPS
;
842 else if (first_word(w
, "keep-caps-locked"))
843 c
->secure_bits
|= SECURE_KEEP_CAPS_LOCKED
;
844 else if (first_word(w
, "no-setuid-fixup"))
845 c
->secure_bits
|= SECURE_NO_SETUID_FIXUP
;
846 else if (first_word(w
, "no-setuid-fixup-locked"))
847 c
->secure_bits
|= SECURE_NO_SETUID_FIXUP_LOCKED
;
848 else if (first_word(w
, "noroot"))
849 c
->secure_bits
|= SECURE_NOROOT
;
850 else if (first_word(w
, "noroot-locked"))
851 c
->secure_bits
|= SECURE_NOROOT_LOCKED
;
853 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s",
854 filename
, line
, rvalue
);
862 int config_parse_bounding_set(
863 const char *filename
,
872 uint64_t *capability_bounding_set_drop
= data
;
884 if (rvalue
[0] == '~') {
889 /* Note that we store this inverted internally, since the
890 * kernel wants it like this. But we actually expose it
891 * non-inverted everywhere to have a fully normalized
894 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
895 char _cleanup_free_
*t
= NULL
;
903 r
= cap_from_name(t
, &cap
);
905 log_error("[%s:%u] Failed to parse capability in bounding set, ignoring: %s",
910 sum
|= ((uint64_t) 1ULL) << (uint64_t) cap
;
914 *capability_bounding_set_drop
|= sum
;
916 *capability_bounding_set_drop
|= ~sum
;
921 int config_parse_limit(
922 const char *filename
,
931 struct rlimit
**rl
= data
;
932 unsigned long long u
;
941 if (streq(rvalue
, "infinity"))
942 u
= (unsigned long long) RLIM_INFINITY
;
943 else if (safe_atollu(rvalue
, &u
) < 0) {
944 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename
, line
, rvalue
);
949 if (!(*rl
= new(struct rlimit
, 1)))
952 (*rl
)->rlim_cur
= (*rl
)->rlim_max
= (rlim_t
) u
;
956 int config_parse_unit_cgroup(
957 const char *filename
,
971 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
972 char _cleanup_free_
*t
= NULL
, *k
= NULL
, *ku
= NULL
;
979 k
= unit_full_printf(u
, t
);
987 r
= unit_add_cgroup_from_text(u
, ku
, true, NULL
);
989 log_error("[%s:%u] Failed to parse cgroup value %s, ignoring: %s",
990 filename
, line
, k
, rvalue
);
998 #ifdef HAVE_SYSV_COMPAT
999 int config_parse_sysv_priority(
1000 const char *filename
,
1002 const char *section
,
1009 int *priority
= data
;
1017 if (safe_atoi(rvalue
, &i
) < 0 || i
< 0) {
1018 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename
, line
, rvalue
);
1022 *priority
= (int) i
;
1027 int config_parse_fsck_passno(
1028 const char *filename
,
1030 const char *section
,
1045 if (safe_atoi(rvalue
, &i
) || i
< 0) {
1046 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename
, line
, rvalue
);
1054 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode
, kill_mode
, KillMode
, "Failed to parse kill mode");
1056 int config_parse_kill_signal(
1057 const char *filename
,
1059 const char *section
,
1074 if ((r
= signal_from_string_try_harder(rvalue
)) <= 0) {
1075 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename
, line
, rvalue
);
1083 int config_parse_exec_mount_flags(
1084 const char *filename
,
1086 const char *section
,
1093 ExecContext
*c
= data
;
1097 unsigned long flags
= 0;
1104 FOREACH_WORD_SEPARATOR(w
, l
, rvalue
, ", ", state
) {
1105 char _cleanup_free_
*t
;
1111 if (streq(t
, "shared"))
1113 else if (streq(t
, "slave"))
1115 else if (streq(w
, "private"))
1116 flags
|= MS_PRIVATE
;
1118 log_error("[%s:%u] Failed to parse mount flag %s, ignoring: %s",
1119 filename
, line
, t
, rvalue
);
1124 c
->mount_flags
= flags
;
1128 int config_parse_timer(
1129 const char *filename
,
1131 const char *section
,
1142 CalendarSpec
*c
= NULL
;
1150 b
= timer_base_from_string(lvalue
);
1152 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename
, line
, lvalue
);
1156 if (b
== TIMER_CALENDAR
) {
1157 if (calendar_spec_from_string(rvalue
, &c
) < 0) {
1158 log_error("[%s:%u] Failed to parse calendar specification, ignoring: %s", filename
, line
, rvalue
);
1162 id
= CLOCK_REALTIME
;
1164 if (parse_usec(rvalue
, &u
) < 0) {
1165 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename
, line
, rvalue
);
1169 id
= CLOCK_MONOTONIC
;
1172 v
= new0(TimerValue
, 1);
1179 v
->calendar_spec
= c
;
1181 LIST_PREPEND(TimerValue
, value
, t
->values
, v
);
1186 int config_parse_timer_unit(
1187 const char *filename
,
1189 const char *section
,
1206 dbus_error_init(&error
);
1208 if (endswith(rvalue
, ".timer")) {
1209 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename
, line
, rvalue
);
1213 r
= manager_load_unit(UNIT(t
)->manager
, rvalue
, NULL
, NULL
, &u
);
1215 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename
, line
, rvalue
, bus_error(&error
, r
));
1216 dbus_error_free(&error
);
1220 unit_ref_set(&t
->unit
, u
);
1225 int config_parse_path_spec(
1226 const char *filename
,
1228 const char *section
,
1245 b
= path_type_from_string(lvalue
);
1247 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename
, line
, lvalue
);
1251 k
= unit_full_printf(UNIT(p
), rvalue
);
1255 if (!path_is_absolute(k
)) {
1256 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename
, line
, k
);
1261 s
= new0(PathSpec
, 1);
1267 s
->path
= path_kill_slashes(k
);
1271 LIST_PREPEND(PathSpec
, spec
, p
->specs
, s
);
1276 int config_parse_path_unit(
1277 const char *filename
,
1279 const char *section
,
1290 _cleanup_free_
char *p
= NULL
;
1297 dbus_error_init(&error
);
1299 p
= unit_name_printf(u
, rvalue
);
1303 if (endswith(p
, ".path")) {
1304 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename
, line
, p
);
1308 r
= manager_load_unit(UNIT(t
)->manager
, p
, NULL
, &error
, &u
);
1310 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename
, line
, p
, bus_error(&error
, r
));
1311 dbus_error_free(&error
);
1315 unit_ref_set(&t
->unit
, u
);
1320 int config_parse_socket_service(
1321 const char *filename
,
1323 const char *section
,
1340 dbus_error_init(&error
);
1342 if (!endswith(rvalue
, ".service")) {
1343 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename
, line
, rvalue
);
1347 r
= manager_load_unit(UNIT(s
)->manager
, rvalue
, NULL
, &error
, &x
);
1349 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename
, line
, rvalue
, bus_error(&error
, r
));
1350 dbus_error_free(&error
);
1354 unit_ref_set(&s
->service
, x
);
1359 int config_parse_service_sockets(
1360 const char *filename
,
1362 const char *section
,
1379 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
1380 char _cleanup_free_
*t
= NULL
, *k
= NULL
;
1386 k
= unit_name_printf(UNIT(s
), t
);
1390 if (!endswith(k
, ".socket")) {
1391 log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1396 r
= unit_add_two_dependencies_by_name(UNIT(s
), UNIT_WANTS
, UNIT_AFTER
, k
, NULL
, true);
1398 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1399 filename
, line
, k
, strerror(-r
));
1401 r
= unit_add_dependency_by_name(UNIT(s
), UNIT_TRIGGERED_BY
, k
, NULL
, true);
1409 int config_parse_service_timeout(
1410 const char *filename
,
1412 const char *section
,
1419 Service
*s
= userdata
;
1427 r
= config_parse_usec(filename
, line
, section
, lvalue
, ltype
, rvalue
, data
, userdata
);
1432 if (streq(lvalue
, "TimeoutSec")) {
1433 s
->start_timeout_defined
= true;
1434 s
->timeout_stop_usec
= s
->timeout_start_usec
;
1435 } else if (streq(lvalue
, "TimeoutStartSec"))
1436 s
->start_timeout_defined
= true;
1441 int config_parse_unit_env_file(
1442 const char *filename
,
1444 const char *section
,
1451 char ***env
= data
, **k
;
1460 s
= unit_full_printf(u
, rvalue
);
1464 if (!path_is_absolute(s
[0] == '-' ? s
+ 1 : s
)) {
1465 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename
, line
, s
);
1470 k
= strv_append(*env
, s
);
1481 int config_parse_ip_tos(
1482 const char *filename
,
1484 const char *section
,
1491 int *ip_tos
= data
, x
;
1498 x
= ip_tos_from_string(rvalue
);
1500 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename
, line
, rvalue
);
1508 int config_parse_unit_condition_path(
1509 const char *filename
,
1511 const char *section
,
1518 ConditionType cond
= ltype
;
1520 bool trigger
, negate
;
1522 _cleanup_free_
char *p
= NULL
;
1529 trigger
= rvalue
[0] == '|';
1533 negate
= rvalue
[0] == '!';
1537 p
= unit_full_printf(u
, rvalue
);
1541 if (!path_is_absolute(p
)) {
1542 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename
, line
, p
);
1546 c
= condition_new(cond
, p
, trigger
, negate
);
1550 LIST_PREPEND(Condition
, conditions
, u
->conditions
, c
);
1554 int config_parse_unit_condition_string(
1555 const char *filename
,
1557 const char *section
,
1564 ConditionType cond
= ltype
;
1566 bool trigger
, negate
;
1568 _cleanup_free_
char *s
= NULL
;
1575 trigger
= rvalue
[0] == '|';
1579 negate
= rvalue
[0] == '!';
1583 s
= unit_full_printf(u
, rvalue
);
1587 c
= condition_new(cond
, s
, trigger
, negate
);
1591 LIST_PREPEND(Condition
, conditions
, u
->conditions
, c
);
1595 int config_parse_unit_condition_null(
1596 const char *filename
,
1598 const char *section
,
1607 bool trigger
, negate
;
1615 if ((trigger
= rvalue
[0] == '|'))
1618 if ((negate
= rvalue
[0] == '!'))
1621 if ((b
= parse_boolean(rvalue
)) < 0) {
1622 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename
, line
, rvalue
);
1629 if (!(c
= condition_new(CONDITION_NULL
, NULL
, trigger
, negate
)))
1632 LIST_PREPEND(Condition
, conditions
, u
->conditions
, c
);
1636 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access
, notify_access
, NotifyAccess
, "Failed to parse notify access specifier");
1637 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action
, start_limit_action
, StartLimitAction
, "Failed to parse start limit action specifier");
1639 int config_parse_unit_cgroup_attr(
1640 const char *filename
,
1642 const char *section
,
1658 l
= strv_split_quoted(rvalue
);
1662 if (strv_length(l
) != 2) {
1663 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1668 r
= unit_add_cgroup_attribute(u
, NULL
, l
[0], l
[1], NULL
, NULL
);
1672 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1679 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
) {
1690 if (safe_atolu(rvalue
, &ul
) < 0 || ul
< 1) {
1691 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename
, line
, rvalue
);
1695 if (asprintf(&t
, "%lu", ul
) < 0)
1698 r
= unit_add_cgroup_attribute(u
, "cpu", "cpu.shares", t
, NULL
, NULL
);
1702 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1709 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
) {
1720 if (parse_bytes(rvalue
, &sz
) < 0 || sz
<= 0) {
1721 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename
, line
, rvalue
);
1725 if (asprintf(&t
, "%llu", (unsigned long long) sz
) < 0)
1728 r
= unit_add_cgroup_attribute(u
,
1730 streq(lvalue
, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1735 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1742 static int device_map(const char *controller
, const char *name
, const char *value
, char **ret
) {
1750 l
= strv_split_quoted(value
);
1754 assert(strv_length(l
) >= 1);
1756 if (streq(l
[0], "*")) {
1758 if (asprintf(ret
, "a *:*%s%s",
1759 isempty(l
[1]) ? "" : " ", strempty(l
[1])) < 0) {
1767 if (stat(l
[0], &st
) < 0) {
1768 log_warning("Couldn't stat device %s", l
[0]);
1773 if (!S_ISCHR(st
.st_mode
) && !S_ISBLK(st
.st_mode
)) {
1774 log_warning("%s is not a device.", l
[0]);
1779 if (asprintf(ret
, "%c %u:%u%s%s",
1780 S_ISCHR(st
.st_mode
) ? 'c' : 'b',
1781 major(st
.st_rdev
), minor(st
.st_rdev
),
1782 isempty(l
[1]) ? "" : " ", strempty(l
[1])) < 0) {
1793 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
) {
1804 l
= strv_split_quoted(rvalue
);
1809 if (k
< 1 || k
> 2) {
1810 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename
, line
, rvalue
);
1815 if (!streq(l
[0], "*") && !path_startswith(l
[0], "/dev")) {
1816 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename
, line
, rvalue
);
1821 if (!isempty(l
[1]) && !in_charset(l
[1], "rwm")) {
1822 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename
, line
, rvalue
);
1828 r
= unit_add_cgroup_attribute(u
, "devices",
1829 streq(lvalue
, "DeviceAllow") ? "devices.allow" : "devices.deny",
1830 rvalue
, device_map
, NULL
);
1833 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1840 static int blkio_map(const char *controller
, const char *name
, const char *value
, char **ret
) {
1850 l
= strv_split_quoted(value
);
1854 assert(strv_length(l
) == 2);
1856 if (stat(l
[0], &st
) < 0) {
1857 log_warning("Couldn't stat device %s", l
[0]);
1862 if (S_ISBLK(st
.st_mode
))
1864 else if (major(st
.st_dev
) != 0) {
1865 /* If this is not a device node then find the block
1866 * device this file is stored on */
1869 /* If this is a partition, try to get the originating
1871 block_get_whole_disk(d
, &d
);
1873 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l
[0]);
1878 if (asprintf(ret
, "%u:%u %s", major(d
), minor(d
), l
[1]) < 0) {
1887 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
) {
1891 const char *device
= NULL
, *weight
;
1900 l
= strv_split_quoted(rvalue
);
1905 if (k
< 1 || k
> 2) {
1906 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename
, line
, rvalue
);
1918 if (device
&& !path_is_absolute(device
)) {
1919 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename
, line
, rvalue
);
1924 if (safe_atolu(weight
, &ul
) < 0 || ul
< 10 || ul
> 1000) {
1925 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename
, line
, rvalue
);
1931 r
= asprintf(&t
, "%s %lu", device
, ul
);
1933 r
= asprintf(&t
, "%lu", ul
);
1940 r
= unit_add_cgroup_attribute(u
, "blkio", "blkio.weight_device", t
, blkio_map
, NULL
);
1942 r
= unit_add_cgroup_attribute(u
, "blkio", "blkio.weight", t
, NULL
, NULL
);
1946 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
1953 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
) {
1965 l
= strv_split_quoted(rvalue
);
1971 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename
, line
, rvalue
);
1976 if (!path_is_absolute(l
[0])) {
1977 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename
, line
, rvalue
);
1982 if (parse_bytes(l
[1], &bytes
) < 0 || bytes
<= 0) {
1983 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename
, line
, rvalue
);
1988 r
= asprintf(&t
, "%s %llu", l
[0], (unsigned long long) bytes
);
1994 r
= unit_add_cgroup_attribute(u
, "blkio",
1995 streq(lvalue
, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1996 t
, blkio_map
, NULL
);
2000 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename
, line
, rvalue
);
2007 int config_parse_unit_requires_mounts_for(
2008 const char *filename
,
2010 const char *section
,
2026 empty_before
= !u
->requires_mounts_for
;
2028 r
= config_parse_path_strv(filename
, line
, section
, lvalue
, ltype
, rvalue
, data
, userdata
);
2030 /* Make it easy to find units with requires_mounts set */
2031 if (empty_before
&& u
->requires_mounts_for
)
2032 LIST_PREPEND(Unit
, has_requires_mounts_for
, u
->manager
->has_requires_mounts_for
, u
);
2037 int config_parse_documentation(
2038 const char *filename
,
2040 const char *section
,
2056 r
= config_parse_unit_strv_printf(filename
, line
, section
, lvalue
, ltype
, rvalue
, data
, userdata
);
2060 for (a
= b
= u
->documentation
; a
&& *a
; a
++) {
2062 if (is_valid_documentation_url(*a
))
2065 log_error("[%s:%u] Invalid URL, ignoring: %s", filename
, line
, *a
);
2074 static void syscall_set(uint32_t *p
, int nr
) {
2075 p
[nr
>> 4] |= 1 << (nr
& 31);
2078 static void syscall_unset(uint32_t *p
, int nr
) {
2079 p
[nr
>> 4] &= ~(1 << (nr
& 31));
2082 int config_parse_syscall_filter(
2083 const char *filename
,
2085 const char *section
,
2092 ExecContext
*c
= data
;
2094 bool invert
= false;
2104 if (rvalue
[0] == '~') {
2109 if (!c
->syscall_filter
) {
2112 n
= (syscall_max() + 31) >> 4;
2113 c
->syscall_filter
= new(uint32_t, n
);
2114 if (!c
->syscall_filter
)
2117 memset(c
->syscall_filter
, invert
? 0xFF : 0, n
* sizeof(uint32_t));
2119 /* Add these by default */
2120 syscall_set(c
->syscall_filter
, __NR_execve
);
2121 syscall_set(c
->syscall_filter
, __NR_rt_sigreturn
);
2122 #ifdef __NR_sigreturn
2123 syscall_set(c
->syscall_filter
, __NR_sigreturn
);
2125 syscall_set(c
->syscall_filter
, __NR_exit_group
);
2126 syscall_set(c
->syscall_filter
, __NR_exit
);
2129 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
2131 char _cleanup_free_
*t
= NULL
;
2137 id
= syscall_from_name(t
);
2140 log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2146 syscall_unset(c
->syscall_filter
, id
);
2148 syscall_set(c
->syscall_filter
, id
);
2151 c
->no_new_privileges
= true;
2156 #define FOLLOW_MAX 8
2158 static int open_follow(char **filename
, FILE **_f
, Set
*names
, char **_final
) {
2169 /* This will update the filename pointer if the loaded file is
2170 * reached by a symlink. The old string will be freed. */
2173 char *target
, *name
;
2175 if (c
++ >= FOLLOW_MAX
)
2178 path_kill_slashes(*filename
);
2180 /* Add the file name we are currently looking at to
2181 * the names of this unit, but only if it is a valid
2183 name
= path_get_file_name(*filename
);
2185 if (unit_name_is_valid(name
, true)) {
2187 id
= set_get(names
, name
);
2193 r
= set_put(names
, id
);
2201 /* Try to open the file name, but don't if its a symlink */
2202 fd
= open(*filename
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
2209 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2210 r
= readlink_and_make_absolute(*filename
, &target
);
2218 f
= fdopen(fd
, "re");
2221 close_nointr_nofail(fd
);
2230 static int merge_by_names(Unit
**u
, Set
*names
, const char *id
) {
2238 /* Let's try to add in all symlink names we found */
2239 while ((k
= set_steal_first(names
))) {
2241 /* First try to merge in the other name into our
2243 r
= unit_merge_by_name(*u
, k
);
2247 /* Hmm, we couldn't merge the other unit into
2248 * ours? Then let's try it the other way
2251 other
= manager_get_unit((*u
)->manager
, k
);
2255 r
= unit_merge(other
, *u
);
2258 return merge_by_names(u
, names
, NULL
);
2266 unit_choose_id(*u
, id
);
2274 static int load_from_path(Unit
*u
, const char *path
) {
2278 char *filename
= NULL
, *id
= NULL
;
2285 symlink_names
= set_new(string_hash_func
, string_compare_func
);
2289 if (path_is_absolute(path
)) {
2291 filename
= strdup(path
);
2297 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
2309 STRV_FOREACH(p
, u
->manager
->lookup_paths
.unit_path
) {
2311 /* Instead of opening the path right away, we manually
2312 * follow all symlinks and add their name to our unit
2313 * name set while doing so */
2314 filename
= path_make_absolute(path
, *p
);
2320 if (u
->manager
->unit_path_cache
&&
2321 !set_get(u
->manager
->unit_path_cache
, filename
))
2324 r
= open_follow(&filename
, &f
, symlink_names
, &id
);
2333 /* Empty the symlink names for the next run */
2334 set_clear_free(symlink_names
);
2343 /* Hmm, no suitable file found? */
2349 r
= merge_by_names(&merged
, symlink_names
, id
);
2354 u
->load_state
= UNIT_MERGED
;
2359 if (fstat(fileno(f
), &st
) < 0) {
2364 if (null_or_empty(&st
))
2365 u
->load_state
= UNIT_MASKED
;
2367 /* Now, parse the file contents */
2368 r
= config_parse(filename
, f
, UNIT_VTABLE(u
)->sections
, config_item_perf_lookup
, (void*) load_fragment_gperf_lookup
, false, u
);
2372 u
->load_state
= UNIT_LOADED
;
2375 free(u
->fragment_path
);
2376 u
->fragment_path
= filename
;
2379 u
->fragment_mtime
= timespec_load(&st
.st_mtim
);
2381 if (u
->source_path
) {
2382 if (stat(u
->source_path
, &st
) >= 0)
2383 u
->source_mtime
= timespec_load(&st
.st_mtim
);
2385 u
->source_mtime
= 0;
2391 set_free_free(symlink_names
);
2400 int unit_load_fragment(Unit
*u
) {
2406 assert(u
->load_state
== UNIT_STUB
);
2409 /* First, try to find the unit under its id. We always look
2410 * for unit files in the default directories, to make it easy
2411 * to override things by placing things in /etc/systemd/system */
2412 r
= load_from_path(u
, u
->id
);
2416 /* Try to find an alias we can load this with */
2417 if (u
->load_state
== UNIT_STUB
)
2418 SET_FOREACH(t
, u
->names
, i
) {
2423 r
= load_from_path(u
, t
);
2427 if (u
->load_state
!= UNIT_STUB
)
2431 /* And now, try looking for it under the suggested (originally linked) path */
2432 if (u
->load_state
== UNIT_STUB
&& u
->fragment_path
) {
2434 r
= load_from_path(u
, u
->fragment_path
);
2438 if (u
->load_state
== UNIT_STUB
) {
2439 /* Hmm, this didn't work? Then let's get rid
2440 * of the fragment path stored for us, so that
2441 * we don't point to an invalid location. */
2442 free(u
->fragment_path
);
2443 u
->fragment_path
= NULL
;
2447 /* Look for a template */
2448 if (u
->load_state
== UNIT_STUB
&& u
->instance
) {
2451 k
= unit_name_template(u
->id
);
2455 r
= load_from_path(u
, k
);
2461 if (u
->load_state
== UNIT_STUB
)
2462 SET_FOREACH(t
, u
->names
, i
) {
2467 k
= unit_name_template(t
);
2471 r
= load_from_path(u
, k
);
2477 if (u
->load_state
!= UNIT_STUB
)
2485 void unit_dump_config_items(FILE *f
) {
2486 static const struct {
2487 const ConfigParserCallback callback
;
2490 { config_parse_int
, "INTEGER" },
2491 { config_parse_unsigned
, "UNSIGNED" },
2492 { config_parse_bytes_size
, "SIZE" },
2493 { config_parse_bool
, "BOOLEAN" },
2494 { config_parse_string
, "STRING" },
2495 { config_parse_path
, "PATH" },
2496 { config_parse_unit_path_printf
, "PATH" },
2497 { config_parse_strv
, "STRING [...]" },
2498 { config_parse_exec_nice
, "NICE" },
2499 { config_parse_exec_oom_score_adjust
, "OOMSCOREADJUST" },
2500 { config_parse_exec_io_class
, "IOCLASS" },
2501 { config_parse_exec_io_priority
, "IOPRIORITY" },
2502 { config_parse_exec_cpu_sched_policy
, "CPUSCHEDPOLICY" },
2503 { config_parse_exec_cpu_sched_prio
, "CPUSCHEDPRIO" },
2504 { config_parse_exec_cpu_affinity
, "CPUAFFINITY" },
2505 { config_parse_mode
, "MODE" },
2506 { config_parse_unit_env_file
, "FILE" },
2507 { config_parse_output
, "OUTPUT" },
2508 { config_parse_input
, "INPUT" },
2509 { config_parse_facility
, "FACILITY" },
2510 { config_parse_level
, "LEVEL" },
2511 { config_parse_exec_capabilities
, "CAPABILITIES" },
2512 { config_parse_exec_secure_bits
, "SECUREBITS" },
2513 { config_parse_bounding_set
, "BOUNDINGSET" },
2514 { config_parse_limit
, "LIMIT" },
2515 { config_parse_unit_cgroup
, "CGROUP [...]" },
2516 { config_parse_unit_deps
, "UNIT [...]" },
2517 { config_parse_exec
, "PATH [ARGUMENT [...]]" },
2518 { config_parse_service_type
, "SERVICETYPE" },
2519 { config_parse_service_restart
, "SERVICERESTART" },
2520 #ifdef HAVE_SYSV_COMPAT
2521 { config_parse_sysv_priority
, "SYSVPRIORITY" },
2523 { config_parse_warn_compat
, "NOTSUPPORTED" },
2525 { config_parse_kill_mode
, "KILLMODE" },
2526 { config_parse_kill_signal
, "SIGNAL" },
2527 { config_parse_socket_listen
, "SOCKET [...]" },
2528 { config_parse_socket_bind
, "SOCKETBIND" },
2529 { config_parse_socket_bindtodevice
, "NETWORKINTERFACE" },
2530 { config_parse_usec
, "SECONDS" },
2531 { config_parse_nsec
, "NANOSECONDS" },
2532 { config_parse_path_strv
, "PATH [...]" },
2533 { config_parse_unit_requires_mounts_for
, "PATH [...]" },
2534 { config_parse_exec_mount_flags
, "MOUNTFLAG [...]" },
2535 { config_parse_unit_string_printf
, "STRING" },
2536 { config_parse_timer
, "TIMER" },
2537 { config_parse_timer_unit
, "NAME" },
2538 { config_parse_path_spec
, "PATH" },
2539 { config_parse_path_unit
, "UNIT" },
2540 { config_parse_notify_access
, "ACCESS" },
2541 { config_parse_ip_tos
, "TOS" },
2542 { config_parse_unit_condition_path
, "CONDITION" },
2543 { config_parse_unit_condition_string
, "CONDITION" },
2544 { config_parse_unit_condition_null
, "CONDITION" },
2547 const char *prev
= NULL
;
2552 NULSTR_FOREACH(i
, load_fragment_gperf_nulstr
) {
2553 const char *rvalue
= "OTHER", *lvalue
;
2557 const ConfigPerfItem
*p
;
2559 assert_se(p
= load_fragment_gperf_lookup(i
, strlen(i
)));
2561 dot
= strchr(i
, '.');
2562 lvalue
= dot
? dot
+ 1 : i
;
2566 if (!prev
|| strncmp(prev
, i
, prefix_len
+1) != 0) {
2570 fprintf(f
, "[%.*s]\n", (int) prefix_len
, i
);
2573 for (j
= 0; j
< ELEMENTSOF(table
); j
++)
2574 if (p
->parse
== table
[j
].callback
) {
2575 rvalue
= table
[j
].rvalue
;
2579 fprintf(f
, "%s=%s\n", lvalue
, rvalue
);