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 "unit-printf.h"
46 #include "bus-errors.h"
48 #include "path-util.h"
49 #include "syscall-list.h"
51 #ifndef HAVE_SYSV_COMPAT
52 int config_parse_warn_compat(
62 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
67 int config_parse_unit_deps(
77 UnitDependency d = ltype;
87 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
95 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", filename, line, k, strerror(-r));
110 int config_parse_unit_string_printf(
111 const char *filename,
129 k = unit_full_printf(u, rvalue);
133 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
139 int config_parse_unit_strv_printf(
140 const char *filename,
158 k = unit_full_printf(u, rvalue);
162 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
168 int config_parse_unit_path_printf(
169 const char *filename,
187 k = unit_full_printf(u, rvalue);
191 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
197 int config_parse_socket_listen(
198 const char *filename,
207 SocketPort *p, *tail;
217 p = new0(SocketPort, 1);
221 if (streq(lvalue, "ListenFIFO")) {
222 p->type = SOCKET_FIFO;
224 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
229 path_kill_slashes(p->path);
231 } else if (streq(lvalue, "ListenSpecial")) {
232 p->type = SOCKET_SPECIAL;
234 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
239 path_kill_slashes(p->path);
241 } else if (streq(lvalue, "ListenMessageQueue")) {
243 p->type = SOCKET_MQUEUE;
245 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
250 path_kill_slashes(p->path);
252 } else if (streq(lvalue, "ListenNetlink")) {
256 p->type = SOCKET_SOCKET;
257 k = unit_full_printf(UNIT(s), rvalue);
258 r = socket_address_parse_netlink(&p->address, k);
262 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
271 p->type = SOCKET_SOCKET;
272 k = unit_full_printf(UNIT(s), rvalue);
273 r = socket_address_parse(&p->address, k);
277 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
282 if (streq(lvalue, "ListenStream"))
283 p->address.type = SOCK_STREAM;
284 else if (streq(lvalue, "ListenDatagram"))
285 p->address.type = SOCK_DGRAM;
287 assert(streq(lvalue, "ListenSequentialPacket"));
288 p->address.type = SOCK_SEQPACKET;
291 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
292 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
301 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
302 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
304 LIST_PREPEND(SocketPort, port, s->ports, p);
309 int config_parse_socket_bind(
310 const char *filename,
320 SocketAddressBindIPv6Only b;
329 b = socket_address_bind_ipv6_only_from_string(rvalue);
333 r = parse_boolean(rvalue);
335 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
339 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
341 s->bind_ipv6_only = b;
346 int config_parse_exec_nice(
347 const char *filename,
356 ExecContext *c = data;
364 if (safe_atoi(rvalue, &priority) < 0) {
365 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
369 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
370 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
380 int config_parse_exec_oom_score_adjust(
381 const char *filename,
390 ExecContext *c = data;
398 if (safe_atoi(rvalue, &oa) < 0) {
399 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
403 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
404 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
408 c->oom_score_adjust = oa;
409 c->oom_score_adjust_set = true;
414 int config_parse_exec(
415 const char *filename,
424 ExecCommand **e = data, *nce;
434 /* We accept an absolute path as first argument, or
435 * alternatively an absolute prefixed with @ to allow
436 * overriding of argv[0]. */
444 bool honour_argv0 = false, ignore = false;
450 rvalue += strspn(rvalue, WHITESPACE);
455 if (rvalue[0] == '-') {
460 if (rvalue[0] == '@') {
465 if (*rvalue != '/') {
466 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
471 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
472 if (strncmp(w, ";", MAX(l, 1U)) == 0)
478 n = new(char*, k + !honour_argv0);
483 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
484 if (strncmp(w, ";", MAX(l, 1U)) == 0)
487 if (honour_argv0 && w == rvalue) {
490 path = strndup(w, l);
496 if (!utf8_is_valid(path)) {
497 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
505 c = n[k++] = cunescape_length(w, l);
511 if (!utf8_is_valid(c)) {
512 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
522 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
535 assert(path_is_absolute(path));
537 nce = new0(ExecCommand, 1);
545 nce->ignore = ignore;
547 path_kill_slashes(nce->path);
549 exec_command_append_list(e, nce);
565 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
566 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
568 int config_parse_socket_bindtodevice(
569 const char *filename,
586 if (rvalue[0] && !streq(rvalue, "*")) {
587 if (!(n = strdup(rvalue)))
592 free(s->bind_to_device);
593 s->bind_to_device = n;
598 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
599 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
601 int config_parse_exec_io_class(
602 const char *filename,
611 ExecContext *c = data;
619 x = ioprio_class_from_string(rvalue);
621 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
625 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
626 c->ioprio_set = true;
631 int config_parse_exec_io_priority(
632 const char *filename,
641 ExecContext *c = data;
649 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
650 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
654 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
655 c->ioprio_set = true;
660 int config_parse_exec_cpu_sched_policy(
661 const char *filename,
671 ExecContext *c = data;
679 x = sched_policy_from_string(rvalue);
681 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
685 c->cpu_sched_policy = x;
686 c->cpu_sched_set = true;
691 int config_parse_exec_cpu_sched_prio(
692 const char *filename,
701 ExecContext *c = data;
709 /* On Linux RR/FIFO have the same range */
710 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
711 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
715 c->cpu_sched_priority = i;
716 c->cpu_sched_set = true;
721 int config_parse_exec_cpu_affinity(
722 const char *filename,
731 ExecContext *c = data;
741 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
746 if (!(t = strndup(w, l)))
749 r = safe_atou(t, &cpu);
753 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
756 if (r < 0 || cpu >= c->cpuset_ncpus) {
757 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
761 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
767 int config_parse_exec_capabilities(
768 const char *filename,
777 ExecContext *c = data;
785 if (!(cap = cap_from_text(rvalue))) {
789 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
794 cap_free(c->capabilities);
795 c->capabilities = cap;
800 int config_parse_exec_secure_bits(
801 const char *filename,
810 ExecContext *c = data;
820 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
821 if (first_word(w, "keep-caps"))
822 c->secure_bits |= SECURE_KEEP_CAPS;
823 else if (first_word(w, "keep-caps-locked"))
824 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
825 else if (first_word(w, "no-setuid-fixup"))
826 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
827 else if (first_word(w, "no-setuid-fixup-locked"))
828 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
829 else if (first_word(w, "noroot"))
830 c->secure_bits |= SECURE_NOROOT;
831 else if (first_word(w, "noroot-locked"))
832 c->secure_bits |= SECURE_NOROOT_LOCKED;
834 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
842 int config_parse_bounding_set(
843 const char *filename,
852 uint64_t *capability_bounding_set_drop = data;
864 if (rvalue[0] == '~') {
869 /* Note that we store this inverted internally, since the
870 * kernel wants it like this. But we actually expose it
871 * non-inverted everywhere to have a fully normalized
874 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
883 r = cap_from_name(t, &cap);
887 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
891 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
895 *capability_bounding_set_drop |= sum;
897 *capability_bounding_set_drop |= ~sum;
902 int config_parse_limit(
903 const char *filename,
912 struct rlimit **rl = data;
913 unsigned long long u;
922 if (streq(rvalue, "infinity"))
923 u = (unsigned long long) RLIM_INFINITY;
924 else if (safe_atollu(rvalue, &u) < 0) {
925 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
930 if (!(*rl = new(struct rlimit, 1)))
933 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
937 int config_parse_unit_cgroup(
938 const char *filename,
952 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
960 k = unit_full_printf(u, t);
972 r = unit_add_cgroup_from_text(u, t);
976 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
984 #ifdef HAVE_SYSV_COMPAT
985 int config_parse_sysv_priority(
986 const char *filename,
995 int *priority = data;
1003 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1004 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1008 *priority = (int) i;
1013 int config_parse_fsck_passno(
1014 const char *filename,
1016 const char *section,
1031 if (safe_atoi(rvalue, &i) || i < 0) {
1032 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1040 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1042 int config_parse_kill_signal(
1043 const char *filename,
1045 const char *section,
1060 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1061 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1069 int config_parse_exec_mount_flags(
1070 const char *filename,
1072 const char *section,
1079 ExecContext *c = data;
1083 unsigned long flags = 0;
1090 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1091 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1093 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1095 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1096 flags |= MS_PRIVATE;
1098 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1103 c->mount_flags = flags;
1107 int config_parse_timer(
1108 const char *filename,
1110 const char *section,
1127 if ((b = timer_base_from_string(lvalue)) < 0) {
1128 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1132 if (parse_usec(rvalue, &u) < 0) {
1133 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1137 if (!(v = new0(TimerValue, 1)))
1143 LIST_PREPEND(TimerValue, value, t->values, v);
1148 int config_parse_timer_unit(
1149 const char *filename,
1151 const char *section,
1168 dbus_error_init(&error);
1170 if (endswith(rvalue, ".timer")) {
1171 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1175 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1177 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1178 dbus_error_free(&error);
1182 unit_ref_set(&t->unit, u);
1187 int config_parse_path_spec(
1188 const char *filename,
1190 const char *section,
1207 b = path_type_from_string(lvalue);
1209 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1213 k = unit_full_printf(UNIT(p), rvalue);
1217 if (!path_is_absolute(k)) {
1218 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1223 s = new0(PathSpec, 1);
1229 s->path = path_kill_slashes(k);
1233 LIST_PREPEND(PathSpec, spec, p->specs, s);
1238 int config_parse_path_unit(
1239 const char *filename,
1241 const char *section,
1258 dbus_error_init(&error);
1260 if (endswith(rvalue, ".path")) {
1261 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1265 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1266 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1267 dbus_error_free(&error);
1271 unit_ref_set(&t->unit, u);
1276 int config_parse_socket_service(
1277 const char *filename,
1279 const char *section,
1296 dbus_error_init(&error);
1298 if (!endswith(rvalue, ".service")) {
1299 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1303 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1305 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1306 dbus_error_free(&error);
1310 unit_ref_set(&s->service, x);
1315 int config_parse_service_sockets(
1316 const char *filename,
1318 const char *section,
1335 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1342 k = unit_name_printf(UNIT(s), t);
1348 if (!endswith(k, ".socket")) {
1349 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1354 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1356 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1358 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1368 int config_parse_service_timeout(
1369 const char *filename,
1371 const char *section,
1378 Service *s = userdata;
1386 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1391 if (streq(lvalue, "TimeoutSec")) {
1392 s->start_timeout_defined = true;
1393 s->timeout_stop_usec = s->timeout_start_usec;
1394 } else if (streq(lvalue, "TimeoutStartSec"))
1395 s->start_timeout_defined = true;
1400 int config_parse_unit_env_file(
1401 const char *filename,
1403 const char *section,
1410 char ***env = data, **k;
1419 s = unit_full_printf(u, rvalue);
1423 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1424 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1429 k = strv_append(*env, s);
1440 int config_parse_ip_tos(
1441 const char *filename,
1443 const char *section,
1450 int *ip_tos = data, x;
1457 x = ip_tos_from_string(rvalue);
1459 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1467 int config_parse_unit_condition_path(
1468 const char *filename,
1470 const char *section,
1477 ConditionType cond = ltype;
1479 bool trigger, negate;
1481 _cleanup_free_ char *p = NULL;
1488 trigger = rvalue[0] == '|';
1492 negate = rvalue[0] == '!';
1496 p = unit_full_printf(u, rvalue);
1500 if (!path_is_absolute(p)) {
1501 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1505 c = condition_new(cond, p, trigger, negate);
1509 LIST_PREPEND(Condition, conditions, u->conditions, c);
1513 int config_parse_unit_condition_string(
1514 const char *filename,
1516 const char *section,
1523 ConditionType cond = ltype;
1525 bool trigger, negate;
1527 _cleanup_free_ char *s = NULL;
1534 trigger = rvalue[0] == '|';
1538 negate = rvalue[0] == '!';
1542 s = unit_full_printf(u, rvalue);
1546 c = condition_new(cond, s, trigger, negate);
1550 LIST_PREPEND(Condition, conditions, u->conditions, c);
1554 int config_parse_unit_condition_null(
1555 const char *filename,
1557 const char *section,
1566 bool trigger, negate;
1574 if ((trigger = rvalue[0] == '|'))
1577 if ((negate = rvalue[0] == '!'))
1580 if ((b = parse_boolean(rvalue)) < 0) {
1581 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1588 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1591 LIST_PREPEND(Condition, conditions, u->conditions, c);
1595 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1596 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1598 int config_parse_unit_cgroup_attr(
1599 const char *filename,
1601 const char *section,
1617 l = strv_split_quoted(rvalue);
1621 if (strv_length(l) != 2) {
1622 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1627 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1631 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1638 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) {
1649 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1650 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1654 if (asprintf(&t, "%lu", ul) < 0)
1657 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1661 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1668 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) {
1679 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1680 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1684 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1687 r = unit_add_cgroup_attribute(u,
1689 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1694 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1701 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1709 l = strv_split_quoted(value);
1713 assert(strv_length(l) >= 1);
1715 if (streq(l[0], "*")) {
1717 if (asprintf(ret, "a *:*%s%s",
1718 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1726 if (stat(l[0], &st) < 0) {
1727 log_warning("Couldn't stat device %s", l[0]);
1732 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1733 log_warning("%s is not a device.", l[0]);
1738 if (asprintf(ret, "%c %u:%u%s%s",
1739 S_ISCHR(st.st_mode) ? 'c' : 'b',
1740 major(st.st_rdev), minor(st.st_rdev),
1741 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1752 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) {
1763 l = strv_split_quoted(rvalue);
1768 if (k < 1 || k > 2) {
1769 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1774 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1775 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1780 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1781 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1787 r = unit_add_cgroup_attribute(u, "devices",
1788 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1789 rvalue, device_map);
1792 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1799 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1809 l = strv_split_quoted(value);
1813 assert(strv_length(l) == 2);
1815 if (stat(l[0], &st) < 0) {
1816 log_warning("Couldn't stat device %s", l[0]);
1821 if (S_ISBLK(st.st_mode))
1823 else if (major(st.st_dev) != 0) {
1824 /* If this is not a device node then find the block
1825 * device this file is stored on */
1828 /* If this is a partition, try to get the originating
1830 block_get_whole_disk(d, &d);
1832 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1837 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1846 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) {
1850 const char *device = NULL, *weight;
1859 l = strv_split_quoted(rvalue);
1864 if (k < 1 || k > 2) {
1865 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1877 if (device && !path_is_absolute(device)) {
1878 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1883 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1884 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1890 r = asprintf(&t, "%s %lu", device, ul);
1892 r = asprintf(&t, "%lu", ul);
1899 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1901 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1905 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1912 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) {
1924 l = strv_split_quoted(rvalue);
1930 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1935 if (!path_is_absolute(l[0])) {
1936 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1941 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1942 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1947 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1953 r = unit_add_cgroup_attribute(u, "blkio",
1954 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1959 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1966 int config_parse_unit_requires_mounts_for(
1967 const char *filename,
1969 const char *section,
1985 empty_before = !u->requires_mounts_for;
1987 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1989 /* Make it easy to find units with requires_mounts set */
1990 if (empty_before && u->requires_mounts_for)
1991 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1996 int config_parse_documentation(
1997 const char *filename,
1999 const char *section,
2015 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2019 for (a = b = u->documentation; a && *a; a++) {
2021 if (is_valid_documentation_url(*a))
2024 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2033 static void syscall_set(uint32_t *p, int nr) {
2034 p[nr >> 4] |= 1 << (nr & 31);
2037 static void syscall_unset(uint32_t *p, int nr) {
2038 p[nr >> 4] &= ~(1 << (nr & 31));
2041 int config_parse_syscall_filter(
2042 const char *filename,
2044 const char *section,
2051 ExecContext *c = data;
2053 bool invert = false;
2063 if (rvalue[0] == '~') {
2068 if (!c->syscall_filter) {
2071 n = (syscall_max() + 31) >> 4;
2072 c->syscall_filter = new(uint32_t, n);
2073 if (!c->syscall_filter)
2076 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2078 /* Add these by default */
2079 syscall_set(c->syscall_filter, __NR_execve);
2080 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2081 #ifdef __NR_sigreturn
2082 syscall_set(c->syscall_filter, __NR_sigreturn);
2084 syscall_set(c->syscall_filter, __NR_exit_group);
2085 syscall_set(c->syscall_filter, __NR_exit);
2088 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2096 id = syscall_from_name(t);
2100 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2105 syscall_unset(c->syscall_filter, id);
2107 syscall_set(c->syscall_filter, id);
2110 c->no_new_privileges = true;
2115 #define FOLLOW_MAX 8
2117 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2128 /* This will update the filename pointer if the loaded file is
2129 * reached by a symlink. The old string will be freed. */
2132 char *target, *name;
2134 if (c++ >= FOLLOW_MAX)
2137 path_kill_slashes(*filename);
2139 /* Add the file name we are currently looking at to
2140 * the names of this unit, but only if it is a valid
2142 name = path_get_file_name(*filename);
2144 if (unit_name_is_valid(name, true)) {
2146 id = set_get(names, name);
2152 r = set_put(names, id);
2160 /* Try to open the file name, but don't if its a symlink */
2161 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2168 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2169 r = readlink_and_make_absolute(*filename, &target);
2177 f = fdopen(fd, "re");
2180 close_nointr_nofail(fd);
2189 static int merge_by_names(Unit **u, Set *names, const char *id) {
2197 /* Let's try to add in all symlink names we found */
2198 while ((k = set_steal_first(names))) {
2200 /* First try to merge in the other name into our
2202 r = unit_merge_by_name(*u, k);
2206 /* Hmm, we couldn't merge the other unit into
2207 * ours? Then let's try it the other way
2210 other = manager_get_unit((*u)->manager, k);
2214 r = unit_merge(other, *u);
2217 return merge_by_names(u, names, NULL);
2225 unit_choose_id(*u, id);
2233 static int load_from_path(Unit *u, const char *path) {
2237 char *filename = NULL, *id = NULL;
2244 symlink_names = set_new(string_hash_func, string_compare_func);
2248 if (path_is_absolute(path)) {
2250 filename = strdup(path);
2256 r = open_follow(&filename, &f, symlink_names, &id);
2268 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2270 /* Instead of opening the path right away, we manually
2271 * follow all symlinks and add their name to our unit
2272 * name set while doing so */
2273 filename = path_make_absolute(path, *p);
2279 if (u->manager->unit_path_cache &&
2280 !set_get(u->manager->unit_path_cache, filename))
2283 r = open_follow(&filename, &f, symlink_names, &id);
2292 /* Empty the symlink names for the next run */
2293 set_clear_free(symlink_names);
2302 /* Hmm, no suitable file found? */
2308 r = merge_by_names(&merged, symlink_names, id);
2313 u->load_state = UNIT_MERGED;
2318 if (fstat(fileno(f), &st) < 0) {
2323 if (null_or_empty(&st))
2324 u->load_state = UNIT_MASKED;
2326 /* Now, parse the file contents */
2327 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2331 u->load_state = UNIT_LOADED;
2334 free(u->fragment_path);
2335 u->fragment_path = filename;
2338 u->fragment_mtime = timespec_load(&st.st_mtim);
2340 if (u->source_path) {
2341 if (stat(u->source_path, &st) >= 0)
2342 u->source_mtime = timespec_load(&st.st_mtim);
2344 u->source_mtime = 0;
2350 set_free_free(symlink_names);
2359 int unit_load_fragment(Unit *u) {
2365 assert(u->load_state == UNIT_STUB);
2368 /* First, try to find the unit under its id. We always look
2369 * for unit files in the default directories, to make it easy
2370 * to override things by placing things in /etc/systemd/system */
2371 r = load_from_path(u, u->id);
2375 /* Try to find an alias we can load this with */
2376 if (u->load_state == UNIT_STUB)
2377 SET_FOREACH(t, u->names, i) {
2382 r = load_from_path(u, t);
2386 if (u->load_state != UNIT_STUB)
2390 /* And now, try looking for it under the suggested (originally linked) path */
2391 if (u->load_state == UNIT_STUB && u->fragment_path) {
2393 r = load_from_path(u, u->fragment_path);
2397 if (u->load_state == UNIT_STUB) {
2398 /* Hmm, this didn't work? Then let's get rid
2399 * of the fragment path stored for us, so that
2400 * we don't point to an invalid location. */
2401 free(u->fragment_path);
2402 u->fragment_path = NULL;
2406 /* Look for a template */
2407 if (u->load_state == UNIT_STUB && u->instance) {
2410 k = unit_name_template(u->id);
2414 r = load_from_path(u, k);
2420 if (u->load_state == UNIT_STUB)
2421 SET_FOREACH(t, u->names, i) {
2426 k = unit_name_template(t);
2430 r = load_from_path(u, k);
2436 if (u->load_state != UNIT_STUB)
2444 void unit_dump_config_items(FILE *f) {
2445 static const struct {
2446 const ConfigParserCallback callback;
2449 { config_parse_int, "INTEGER" },
2450 { config_parse_unsigned, "UNSIGNED" },
2451 { config_parse_bytes_size, "SIZE" },
2452 { config_parse_bool, "BOOLEAN" },
2453 { config_parse_string, "STRING" },
2454 { config_parse_path, "PATH" },
2455 { config_parse_unit_path_printf, "PATH" },
2456 { config_parse_strv, "STRING [...]" },
2457 { config_parse_exec_nice, "NICE" },
2458 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2459 { config_parse_exec_io_class, "IOCLASS" },
2460 { config_parse_exec_io_priority, "IOPRIORITY" },
2461 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2462 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2463 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2464 { config_parse_mode, "MODE" },
2465 { config_parse_unit_env_file, "FILE" },
2466 { config_parse_output, "OUTPUT" },
2467 { config_parse_input, "INPUT" },
2468 { config_parse_facility, "FACILITY" },
2469 { config_parse_level, "LEVEL" },
2470 { config_parse_exec_capabilities, "CAPABILITIES" },
2471 { config_parse_exec_secure_bits, "SECUREBITS" },
2472 { config_parse_bounding_set, "BOUNDINGSET" },
2473 { config_parse_limit, "LIMIT" },
2474 { config_parse_unit_cgroup, "CGROUP [...]" },
2475 { config_parse_unit_deps, "UNIT [...]" },
2476 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2477 { config_parse_service_type, "SERVICETYPE" },
2478 { config_parse_service_restart, "SERVICERESTART" },
2479 #ifdef HAVE_SYSV_COMPAT
2480 { config_parse_sysv_priority, "SYSVPRIORITY" },
2482 { config_parse_warn_compat, "NOTSUPPORTED" },
2484 { config_parse_kill_mode, "KILLMODE" },
2485 { config_parse_kill_signal, "SIGNAL" },
2486 { config_parse_socket_listen, "SOCKET [...]" },
2487 { config_parse_socket_bind, "SOCKETBIND" },
2488 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2489 { config_parse_usec, "SECONDS" },
2490 { config_parse_nsec, "NANOSECONDS" },
2491 { config_parse_path_strv, "PATH [...]" },
2492 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2493 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2494 { config_parse_unit_string_printf, "STRING" },
2495 { config_parse_timer, "TIMER" },
2496 { config_parse_timer_unit, "NAME" },
2497 { config_parse_path_spec, "PATH" },
2498 { config_parse_path_unit, "UNIT" },
2499 { config_parse_notify_access, "ACCESS" },
2500 { config_parse_ip_tos, "TOS" },
2501 { config_parse_unit_condition_path, "CONDITION" },
2502 { config_parse_unit_condition_string, "CONDITION" },
2503 { config_parse_unit_condition_null, "CONDITION" },
2506 const char *prev = NULL;
2511 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2512 const char *rvalue = "OTHER", *lvalue;
2516 const ConfigPerfItem *p;
2518 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2520 dot = strchr(i, '.');
2521 lvalue = dot ? dot + 1 : i;
2525 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2529 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2532 for (j = 0; j < ELEMENTSOF(table); j++)
2533 if (p->parse == table[j].callback) {
2534 rvalue = table[j].rvalue;
2538 fprintf(f, "%s=%s\n", lvalue, rvalue);