1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/oom.h>
29 #include <sys/prctl.h>
30 #include <sys/mount.h>
34 #include <sys/resource.h>
38 #include "conf-parser.h"
39 #include "load-fragment.h"
42 #include "securebits.h"
44 #include "unit-name.h"
45 #include "bus-errors.h"
48 #ifndef HAVE_SYSV_COMPAT
49 int config_parse_warn_compat(
59 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
64 int config_parse_unit_deps(
74 UnitDependency d = ltype;
84 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
92 k = unit_name_printf(u, t);
97 r = unit_add_dependency_by_name(u, d, k, NULL, true);
99 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
107 int config_parse_unit_names(
108 const char *filename,
127 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
135 k = unit_name_printf(u, t);
140 r = unit_merge_by_name(u, k);
142 log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
150 int config_parse_unit_string_printf(
151 const char *filename,
169 k = unit_full_printf(u, rvalue);
173 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
179 int config_parse_unit_strv_printf(
180 const char *filename,
198 k = unit_full_printf(u, rvalue);
202 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
208 int config_parse_unit_path_printf(
209 const char *filename,
227 k = unit_full_printf(u, rvalue);
231 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
237 int config_parse_socket_listen(
238 const char *filename,
247 SocketPort *p, *tail;
257 p = new0(SocketPort, 1);
261 if (streq(lvalue, "ListenFIFO")) {
262 p->type = SOCKET_FIFO;
264 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
269 path_kill_slashes(p->path);
271 } else if (streq(lvalue, "ListenSpecial")) {
272 p->type = SOCKET_SPECIAL;
274 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
279 path_kill_slashes(p->path);
281 } else if (streq(lvalue, "ListenMessageQueue")) {
283 p->type = SOCKET_MQUEUE;
285 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
290 path_kill_slashes(p->path);
292 } else if (streq(lvalue, "ListenNetlink")) {
296 p->type = SOCKET_SOCKET;
297 k = unit_full_printf(UNIT(s), rvalue);
298 r = socket_address_parse_netlink(&p->address, k);
302 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
311 p->type = SOCKET_SOCKET;
312 k = unit_full_printf(UNIT(s), rvalue);
313 r = socket_address_parse(&p->address, k);
317 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
322 if (streq(lvalue, "ListenStream"))
323 p->address.type = SOCK_STREAM;
324 else if (streq(lvalue, "ListenDatagram"))
325 p->address.type = SOCK_DGRAM;
327 assert(streq(lvalue, "ListenSequentialPacket"));
328 p->address.type = SOCK_SEQPACKET;
331 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
332 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
341 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
342 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
344 LIST_PREPEND(SocketPort, port, s->ports, p);
349 int config_parse_socket_bind(
350 const char *filename,
360 SocketAddressBindIPv6Only b;
369 if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
372 if ((r = parse_boolean(rvalue)) < 0) {
373 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
377 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
379 s->bind_ipv6_only = b;
384 int config_parse_exec_nice(
385 const char *filename,
394 ExecContext *c = data;
402 if (safe_atoi(rvalue, &priority) < 0) {
403 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
407 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
408 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
418 int config_parse_exec_oom_score_adjust(
419 const char *filename,
428 ExecContext *c = data;
436 if (safe_atoi(rvalue, &oa) < 0) {
437 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
441 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
442 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
446 c->oom_score_adjust = oa;
447 c->oom_score_adjust_set = true;
452 int config_parse_exec(
453 const char *filename,
462 ExecCommand **e = data, *nce;
472 /* We accept an absolute path as first argument, or
473 * alternatively an absolute prefixed with @ to allow
474 * overriding of argv[0]. */
482 bool honour_argv0 = false, ignore = false;
488 rvalue += strspn(rvalue, WHITESPACE);
493 if (rvalue[0] == '-') {
498 if (rvalue[0] == '@') {
503 if (*rvalue != '/') {
504 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
509 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
510 if (strncmp(w, ";", MAX(l, 1U)) == 0)
516 n = new(char*, k + !honour_argv0);
521 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
522 if (strncmp(w, ";", MAX(l, 1U)) == 0)
525 if (honour_argv0 && w == rvalue) {
528 path = strndup(w, l);
534 if (!utf8_is_valid(path)) {
535 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
543 c = n[k++] = cunescape_length(w, l);
549 if (!utf8_is_valid(c)) {
550 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
560 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
573 assert(path_is_absolute(path));
575 nce = new0(ExecCommand, 1);
583 nce->ignore = ignore;
585 path_kill_slashes(nce->path);
587 exec_command_append_list(e, nce);
603 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
604 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
606 int config_parse_socket_bindtodevice(
607 const char *filename,
624 if (rvalue[0] && !streq(rvalue, "*")) {
625 if (!(n = strdup(rvalue)))
630 free(s->bind_to_device);
631 s->bind_to_device = n;
636 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
637 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
639 int config_parse_facility(
640 const char *filename,
657 if ((x = log_facility_unshifted_from_string(rvalue)) < 0) {
658 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
662 *o = (x << 3) | LOG_PRI(*o);
667 int config_parse_level(
668 const char *filename,
685 if ((x = log_level_from_string(rvalue)) < 0) {
686 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
690 *o = (*o & LOG_FACMASK) | x;
694 int config_parse_exec_io_class(
695 const char *filename,
704 ExecContext *c = data;
712 if ((x = ioprio_class_from_string(rvalue)) < 0) {
713 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
717 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
718 c->ioprio_set = true;
723 int config_parse_exec_io_priority(
724 const char *filename,
733 ExecContext *c = data;
741 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
742 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
746 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
747 c->ioprio_set = true;
752 int config_parse_exec_cpu_sched_policy(
753 const char *filename,
763 ExecContext *c = data;
771 if ((x = sched_policy_from_string(rvalue)) < 0) {
772 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
776 c->cpu_sched_policy = x;
777 c->cpu_sched_set = true;
782 int config_parse_exec_cpu_sched_prio(
783 const char *filename,
792 ExecContext *c = data;
800 /* On Linux RR/FIFO have the same range */
801 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
802 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
806 c->cpu_sched_priority = i;
807 c->cpu_sched_set = true;
812 int config_parse_exec_cpu_affinity(
813 const char *filename,
822 ExecContext *c = data;
832 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
837 if (!(t = strndup(w, l)))
840 r = safe_atou(t, &cpu);
844 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
847 if (r < 0 || cpu >= c->cpuset_ncpus) {
848 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
852 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
858 int config_parse_exec_capabilities(
859 const char *filename,
868 ExecContext *c = data;
876 if (!(cap = cap_from_text(rvalue))) {
880 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
885 cap_free(c->capabilities);
886 c->capabilities = cap;
891 int config_parse_exec_secure_bits(
892 const char *filename,
901 ExecContext *c = data;
911 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
912 if (first_word(w, "keep-caps"))
913 c->secure_bits |= SECURE_KEEP_CAPS;
914 else if (first_word(w, "keep-caps-locked"))
915 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
916 else if (first_word(w, "no-setuid-fixup"))
917 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
918 else if (first_word(w, "no-setuid-fixup-locked"))
919 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
920 else if (first_word(w, "noroot"))
921 c->secure_bits |= SECURE_NOROOT;
922 else if (first_word(w, "noroot-locked"))
923 c->secure_bits |= SECURE_NOROOT_LOCKED;
925 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
933 int config_parse_exec_bounding_set(
934 const char *filename,
943 ExecContext *c = data;
955 if (rvalue[0] == '~') {
960 /* Note that we store this inverted internally, since the
961 * kernel wants it like this. But we actually expose it
962 * non-inverted everywhere to have a fully normalized
965 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
970 if (!(t = strndup(w, l)))
973 r = cap_from_name(t, &cap);
977 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
981 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
985 c->capability_bounding_set_drop |= sum;
987 c->capability_bounding_set_drop |= ~sum;
992 int config_parse_exec_timer_slack_nsec(
993 const char *filename,
1002 ExecContext *c = data;
1010 if (safe_atolu(rvalue, &u) < 0) {
1011 log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue);
1015 c->timer_slack_nsec = u;
1020 int config_parse_limit(
1021 const char *filename,
1023 const char *section,
1030 struct rlimit **rl = data;
1031 unsigned long long u;
1040 if (streq(rvalue, "infinity"))
1041 u = (unsigned long long) RLIM_INFINITY;
1042 else if (safe_atollu(rvalue, &u) < 0) {
1043 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
1048 if (!(*rl = new(struct rlimit, 1)))
1051 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1055 int config_parse_unit_cgroup(
1056 const char *filename,
1058 const char *section,
1070 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1078 k = unit_full_printf(u, t);
1090 r = unit_add_cgroup_from_text(u, t);
1094 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
1102 #ifdef HAVE_SYSV_COMPAT
1103 int config_parse_sysv_priority(
1104 const char *filename,
1106 const char *section,
1113 int *priority = data;
1121 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1122 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1126 *priority = (int) i;
1131 int config_parse_fsck_passno(
1132 const char *filename,
1134 const char *section,
1149 if (safe_atoi(rvalue, &i) || i < 0) {
1150 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1158 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1160 int config_parse_kill_signal(
1161 const char *filename,
1163 const char *section,
1178 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1179 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1187 int config_parse_exec_mount_flags(
1188 const char *filename,
1190 const char *section,
1197 ExecContext *c = data;
1201 unsigned long flags = 0;
1208 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1209 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1211 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1213 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1214 flags |= MS_PRIVATE;
1216 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1221 c->mount_flags = flags;
1225 int config_parse_timer(
1226 const char *filename,
1228 const char *section,
1245 if ((b = timer_base_from_string(lvalue)) < 0) {
1246 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1250 if (parse_usec(rvalue, &u) < 0) {
1251 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1255 if (!(v = new0(TimerValue, 1)))
1261 LIST_PREPEND(TimerValue, value, t->values, v);
1266 int config_parse_timer_unit(
1267 const char *filename,
1269 const char *section,
1286 dbus_error_init(&error);
1288 if (endswith(rvalue, ".timer")) {
1289 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1293 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1295 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1296 dbus_error_free(&error);
1300 unit_ref_set(&t->unit, u);
1305 int config_parse_path_spec(
1306 const char *filename,
1308 const char *section,
1324 if ((b = path_type_from_string(lvalue)) < 0) {
1325 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1329 if (!path_is_absolute(rvalue)) {
1330 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1334 if (!(s = new0(PathSpec, 1)))
1337 if (!(s->path = strdup(rvalue))) {
1342 path_kill_slashes(s->path);
1347 LIST_PREPEND(PathSpec, spec, p->specs, s);
1352 int config_parse_path_unit(
1353 const char *filename,
1355 const char *section,
1372 dbus_error_init(&error);
1374 if (endswith(rvalue, ".path")) {
1375 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1379 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1380 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1381 dbus_error_free(&error);
1385 unit_ref_set(&t->unit, u);
1390 int config_parse_socket_service(
1391 const char *filename,
1393 const char *section,
1410 dbus_error_init(&error);
1412 if (!endswith(rvalue, ".service")) {
1413 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1417 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1419 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1420 dbus_error_free(&error);
1424 unit_ref_set(&s->service, x);
1429 int config_parse_service_sockets(
1430 const char *filename,
1432 const char *section,
1449 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1456 k = unit_name_printf(UNIT(s), t);
1462 if (!endswith(k, ".socket")) {
1463 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1468 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1470 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1472 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1482 int config_parse_unit_env_file(
1483 const char *filename,
1485 const char *section,
1492 char ***env = data, **k;
1501 s = unit_full_printf(u, rvalue);
1505 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1506 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1511 k = strv_append(*env, s);
1522 int config_parse_ip_tos(
1523 const char *filename,
1525 const char *section,
1532 int *ip_tos = data, x;
1539 if ((x = ip_tos_from_string(rvalue)) < 0)
1540 if (safe_atoi(rvalue, &x) < 0) {
1541 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1549 int config_parse_unit_condition_path(
1550 const char *filename,
1552 const char *section,
1559 ConditionType cond = ltype;
1561 bool trigger, negate;
1569 trigger = rvalue[0] == '|';
1573 negate = rvalue[0] == '!';
1577 if (!path_is_absolute(rvalue)) {
1578 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1582 c = condition_new(cond, rvalue, trigger, negate);
1586 LIST_PREPEND(Condition, conditions, u->conditions, c);
1590 int config_parse_unit_condition_string(
1591 const char *filename,
1593 const char *section,
1600 ConditionType cond = ltype;
1602 bool trigger, negate;
1610 if ((trigger = rvalue[0] == '|'))
1613 if ((negate = rvalue[0] == '!'))
1616 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1619 LIST_PREPEND(Condition, conditions, u->conditions, c);
1623 int config_parse_unit_condition_null(
1624 const char *filename,
1626 const char *section,
1635 bool trigger, negate;
1643 if ((trigger = rvalue[0] == '|'))
1646 if ((negate = rvalue[0] == '!'))
1649 if ((b = parse_boolean(rvalue)) < 0) {
1650 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1657 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1660 LIST_PREPEND(Condition, conditions, u->conditions, c);
1664 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1665 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1667 int config_parse_unit_cgroup_attr(
1668 const char *filename,
1670 const char *section,
1686 l = strv_split_quoted(rvalue);
1690 if (strv_length(l) != 2) {
1691 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1696 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1700 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1707 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) {
1718 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1719 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1723 if (asprintf(&t, "%lu", ul) < 0)
1726 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1730 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1737 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) {
1748 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1749 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1753 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1756 r = unit_add_cgroup_attribute(u,
1758 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1763 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1770 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1778 l = strv_split_quoted(value);
1782 assert(strv_length(l) >= 1);
1784 if (streq(l[0], "*")) {
1786 if (asprintf(ret, "a *:*%s%s",
1787 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1795 if (stat(l[0], &st) < 0) {
1796 log_warning("Couldn't stat device %s", l[0]);
1801 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1802 log_warning("%s is not a device.", l[0]);
1807 if (asprintf(ret, "%c %u:%u%s%s",
1808 S_ISCHR(st.st_mode) ? 'c' : 'b',
1809 major(st.st_rdev), minor(st.st_rdev),
1810 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1821 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) {
1832 l = strv_split_quoted(rvalue);
1837 if (k < 1 || k > 2) {
1838 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1843 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1844 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1849 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1850 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1856 r = unit_add_cgroup_attribute(u, "devices",
1857 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1858 rvalue, device_map);
1861 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1868 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1878 l = strv_split_quoted(value);
1882 assert(strv_length(l) == 2);
1884 if (stat(l[0], &st) < 0) {
1885 log_warning("Couldn't stat device %s", l[0]);
1890 if (S_ISBLK(st.st_mode))
1892 else if (major(st.st_dev) != 0) {
1893 /* If this is not a device node then find the block
1894 * device this file is stored on */
1897 /* If this is a partition, try to get the originating
1899 block_get_whole_disk(d, &d);
1901 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1906 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1915 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) {
1919 const char *device = NULL, *weight;
1928 l = strv_split_quoted(rvalue);
1933 if (k < 1 || k > 2) {
1934 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1946 if (device && !path_is_absolute(device)) {
1947 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1952 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1953 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1959 r = asprintf(&t, "%s %lu", device, ul);
1961 r = asprintf(&t, "%lu", ul);
1968 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1970 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1974 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1981 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) {
1993 l = strv_split_quoted(rvalue);
1999 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
2004 if (!path_is_absolute(l[0])) {
2005 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
2010 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
2011 log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
2016 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
2022 r = unit_add_cgroup_attribute(u, "blkio",
2023 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
2028 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
2036 #define FOLLOW_MAX 8
2038 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2049 /* This will update the filename pointer if the loaded file is
2050 * reached by a symlink. The old string will be freed. */
2053 char *target, *name;
2055 if (c++ >= FOLLOW_MAX)
2058 path_kill_slashes(*filename);
2060 /* Add the file name we are currently looking at to
2061 * the names of this unit, but only if it is a valid
2063 name = file_name_from_path(*filename);
2065 if (unit_name_is_valid(name, true)) {
2067 id = set_get(names, name);
2073 r = set_put(names, id);
2081 /* Try to open the file name, but don't if its a symlink */
2082 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
2088 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2089 if ((r = readlink_and_make_absolute(*filename, &target)) < 0)
2096 if (!(f = fdopen(fd, "re"))) {
2098 close_nointr_nofail(fd);
2107 static int merge_by_names(Unit **u, Set *names, const char *id) {
2115 /* Let's try to add in all symlink names we found */
2116 while ((k = set_steal_first(names))) {
2118 /* First try to merge in the other name into our
2120 if ((r = unit_merge_by_name(*u, k)) < 0) {
2123 /* Hmm, we couldn't merge the other unit into
2124 * ours? Then let's try it the other way
2127 other = manager_get_unit((*u)->manager, k);
2131 if ((r = unit_merge(other, *u)) >= 0) {
2133 return merge_by_names(u, names, NULL);
2140 unit_choose_id(*u, id);
2148 static int load_from_path(Unit *u, const char *path) {
2152 char *filename = NULL, *id = NULL;
2159 symlink_names = set_new(string_hash_func, string_compare_func);
2163 if (path_is_absolute(path)) {
2165 if (!(filename = strdup(path))) {
2170 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
2181 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2183 /* Instead of opening the path right away, we manually
2184 * follow all symlinks and add their name to our unit
2185 * name set while doing so */
2186 if (!(filename = path_make_absolute(path, *p))) {
2191 if (u->manager->unit_path_cache &&
2192 !set_get(u->manager->unit_path_cache, filename))
2195 r = open_follow(&filename, &f, symlink_names, &id);
2206 /* Empty the symlink names for the next run */
2207 while ((sn = set_steal_first(symlink_names)))
2218 /* Hmm, no suitable file found? */
2224 if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
2228 u->load_state = UNIT_MERGED;
2234 if (fstat(fileno(f), &st) < 0) {
2239 if (null_or_empty(&st))
2240 u->load_state = UNIT_MASKED;
2242 /* Now, parse the file contents */
2243 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2247 u->load_state = UNIT_LOADED;
2250 free(u->fragment_path);
2251 u->fragment_path = filename;
2254 u->fragment_mtime = timespec_load(&st.st_mtim);
2259 set_free_free(symlink_names);
2268 int unit_load_fragment(Unit *u) {
2274 assert(u->load_state == UNIT_STUB);
2277 /* First, try to find the unit under its id. We always look
2278 * for unit files in the default directories, to make it easy
2279 * to override things by placing things in /etc/systemd/system */
2280 if ((r = load_from_path(u, u->id)) < 0)
2283 /* Try to find an alias we can load this with */
2284 if (u->load_state == UNIT_STUB)
2285 SET_FOREACH(t, u->names, i) {
2290 if ((r = load_from_path(u, t)) < 0)
2293 if (u->load_state != UNIT_STUB)
2297 /* And now, try looking for it under the suggested (originally linked) path */
2298 if (u->load_state == UNIT_STUB && u->fragment_path) {
2300 if ((r = load_from_path(u, u->fragment_path)) < 0)
2303 if (u->load_state == UNIT_STUB) {
2304 /* Hmm, this didn't work? Then let's get rid
2305 * of the fragment path stored for us, so that
2306 * we don't point to an invalid location. */
2307 free(u->fragment_path);
2308 u->fragment_path = NULL;
2312 /* Look for a template */
2313 if (u->load_state == UNIT_STUB && u->instance) {
2316 if (!(k = unit_name_template(u->id)))
2319 r = load_from_path(u, k);
2325 if (u->load_state == UNIT_STUB)
2326 SET_FOREACH(t, u->names, i) {
2331 if (!(k = unit_name_template(t)))
2334 r = load_from_path(u, k);
2340 if (u->load_state != UNIT_STUB)
2348 void unit_dump_config_items(FILE *f) {
2349 static const struct {
2350 const ConfigParserCallback callback;
2353 { config_parse_int, "INTEGER" },
2354 { config_parse_unsigned, "UNSIGNED" },
2355 { config_parse_bytes_size, "SIZE" },
2356 { config_parse_bool, "BOOLEAN" },
2357 { config_parse_string, "STRING" },
2358 { config_parse_path, "PATH" },
2359 { config_parse_unit_path_printf, "PATH" },
2360 { config_parse_strv, "STRING [...]" },
2361 { config_parse_exec_nice, "NICE" },
2362 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2363 { config_parse_exec_io_class, "IOCLASS" },
2364 { config_parse_exec_io_priority, "IOPRIORITY" },
2365 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2366 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2367 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2368 { config_parse_mode, "MODE" },
2369 { config_parse_unit_env_file, "FILE" },
2370 { config_parse_output, "OUTPUT" },
2371 { config_parse_input, "INPUT" },
2372 { config_parse_facility, "FACILITY" },
2373 { config_parse_level, "LEVEL" },
2374 { config_parse_exec_capabilities, "CAPABILITIES" },
2375 { config_parse_exec_secure_bits, "SECUREBITS" },
2376 { config_parse_exec_bounding_set, "BOUNDINGSET" },
2377 { config_parse_exec_timer_slack_nsec, "TIMERSLACK" },
2378 { config_parse_limit, "LIMIT" },
2379 { config_parse_unit_cgroup, "CGROUP [...]" },
2380 { config_parse_unit_deps, "UNIT [...]" },
2381 { config_parse_unit_names, "UNIT [...]" },
2382 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2383 { config_parse_service_type, "SERVICETYPE" },
2384 { config_parse_service_restart, "SERVICERESTART" },
2385 #ifdef HAVE_SYSV_COMPAT
2386 { config_parse_sysv_priority, "SYSVPRIORITY" },
2388 { config_parse_warn_compat, "NOTSUPPORTED" },
2390 { config_parse_kill_mode, "KILLMODE" },
2391 { config_parse_kill_signal, "SIGNAL" },
2392 { config_parse_socket_listen, "SOCKET [...]" },
2393 { config_parse_socket_bind, "SOCKETBIND" },
2394 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2395 { config_parse_usec, "SECONDS" },
2396 { config_parse_path_strv, "PATH [...]" },
2397 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2398 { config_parse_unit_string_printf, "STRING" },
2399 { config_parse_timer, "TIMER" },
2400 { config_parse_timer_unit, "NAME" },
2401 { config_parse_path_spec, "PATH" },
2402 { config_parse_path_unit, "UNIT" },
2403 { config_parse_notify_access, "ACCESS" },
2404 { config_parse_ip_tos, "TOS" },
2405 { config_parse_unit_condition_path, "CONDITION" },
2406 { config_parse_unit_condition_string, "CONDITION" },
2407 { config_parse_unit_condition_null, "CONDITION" },
2410 const char *prev = NULL;
2415 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2416 const char *rvalue = "OTHER", *lvalue;
2420 const ConfigPerfItem *p;
2422 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2424 dot = strchr(i, '.');
2425 lvalue = dot ? dot + 1 : i;
2429 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2433 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2436 for (j = 0; j < ELEMENTSOF(table); j++)
2437 if (p->parse == table[j].callback) {
2438 rvalue = table[j].rvalue;
2442 fprintf(f, "%s=%s\n", lvalue, rvalue);