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) {
96 k = unit_name_printf(u, t);
101 r = unit_add_dependency_by_name(u, d, k, NULL, true);
103 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
111 int config_parse_unit_string_printf(
112 const char *filename,
130 k = unit_full_printf(u, rvalue);
134 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
140 int config_parse_unit_strv_printf(
141 const char *filename,
159 k = unit_full_printf(u, rvalue);
163 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
169 int config_parse_unit_path_printf(
170 const char *filename,
188 k = unit_full_printf(u, rvalue);
192 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
198 int config_parse_socket_listen(
199 const char *filename,
208 SocketPort *p, *tail;
218 p = new0(SocketPort, 1);
222 if (streq(lvalue, "ListenFIFO")) {
223 p->type = SOCKET_FIFO;
225 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
230 path_kill_slashes(p->path);
232 } else if (streq(lvalue, "ListenSpecial")) {
233 p->type = SOCKET_SPECIAL;
235 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
240 path_kill_slashes(p->path);
242 } else if (streq(lvalue, "ListenMessageQueue")) {
244 p->type = SOCKET_MQUEUE;
246 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
251 path_kill_slashes(p->path);
253 } else if (streq(lvalue, "ListenNetlink")) {
257 p->type = SOCKET_SOCKET;
258 k = unit_full_printf(UNIT(s), rvalue);
259 r = socket_address_parse_netlink(&p->address, k);
263 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
272 p->type = SOCKET_SOCKET;
273 k = unit_full_printf(UNIT(s), rvalue);
274 r = socket_address_parse(&p->address, k);
278 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
283 if (streq(lvalue, "ListenStream"))
284 p->address.type = SOCK_STREAM;
285 else if (streq(lvalue, "ListenDatagram"))
286 p->address.type = SOCK_DGRAM;
288 assert(streq(lvalue, "ListenSequentialPacket"));
289 p->address.type = SOCK_SEQPACKET;
292 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
293 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
302 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
303 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
305 LIST_PREPEND(SocketPort, port, s->ports, p);
310 int config_parse_socket_bind(
311 const char *filename,
321 SocketAddressBindIPv6Only b;
330 b = socket_address_bind_ipv6_only_from_string(rvalue);
334 r = parse_boolean(rvalue);
336 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
340 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
342 s->bind_ipv6_only = b;
347 int config_parse_exec_nice(
348 const char *filename,
357 ExecContext *c = data;
365 if (safe_atoi(rvalue, &priority) < 0) {
366 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
370 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
371 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
381 int config_parse_exec_oom_score_adjust(
382 const char *filename,
391 ExecContext *c = data;
399 if (safe_atoi(rvalue, &oa) < 0) {
400 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
404 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
405 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
409 c->oom_score_adjust = oa;
410 c->oom_score_adjust_set = true;
415 int config_parse_exec(
416 const char *filename,
425 ExecCommand **e = data, *nce;
435 /* We accept an absolute path as first argument, or
436 * alternatively an absolute prefixed with @ to allow
437 * overriding of argv[0]. */
446 bool honour_argv0 = false, ignore = false;
452 rvalue += strspn(rvalue, WHITESPACE);
457 for (i = 0; i < 2; i++) {
458 if (rvalue[0] == '-' && !ignore) {
463 if (rvalue[0] == '@' && !honour_argv0) {
469 if (*rvalue != '/') {
470 log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
471 filename, line, rvalue);
476 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
477 if (strncmp(w, ";", MAX(l, 1U)) == 0)
483 n = new(char*, k + !honour_argv0);
488 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
489 if (strncmp(w, ";", MAX(l, 1U)) == 0)
491 else if (strncmp(w, "\\;", MAX(l, 1U)) == 0)
494 if (honour_argv0 && w == rvalue) {
497 path = strndup(w, l);
503 if (!utf8_is_valid(path)) {
504 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
512 c = n[k++] = cunescape_length(w, l);
518 if (!utf8_is_valid(c)) {
519 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
529 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
542 assert(path_is_absolute(path));
544 nce = new0(ExecCommand, 1);
552 nce->ignore = ignore;
554 path_kill_slashes(nce->path);
556 exec_command_append_list(e, nce);
572 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
573 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
575 int config_parse_socket_bindtodevice(
576 const char *filename,
593 if (rvalue[0] && !streq(rvalue, "*")) {
594 if (!(n = strdup(rvalue)))
599 free(s->bind_to_device);
600 s->bind_to_device = n;
605 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
606 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
608 int config_parse_exec_io_class(
609 const char *filename,
618 ExecContext *c = data;
626 x = ioprio_class_from_string(rvalue);
628 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
632 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
633 c->ioprio_set = true;
638 int config_parse_exec_io_priority(
639 const char *filename,
648 ExecContext *c = data;
656 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
657 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
661 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
662 c->ioprio_set = true;
667 int config_parse_exec_cpu_sched_policy(
668 const char *filename,
678 ExecContext *c = data;
686 x = sched_policy_from_string(rvalue);
688 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
692 c->cpu_sched_policy = x;
693 /* Moving to or from real-time policy? We need to adjust the priority */
694 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
695 c->cpu_sched_set = true;
700 int config_parse_exec_cpu_sched_prio(
701 const char *filename,
710 ExecContext *c = data;
718 if (safe_atoi(rvalue, &i) < 0) {
719 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
724 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
725 min = sched_get_priority_min(c->cpu_sched_policy);
726 max = sched_get_priority_max(c->cpu_sched_policy);
728 if (i < min || i > max) {
729 log_error("[%s:%u] CPU scheduling priority is out of range, ignoring: %s", filename, line, rvalue);
733 c->cpu_sched_priority = i;
734 c->cpu_sched_set = true;
739 int config_parse_exec_cpu_affinity(
740 const char *filename,
749 ExecContext *c = data;
759 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
764 if (!(t = strndup(w, l)))
767 r = safe_atou(t, &cpu);
771 if (!(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, ignoring: %s", filename, line, rvalue);
779 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
785 int config_parse_exec_capabilities(
786 const char *filename,
795 ExecContext *c = data;
803 if (!(cap = cap_from_text(rvalue))) {
807 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
812 cap_free(c->capabilities);
813 c->capabilities = cap;
818 int config_parse_exec_secure_bits(
819 const char *filename,
828 ExecContext *c = data;
838 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
839 if (first_word(w, "keep-caps"))
840 c->secure_bits |= SECURE_KEEP_CAPS;
841 else if (first_word(w, "keep-caps-locked"))
842 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
843 else if (first_word(w, "no-setuid-fixup"))
844 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
845 else if (first_word(w, "no-setuid-fixup-locked"))
846 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
847 else if (first_word(w, "noroot"))
848 c->secure_bits |= SECURE_NOROOT;
849 else if (first_word(w, "noroot-locked"))
850 c->secure_bits |= SECURE_NOROOT_LOCKED;
852 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
860 int config_parse_bounding_set(
861 const char *filename,
870 uint64_t *capability_bounding_set_drop = data;
882 if (rvalue[0] == '~') {
887 /* Note that we store this inverted internally, since the
888 * kernel wants it like this. But we actually expose it
889 * non-inverted everywhere to have a fully normalized
892 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
901 r = cap_from_name(t, &cap);
905 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
909 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
913 *capability_bounding_set_drop |= sum;
915 *capability_bounding_set_drop |= ~sum;
920 int config_parse_limit(
921 const char *filename,
930 struct rlimit **rl = data;
931 unsigned long long u;
940 if (streq(rvalue, "infinity"))
941 u = (unsigned long long) RLIM_INFINITY;
942 else if (safe_atollu(rvalue, &u) < 0) {
943 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
948 if (!(*rl = new(struct rlimit, 1)))
951 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
955 int config_parse_unit_cgroup(
956 const char *filename,
970 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
978 k = unit_full_printf(u, t);
990 r = unit_add_cgroup_from_text(u, t);
994 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
1002 #ifdef HAVE_SYSV_COMPAT
1003 int config_parse_sysv_priority(
1004 const char *filename,
1006 const char *section,
1013 int *priority = data;
1021 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1022 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1026 *priority = (int) i;
1031 int config_parse_fsck_passno(
1032 const char *filename,
1034 const char *section,
1049 if (safe_atoi(rvalue, &i) || i < 0) {
1050 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1058 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1060 int config_parse_kill_signal(
1061 const char *filename,
1063 const char *section,
1078 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1079 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1087 int config_parse_exec_mount_flags(
1088 const char *filename,
1090 const char *section,
1097 ExecContext *c = data;
1101 unsigned long flags = 0;
1108 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1109 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1111 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1113 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1114 flags |= MS_PRIVATE;
1116 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1121 c->mount_flags = flags;
1125 int config_parse_timer(
1126 const char *filename,
1128 const char *section,
1145 if ((b = timer_base_from_string(lvalue)) < 0) {
1146 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1150 if (parse_usec(rvalue, &u) < 0) {
1151 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1155 if (!(v = new0(TimerValue, 1)))
1161 LIST_PREPEND(TimerValue, value, t->values, v);
1166 int config_parse_timer_unit(
1167 const char *filename,
1169 const char *section,
1186 dbus_error_init(&error);
1188 if (endswith(rvalue, ".timer")) {
1189 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1193 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1195 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1196 dbus_error_free(&error);
1200 unit_ref_set(&t->unit, u);
1205 int config_parse_path_spec(
1206 const char *filename,
1208 const char *section,
1225 b = path_type_from_string(lvalue);
1227 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1231 k = unit_full_printf(UNIT(p), rvalue);
1235 if (!path_is_absolute(k)) {
1236 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1241 s = new0(PathSpec, 1);
1247 s->path = path_kill_slashes(k);
1251 LIST_PREPEND(PathSpec, spec, p->specs, s);
1256 int config_parse_path_unit(
1257 const char *filename,
1259 const char *section,
1276 dbus_error_init(&error);
1278 if (endswith(rvalue, ".path")) {
1279 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1283 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1284 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1285 dbus_error_free(&error);
1289 unit_ref_set(&t->unit, u);
1294 int config_parse_socket_service(
1295 const char *filename,
1297 const char *section,
1314 dbus_error_init(&error);
1316 if (!endswith(rvalue, ".service")) {
1317 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1321 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1323 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1324 dbus_error_free(&error);
1328 unit_ref_set(&s->service, x);
1333 int config_parse_service_sockets(
1334 const char *filename,
1336 const char *section,
1353 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1360 k = unit_name_printf(UNIT(s), t);
1366 if (!endswith(k, ".socket")) {
1367 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1372 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1374 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1376 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1386 int config_parse_service_timeout(
1387 const char *filename,
1389 const char *section,
1396 Service *s = userdata;
1404 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1409 if (streq(lvalue, "TimeoutSec")) {
1410 s->start_timeout_defined = true;
1411 s->timeout_stop_usec = s->timeout_start_usec;
1412 } else if (streq(lvalue, "TimeoutStartSec"))
1413 s->start_timeout_defined = true;
1418 int config_parse_unit_env_file(
1419 const char *filename,
1421 const char *section,
1428 char ***env = data, **k;
1437 s = unit_full_printf(u, rvalue);
1441 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1442 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1447 k = strv_append(*env, s);
1458 int config_parse_ip_tos(
1459 const char *filename,
1461 const char *section,
1468 int *ip_tos = data, x;
1475 x = ip_tos_from_string(rvalue);
1477 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1485 int config_parse_unit_condition_path(
1486 const char *filename,
1488 const char *section,
1495 ConditionType cond = ltype;
1497 bool trigger, negate;
1499 _cleanup_free_ char *p = NULL;
1506 trigger = rvalue[0] == '|';
1510 negate = rvalue[0] == '!';
1514 p = unit_full_printf(u, rvalue);
1518 if (!path_is_absolute(p)) {
1519 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1523 c = condition_new(cond, p, trigger, negate);
1527 LIST_PREPEND(Condition, conditions, u->conditions, c);
1531 int config_parse_unit_condition_string(
1532 const char *filename,
1534 const char *section,
1541 ConditionType cond = ltype;
1543 bool trigger, negate;
1545 _cleanup_free_ char *s = NULL;
1552 trigger = rvalue[0] == '|';
1556 negate = rvalue[0] == '!';
1560 s = unit_full_printf(u, rvalue);
1564 c = condition_new(cond, s, trigger, negate);
1568 LIST_PREPEND(Condition, conditions, u->conditions, c);
1572 int config_parse_unit_condition_null(
1573 const char *filename,
1575 const char *section,
1584 bool trigger, negate;
1592 if ((trigger = rvalue[0] == '|'))
1595 if ((negate = rvalue[0] == '!'))
1598 if ((b = parse_boolean(rvalue)) < 0) {
1599 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1606 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1609 LIST_PREPEND(Condition, conditions, u->conditions, c);
1613 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1614 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1616 int config_parse_unit_cgroup_attr(
1617 const char *filename,
1619 const char *section,
1635 l = strv_split_quoted(rvalue);
1639 if (strv_length(l) != 2) {
1640 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1645 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1649 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1656 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) {
1667 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1668 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1672 if (asprintf(&t, "%lu", ul) < 0)
1675 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1679 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1686 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) {
1697 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1698 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1702 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1705 r = unit_add_cgroup_attribute(u,
1707 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1712 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1719 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1727 l = strv_split_quoted(value);
1731 assert(strv_length(l) >= 1);
1733 if (streq(l[0], "*")) {
1735 if (asprintf(ret, "a *:*%s%s",
1736 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1744 if (stat(l[0], &st) < 0) {
1745 log_warning("Couldn't stat device %s", l[0]);
1750 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1751 log_warning("%s is not a device.", l[0]);
1756 if (asprintf(ret, "%c %u:%u%s%s",
1757 S_ISCHR(st.st_mode) ? 'c' : 'b',
1758 major(st.st_rdev), minor(st.st_rdev),
1759 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1770 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) {
1781 l = strv_split_quoted(rvalue);
1786 if (k < 1 || k > 2) {
1787 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1792 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1793 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1798 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1799 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1805 r = unit_add_cgroup_attribute(u, "devices",
1806 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1807 rvalue, device_map);
1810 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1817 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1827 l = strv_split_quoted(value);
1831 assert(strv_length(l) == 2);
1833 if (stat(l[0], &st) < 0) {
1834 log_warning("Couldn't stat device %s", l[0]);
1839 if (S_ISBLK(st.st_mode))
1841 else if (major(st.st_dev) != 0) {
1842 /* If this is not a device node then find the block
1843 * device this file is stored on */
1846 /* If this is a partition, try to get the originating
1848 block_get_whole_disk(d, &d);
1850 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1855 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1864 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) {
1868 const char *device = NULL, *weight;
1877 l = strv_split_quoted(rvalue);
1882 if (k < 1 || k > 2) {
1883 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1895 if (device && !path_is_absolute(device)) {
1896 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1901 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1902 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1908 r = asprintf(&t, "%s %lu", device, ul);
1910 r = asprintf(&t, "%lu", ul);
1917 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1919 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1923 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1930 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) {
1942 l = strv_split_quoted(rvalue);
1948 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1953 if (!path_is_absolute(l[0])) {
1954 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1959 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1960 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1965 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1971 r = unit_add_cgroup_attribute(u, "blkio",
1972 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1977 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1984 int config_parse_unit_requires_mounts_for(
1985 const char *filename,
1987 const char *section,
2003 empty_before = !u->requires_mounts_for;
2005 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2007 /* Make it easy to find units with requires_mounts set */
2008 if (empty_before && u->requires_mounts_for)
2009 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2014 int config_parse_documentation(
2015 const char *filename,
2017 const char *section,
2033 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2037 for (a = b = u->documentation; a && *a; a++) {
2039 if (is_valid_documentation_url(*a))
2042 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2051 static void syscall_set(uint32_t *p, int nr) {
2052 p[nr >> 4] |= 1 << (nr & 31);
2055 static void syscall_unset(uint32_t *p, int nr) {
2056 p[nr >> 4] &= ~(1 << (nr & 31));
2059 int config_parse_syscall_filter(
2060 const char *filename,
2062 const char *section,
2069 ExecContext *c = data;
2071 bool invert = false;
2081 if (rvalue[0] == '~') {
2086 if (!c->syscall_filter) {
2089 n = (syscall_max() + 31) >> 4;
2090 c->syscall_filter = new(uint32_t, n);
2091 if (!c->syscall_filter)
2094 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2096 /* Add these by default */
2097 syscall_set(c->syscall_filter, __NR_execve);
2098 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2099 #ifdef __NR_sigreturn
2100 syscall_set(c->syscall_filter, __NR_sigreturn);
2102 syscall_set(c->syscall_filter, __NR_exit_group);
2103 syscall_set(c->syscall_filter, __NR_exit);
2106 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2114 id = syscall_from_name(t);
2118 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2123 syscall_unset(c->syscall_filter, id);
2125 syscall_set(c->syscall_filter, id);
2128 c->no_new_privileges = true;
2133 #define FOLLOW_MAX 8
2135 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2146 /* This will update the filename pointer if the loaded file is
2147 * reached by a symlink. The old string will be freed. */
2150 char *target, *name;
2152 if (c++ >= FOLLOW_MAX)
2155 path_kill_slashes(*filename);
2157 /* Add the file name we are currently looking at to
2158 * the names of this unit, but only if it is a valid
2160 name = path_get_file_name(*filename);
2162 if (unit_name_is_valid(name, true)) {
2164 id = set_get(names, name);
2170 r = set_put(names, id);
2178 /* Try to open the file name, but don't if its a symlink */
2179 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2186 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2187 r = readlink_and_make_absolute(*filename, &target);
2195 f = fdopen(fd, "re");
2198 close_nointr_nofail(fd);
2207 static int merge_by_names(Unit **u, Set *names, const char *id) {
2215 /* Let's try to add in all symlink names we found */
2216 while ((k = set_steal_first(names))) {
2218 /* First try to merge in the other name into our
2220 r = unit_merge_by_name(*u, k);
2224 /* Hmm, we couldn't merge the other unit into
2225 * ours? Then let's try it the other way
2228 other = manager_get_unit((*u)->manager, k);
2232 r = unit_merge(other, *u);
2235 return merge_by_names(u, names, NULL);
2243 unit_choose_id(*u, id);
2251 static int load_from_path(Unit *u, const char *path) {
2255 char *filename = NULL, *id = NULL;
2262 symlink_names = set_new(string_hash_func, string_compare_func);
2266 if (path_is_absolute(path)) {
2268 filename = strdup(path);
2274 r = open_follow(&filename, &f, symlink_names, &id);
2286 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2288 /* Instead of opening the path right away, we manually
2289 * follow all symlinks and add their name to our unit
2290 * name set while doing so */
2291 filename = path_make_absolute(path, *p);
2297 if (u->manager->unit_path_cache &&
2298 !set_get(u->manager->unit_path_cache, filename))
2301 r = open_follow(&filename, &f, symlink_names, &id);
2310 /* Empty the symlink names for the next run */
2311 set_clear_free(symlink_names);
2320 /* Hmm, no suitable file found? */
2326 r = merge_by_names(&merged, symlink_names, id);
2331 u->load_state = UNIT_MERGED;
2336 if (fstat(fileno(f), &st) < 0) {
2341 if (null_or_empty(&st))
2342 u->load_state = UNIT_MASKED;
2344 /* Now, parse the file contents */
2345 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2349 u->load_state = UNIT_LOADED;
2352 free(u->fragment_path);
2353 u->fragment_path = filename;
2356 u->fragment_mtime = timespec_load(&st.st_mtim);
2358 if (u->source_path) {
2359 if (stat(u->source_path, &st) >= 0)
2360 u->source_mtime = timespec_load(&st.st_mtim);
2362 u->source_mtime = 0;
2368 set_free_free(symlink_names);
2377 int unit_load_fragment(Unit *u) {
2383 assert(u->load_state == UNIT_STUB);
2386 /* First, try to find the unit under its id. We always look
2387 * for unit files in the default directories, to make it easy
2388 * to override things by placing things in /etc/systemd/system */
2389 r = load_from_path(u, u->id);
2393 /* Try to find an alias we can load this with */
2394 if (u->load_state == UNIT_STUB)
2395 SET_FOREACH(t, u->names, i) {
2400 r = load_from_path(u, t);
2404 if (u->load_state != UNIT_STUB)
2408 /* And now, try looking for it under the suggested (originally linked) path */
2409 if (u->load_state == UNIT_STUB && u->fragment_path) {
2411 r = load_from_path(u, u->fragment_path);
2415 if (u->load_state == UNIT_STUB) {
2416 /* Hmm, this didn't work? Then let's get rid
2417 * of the fragment path stored for us, so that
2418 * we don't point to an invalid location. */
2419 free(u->fragment_path);
2420 u->fragment_path = NULL;
2424 /* Look for a template */
2425 if (u->load_state == UNIT_STUB && u->instance) {
2428 k = unit_name_template(u->id);
2432 r = load_from_path(u, k);
2438 if (u->load_state == UNIT_STUB)
2439 SET_FOREACH(t, u->names, i) {
2444 k = unit_name_template(t);
2448 r = load_from_path(u, k);
2454 if (u->load_state != UNIT_STUB)
2462 void unit_dump_config_items(FILE *f) {
2463 static const struct {
2464 const ConfigParserCallback callback;
2467 { config_parse_int, "INTEGER" },
2468 { config_parse_unsigned, "UNSIGNED" },
2469 { config_parse_bytes_size, "SIZE" },
2470 { config_parse_bool, "BOOLEAN" },
2471 { config_parse_string, "STRING" },
2472 { config_parse_path, "PATH" },
2473 { config_parse_unit_path_printf, "PATH" },
2474 { config_parse_strv, "STRING [...]" },
2475 { config_parse_exec_nice, "NICE" },
2476 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2477 { config_parse_exec_io_class, "IOCLASS" },
2478 { config_parse_exec_io_priority, "IOPRIORITY" },
2479 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2480 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2481 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2482 { config_parse_mode, "MODE" },
2483 { config_parse_unit_env_file, "FILE" },
2484 { config_parse_output, "OUTPUT" },
2485 { config_parse_input, "INPUT" },
2486 { config_parse_facility, "FACILITY" },
2487 { config_parse_level, "LEVEL" },
2488 { config_parse_exec_capabilities, "CAPABILITIES" },
2489 { config_parse_exec_secure_bits, "SECUREBITS" },
2490 { config_parse_bounding_set, "BOUNDINGSET" },
2491 { config_parse_limit, "LIMIT" },
2492 { config_parse_unit_cgroup, "CGROUP [...]" },
2493 { config_parse_unit_deps, "UNIT [...]" },
2494 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2495 { config_parse_service_type, "SERVICETYPE" },
2496 { config_parse_service_restart, "SERVICERESTART" },
2497 #ifdef HAVE_SYSV_COMPAT
2498 { config_parse_sysv_priority, "SYSVPRIORITY" },
2500 { config_parse_warn_compat, "NOTSUPPORTED" },
2502 { config_parse_kill_mode, "KILLMODE" },
2503 { config_parse_kill_signal, "SIGNAL" },
2504 { config_parse_socket_listen, "SOCKET [...]" },
2505 { config_parse_socket_bind, "SOCKETBIND" },
2506 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2507 { config_parse_usec, "SECONDS" },
2508 { config_parse_nsec, "NANOSECONDS" },
2509 { config_parse_path_strv, "PATH [...]" },
2510 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2511 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2512 { config_parse_unit_string_printf, "STRING" },
2513 { config_parse_timer, "TIMER" },
2514 { config_parse_timer_unit, "NAME" },
2515 { config_parse_path_spec, "PATH" },
2516 { config_parse_path_unit, "UNIT" },
2517 { config_parse_notify_access, "ACCESS" },
2518 { config_parse_ip_tos, "TOS" },
2519 { config_parse_unit_condition_path, "CONDITION" },
2520 { config_parse_unit_condition_string, "CONDITION" },
2521 { config_parse_unit_condition_null, "CONDITION" },
2524 const char *prev = NULL;
2529 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2530 const char *rvalue = "OTHER", *lvalue;
2534 const ConfigPerfItem *p;
2536 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2538 dot = strchr(i, '.');
2539 lvalue = dot ? dot + 1 : i;
2543 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2547 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2550 for (j = 0; j < ELEMENTSOF(table); j++)
2551 if (p->parse == table[j].callback) {
2552 rvalue = table[j].rvalue;
2556 fprintf(f, "%s=%s\n", lvalue, rvalue);