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 if ((x = ioprio_class_from_string(rvalue)) < 0) {
620 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
624 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
625 c->ioprio_set = true;
630 int config_parse_exec_io_priority(
631 const char *filename,
640 ExecContext *c = data;
648 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
649 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
653 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
654 c->ioprio_set = true;
659 int config_parse_exec_cpu_sched_policy(
660 const char *filename,
670 ExecContext *c = data;
678 if ((x = sched_policy_from_string(rvalue)) < 0) {
679 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
683 c->cpu_sched_policy = x;
684 c->cpu_sched_set = true;
689 int config_parse_exec_cpu_sched_prio(
690 const char *filename,
699 ExecContext *c = data;
707 /* On Linux RR/FIFO have the same range */
708 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
709 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
713 c->cpu_sched_priority = i;
714 c->cpu_sched_set = true;
719 int config_parse_exec_cpu_affinity(
720 const char *filename,
729 ExecContext *c = data;
739 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
744 if (!(t = strndup(w, l)))
747 r = safe_atou(t, &cpu);
751 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
754 if (r < 0 || cpu >= c->cpuset_ncpus) {
755 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
759 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
765 int config_parse_exec_capabilities(
766 const char *filename,
775 ExecContext *c = data;
783 if (!(cap = cap_from_text(rvalue))) {
787 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
792 cap_free(c->capabilities);
793 c->capabilities = cap;
798 int config_parse_exec_secure_bits(
799 const char *filename,
808 ExecContext *c = data;
818 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
819 if (first_word(w, "keep-caps"))
820 c->secure_bits |= SECURE_KEEP_CAPS;
821 else if (first_word(w, "keep-caps-locked"))
822 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
823 else if (first_word(w, "no-setuid-fixup"))
824 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
825 else if (first_word(w, "no-setuid-fixup-locked"))
826 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
827 else if (first_word(w, "noroot"))
828 c->secure_bits |= SECURE_NOROOT;
829 else if (first_word(w, "noroot-locked"))
830 c->secure_bits |= SECURE_NOROOT_LOCKED;
832 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
840 int config_parse_bounding_set(
841 const char *filename,
850 uint64_t *capability_bounding_set_drop = data;
862 if (rvalue[0] == '~') {
867 /* Note that we store this inverted internally, since the
868 * kernel wants it like this. But we actually expose it
869 * non-inverted everywhere to have a fully normalized
872 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
881 r = cap_from_name(t, &cap);
885 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
889 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
893 *capability_bounding_set_drop |= sum;
895 *capability_bounding_set_drop |= ~sum;
900 int config_parse_limit(
901 const char *filename,
910 struct rlimit **rl = data;
911 unsigned long long u;
920 if (streq(rvalue, "infinity"))
921 u = (unsigned long long) RLIM_INFINITY;
922 else if (safe_atollu(rvalue, &u) < 0) {
923 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
928 if (!(*rl = new(struct rlimit, 1)))
931 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
935 int config_parse_unit_cgroup(
936 const char *filename,
950 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
958 k = unit_full_printf(u, t);
970 r = unit_add_cgroup_from_text(u, t);
974 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
982 #ifdef HAVE_SYSV_COMPAT
983 int config_parse_sysv_priority(
984 const char *filename,
993 int *priority = data;
1001 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1002 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1006 *priority = (int) i;
1011 int config_parse_fsck_passno(
1012 const char *filename,
1014 const char *section,
1029 if (safe_atoi(rvalue, &i) || i < 0) {
1030 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1038 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1040 int config_parse_kill_signal(
1041 const char *filename,
1043 const char *section,
1058 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1059 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1067 int config_parse_exec_mount_flags(
1068 const char *filename,
1070 const char *section,
1077 ExecContext *c = data;
1081 unsigned long flags = 0;
1088 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1089 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1091 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1093 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1094 flags |= MS_PRIVATE;
1096 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1101 c->mount_flags = flags;
1105 int config_parse_timer(
1106 const char *filename,
1108 const char *section,
1125 if ((b = timer_base_from_string(lvalue)) < 0) {
1126 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1130 if (parse_usec(rvalue, &u) < 0) {
1131 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1135 if (!(v = new0(TimerValue, 1)))
1141 LIST_PREPEND(TimerValue, value, t->values, v);
1146 int config_parse_timer_unit(
1147 const char *filename,
1149 const char *section,
1166 dbus_error_init(&error);
1168 if (endswith(rvalue, ".timer")) {
1169 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1173 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1175 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1176 dbus_error_free(&error);
1180 unit_ref_set(&t->unit, u);
1185 int config_parse_path_spec(
1186 const char *filename,
1188 const char *section,
1205 b = path_type_from_string(lvalue);
1207 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1211 k = unit_full_printf(UNIT(p), rvalue);
1215 if (!path_is_absolute(k)) {
1216 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1221 s = new0(PathSpec, 1);
1227 s->path = path_kill_slashes(k);
1231 LIST_PREPEND(PathSpec, spec, p->specs, s);
1236 int config_parse_path_unit(
1237 const char *filename,
1239 const char *section,
1256 dbus_error_init(&error);
1258 if (endswith(rvalue, ".path")) {
1259 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1263 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1264 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1265 dbus_error_free(&error);
1269 unit_ref_set(&t->unit, u);
1274 int config_parse_socket_service(
1275 const char *filename,
1277 const char *section,
1294 dbus_error_init(&error);
1296 if (!endswith(rvalue, ".service")) {
1297 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1301 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1303 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1304 dbus_error_free(&error);
1308 unit_ref_set(&s->service, x);
1313 int config_parse_service_sockets(
1314 const char *filename,
1316 const char *section,
1333 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1340 k = unit_name_printf(UNIT(s), t);
1346 if (!endswith(k, ".socket")) {
1347 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1352 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1354 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1356 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1366 int config_parse_service_timeout(
1367 const char *filename,
1369 const char *section,
1376 Service *s = userdata;
1384 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1389 if (streq(lvalue, "TimeoutSec")) {
1390 s->start_timeout_defined = true;
1391 s->timeout_stop_usec = s->timeout_start_usec;
1392 } else if (streq(lvalue, "TimeoutStartSec"))
1393 s->start_timeout_defined = true;
1398 int config_parse_unit_env_file(
1399 const char *filename,
1401 const char *section,
1408 char ***env = data, **k;
1417 s = unit_full_printf(u, rvalue);
1421 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1422 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1427 k = strv_append(*env, s);
1438 int config_parse_ip_tos(
1439 const char *filename,
1441 const char *section,
1448 int *ip_tos = data, x;
1455 if ((x = ip_tos_from_string(rvalue)) < 0)
1456 if (safe_atoi(rvalue, &x) < 0) {
1457 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1465 int config_parse_unit_condition_path(
1466 const char *filename,
1468 const char *section,
1475 ConditionType cond = ltype;
1477 bool trigger, negate;
1479 _cleanup_free_ char *p = NULL;
1486 trigger = rvalue[0] == '|';
1490 negate = rvalue[0] == '!';
1494 p = unit_full_printf(u, rvalue);
1498 if (!path_is_absolute(p)) {
1499 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1503 c = condition_new(cond, p, trigger, negate);
1507 LIST_PREPEND(Condition, conditions, u->conditions, c);
1511 int config_parse_unit_condition_string(
1512 const char *filename,
1514 const char *section,
1521 ConditionType cond = ltype;
1523 bool trigger, negate;
1525 _cleanup_free_ char *s = NULL;
1532 trigger = rvalue[0] == '|';
1536 negate = rvalue[0] == '!';
1540 s = unit_full_printf(u, rvalue);
1544 c = condition_new(cond, s, trigger, negate);
1548 LIST_PREPEND(Condition, conditions, u->conditions, c);
1552 int config_parse_unit_condition_null(
1553 const char *filename,
1555 const char *section,
1564 bool trigger, negate;
1572 if ((trigger = rvalue[0] == '|'))
1575 if ((negate = rvalue[0] == '!'))
1578 if ((b = parse_boolean(rvalue)) < 0) {
1579 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1586 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1589 LIST_PREPEND(Condition, conditions, u->conditions, c);
1593 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1594 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1596 int config_parse_unit_cgroup_attr(
1597 const char *filename,
1599 const char *section,
1615 l = strv_split_quoted(rvalue);
1619 if (strv_length(l) != 2) {
1620 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1625 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1629 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1636 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) {
1647 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1648 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1652 if (asprintf(&t, "%lu", ul) < 0)
1655 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1659 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1666 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) {
1677 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1678 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1682 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1685 r = unit_add_cgroup_attribute(u,
1687 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1692 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1699 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1707 l = strv_split_quoted(value);
1711 assert(strv_length(l) >= 1);
1713 if (streq(l[0], "*")) {
1715 if (asprintf(ret, "a *:*%s%s",
1716 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1724 if (stat(l[0], &st) < 0) {
1725 log_warning("Couldn't stat device %s", l[0]);
1730 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1731 log_warning("%s is not a device.", l[0]);
1736 if (asprintf(ret, "%c %u:%u%s%s",
1737 S_ISCHR(st.st_mode) ? 'c' : 'b',
1738 major(st.st_rdev), minor(st.st_rdev),
1739 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1750 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) {
1761 l = strv_split_quoted(rvalue);
1766 if (k < 1 || k > 2) {
1767 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1772 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1773 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1778 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1779 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1785 r = unit_add_cgroup_attribute(u, "devices",
1786 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1787 rvalue, device_map);
1790 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1797 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1807 l = strv_split_quoted(value);
1811 assert(strv_length(l) == 2);
1813 if (stat(l[0], &st) < 0) {
1814 log_warning("Couldn't stat device %s", l[0]);
1819 if (S_ISBLK(st.st_mode))
1821 else if (major(st.st_dev) != 0) {
1822 /* If this is not a device node then find the block
1823 * device this file is stored on */
1826 /* If this is a partition, try to get the originating
1828 block_get_whole_disk(d, &d);
1830 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1835 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1844 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) {
1848 const char *device = NULL, *weight;
1857 l = strv_split_quoted(rvalue);
1862 if (k < 1 || k > 2) {
1863 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1875 if (device && !path_is_absolute(device)) {
1876 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1881 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1882 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1888 r = asprintf(&t, "%s %lu", device, ul);
1890 r = asprintf(&t, "%lu", ul);
1897 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1899 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1903 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1910 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) {
1922 l = strv_split_quoted(rvalue);
1928 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1933 if (!path_is_absolute(l[0])) {
1934 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1939 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1940 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1945 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1951 r = unit_add_cgroup_attribute(u, "blkio",
1952 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1957 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1964 int config_parse_unit_requires_mounts_for(
1965 const char *filename,
1967 const char *section,
1983 empty_before = !u->requires_mounts_for;
1985 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1987 /* Make it easy to find units with requires_mounts set */
1988 if (empty_before && u->requires_mounts_for)
1989 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1994 int config_parse_documentation(
1995 const char *filename,
1997 const char *section,
2013 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2017 for (a = b = u->documentation; a && *a; a++) {
2019 if (is_valid_documentation_url(*a))
2022 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2031 static void syscall_set(uint32_t *p, int nr) {
2032 p[nr >> 4] |= 1 << (nr & 31);
2035 static void syscall_unset(uint32_t *p, int nr) {
2036 p[nr >> 4] &= ~(1 << (nr & 31));
2039 int config_parse_syscall_filter(
2040 const char *filename,
2042 const char *section,
2049 ExecContext *c = data;
2051 bool invert = false;
2061 if (rvalue[0] == '~') {
2066 if (!c->syscall_filter) {
2069 n = (syscall_max() + 31) >> 4;
2070 c->syscall_filter = new(uint32_t, n);
2071 if (!c->syscall_filter)
2074 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2076 /* Add these by default */
2077 syscall_set(c->syscall_filter, __NR_execve);
2078 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2079 #ifdef __NR_sigreturn
2080 syscall_set(c->syscall_filter, __NR_sigreturn);
2082 syscall_set(c->syscall_filter, __NR_exit_group);
2083 syscall_set(c->syscall_filter, __NR_exit);
2086 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2094 id = syscall_from_name(t);
2098 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2103 syscall_unset(c->syscall_filter, id);
2105 syscall_set(c->syscall_filter, id);
2108 c->no_new_privileges = true;
2113 #define FOLLOW_MAX 8
2115 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2126 /* This will update the filename pointer if the loaded file is
2127 * reached by a symlink. The old string will be freed. */
2130 char *target, *name;
2132 if (c++ >= FOLLOW_MAX)
2135 path_kill_slashes(*filename);
2137 /* Add the file name we are currently looking at to
2138 * the names of this unit, but only if it is a valid
2140 name = path_get_file_name(*filename);
2142 if (unit_name_is_valid(name, true)) {
2144 id = set_get(names, name);
2150 r = set_put(names, id);
2158 /* Try to open the file name, but don't if its a symlink */
2159 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2166 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2167 r = readlink_and_make_absolute(*filename, &target);
2175 f = fdopen(fd, "re");
2178 close_nointr_nofail(fd);
2187 static int merge_by_names(Unit **u, Set *names, const char *id) {
2195 /* Let's try to add in all symlink names we found */
2196 while ((k = set_steal_first(names))) {
2198 /* First try to merge in the other name into our
2200 r = unit_merge_by_name(*u, k);
2204 /* Hmm, we couldn't merge the other unit into
2205 * ours? Then let's try it the other way
2208 other = manager_get_unit((*u)->manager, k);
2212 r = unit_merge(other, *u);
2215 return merge_by_names(u, names, NULL);
2223 unit_choose_id(*u, id);
2231 static int load_from_path(Unit *u, const char *path) {
2235 char *filename = NULL, *id = NULL;
2242 symlink_names = set_new(string_hash_func, string_compare_func);
2246 if (path_is_absolute(path)) {
2248 filename = strdup(path);
2254 r = open_follow(&filename, &f, symlink_names, &id);
2266 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2268 /* Instead of opening the path right away, we manually
2269 * follow all symlinks and add their name to our unit
2270 * name set while doing so */
2271 filename = path_make_absolute(path, *p);
2277 if (u->manager->unit_path_cache &&
2278 !set_get(u->manager->unit_path_cache, filename))
2281 r = open_follow(&filename, &f, symlink_names, &id);
2290 /* Empty the symlink names for the next run */
2291 set_clear_free(symlink_names);
2300 /* Hmm, no suitable file found? */
2306 r = merge_by_names(&merged, symlink_names, id);
2311 u->load_state = UNIT_MERGED;
2316 if (fstat(fileno(f), &st) < 0) {
2321 if (null_or_empty(&st))
2322 u->load_state = UNIT_MASKED;
2324 /* Now, parse the file contents */
2325 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2329 u->load_state = UNIT_LOADED;
2332 free(u->fragment_path);
2333 u->fragment_path = filename;
2336 u->fragment_mtime = timespec_load(&st.st_mtim);
2338 if (u->source_path) {
2339 if (stat(u->source_path, &st) >= 0)
2340 u->source_mtime = timespec_load(&st.st_mtim);
2342 u->source_mtime = 0;
2348 set_free_free(symlink_names);
2357 int unit_load_fragment(Unit *u) {
2363 assert(u->load_state == UNIT_STUB);
2366 /* First, try to find the unit under its id. We always look
2367 * for unit files in the default directories, to make it easy
2368 * to override things by placing things in /etc/systemd/system */
2369 r = load_from_path(u, u->id);
2373 /* Try to find an alias we can load this with */
2374 if (u->load_state == UNIT_STUB)
2375 SET_FOREACH(t, u->names, i) {
2380 r = load_from_path(u, t);
2384 if (u->load_state != UNIT_STUB)
2388 /* And now, try looking for it under the suggested (originally linked) path */
2389 if (u->load_state == UNIT_STUB && u->fragment_path) {
2391 r = load_from_path(u, u->fragment_path);
2395 if (u->load_state == UNIT_STUB) {
2396 /* Hmm, this didn't work? Then let's get rid
2397 * of the fragment path stored for us, so that
2398 * we don't point to an invalid location. */
2399 free(u->fragment_path);
2400 u->fragment_path = NULL;
2404 /* Look for a template */
2405 if (u->load_state == UNIT_STUB && u->instance) {
2408 k = unit_name_template(u->id);
2412 r = load_from_path(u, k);
2418 if (u->load_state == UNIT_STUB)
2419 SET_FOREACH(t, u->names, i) {
2424 k = unit_name_template(t);
2428 r = load_from_path(u, k);
2434 if (u->load_state != UNIT_STUB)
2442 void unit_dump_config_items(FILE *f) {
2443 static const struct {
2444 const ConfigParserCallback callback;
2447 { config_parse_int, "INTEGER" },
2448 { config_parse_unsigned, "UNSIGNED" },
2449 { config_parse_bytes_size, "SIZE" },
2450 { config_parse_bool, "BOOLEAN" },
2451 { config_parse_string, "STRING" },
2452 { config_parse_path, "PATH" },
2453 { config_parse_unit_path_printf, "PATH" },
2454 { config_parse_strv, "STRING [...]" },
2455 { config_parse_exec_nice, "NICE" },
2456 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2457 { config_parse_exec_io_class, "IOCLASS" },
2458 { config_parse_exec_io_priority, "IOPRIORITY" },
2459 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2460 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2461 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2462 { config_parse_mode, "MODE" },
2463 { config_parse_unit_env_file, "FILE" },
2464 { config_parse_output, "OUTPUT" },
2465 { config_parse_input, "INPUT" },
2466 { config_parse_facility, "FACILITY" },
2467 { config_parse_level, "LEVEL" },
2468 { config_parse_exec_capabilities, "CAPABILITIES" },
2469 { config_parse_exec_secure_bits, "SECUREBITS" },
2470 { config_parse_bounding_set, "BOUNDINGSET" },
2471 { config_parse_limit, "LIMIT" },
2472 { config_parse_unit_cgroup, "CGROUP [...]" },
2473 { config_parse_unit_deps, "UNIT [...]" },
2474 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2475 { config_parse_service_type, "SERVICETYPE" },
2476 { config_parse_service_restart, "SERVICERESTART" },
2477 #ifdef HAVE_SYSV_COMPAT
2478 { config_parse_sysv_priority, "SYSVPRIORITY" },
2480 { config_parse_warn_compat, "NOTSUPPORTED" },
2482 { config_parse_kill_mode, "KILLMODE" },
2483 { config_parse_kill_signal, "SIGNAL" },
2484 { config_parse_socket_listen, "SOCKET [...]" },
2485 { config_parse_socket_bind, "SOCKETBIND" },
2486 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2487 { config_parse_usec, "SECONDS" },
2488 { config_parse_nsec, "NANOSECONDS" },
2489 { config_parse_path_strv, "PATH [...]" },
2490 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2491 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2492 { config_parse_unit_string_printf, "STRING" },
2493 { config_parse_timer, "TIMER" },
2494 { config_parse_timer_unit, "NAME" },
2495 { config_parse_path_spec, "PATH" },
2496 { config_parse_path_unit, "UNIT" },
2497 { config_parse_notify_access, "ACCESS" },
2498 { config_parse_ip_tos, "TOS" },
2499 { config_parse_unit_condition_path, "CONDITION" },
2500 { config_parse_unit_condition_string, "CONDITION" },
2501 { config_parse_unit_condition_null, "CONDITION" },
2504 const char *prev = NULL;
2509 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2510 const char *rvalue = "OTHER", *lvalue;
2514 const ConfigPerfItem *p;
2516 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2518 dot = strchr(i, '.');
2519 lvalue = dot ? dot + 1 : i;
2523 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2527 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2530 for (j = 0; j < ELEMENTSOF(table); j++)
2531 if (p->parse == table[j].callback) {
2532 rvalue = table[j].rvalue;
2536 fprintf(f, "%s=%s\n", lvalue, rvalue);