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"
47 #include "path-util.h"
49 #ifndef HAVE_SYSV_COMPAT
50 int config_parse_warn_compat(
60 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
65 int config_parse_unit_deps(
75 UnitDependency d = ltype;
85 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
93 k = unit_name_printf(u, t);
98 r = unit_add_dependency_by_name(u, d, k, NULL, true);
100 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
108 int config_parse_unit_names(
109 const char *filename,
128 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
136 k = unit_name_printf(u, t);
141 r = unit_merge_by_name(u, k);
143 log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
151 int config_parse_unit_string_printf(
152 const char *filename,
170 k = unit_full_printf(u, rvalue);
174 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
180 int config_parse_unit_strv_printf(
181 const char *filename,
199 k = unit_full_printf(u, rvalue);
203 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
209 int config_parse_unit_path_printf(
210 const char *filename,
228 k = unit_full_printf(u, rvalue);
232 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
238 int config_parse_socket_listen(
239 const char *filename,
248 SocketPort *p, *tail;
258 p = new0(SocketPort, 1);
262 if (streq(lvalue, "ListenFIFO")) {
263 p->type = SOCKET_FIFO;
265 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
270 path_kill_slashes(p->path);
272 } else if (streq(lvalue, "ListenSpecial")) {
273 p->type = SOCKET_SPECIAL;
275 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
280 path_kill_slashes(p->path);
282 } else if (streq(lvalue, "ListenMessageQueue")) {
284 p->type = SOCKET_MQUEUE;
286 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
291 path_kill_slashes(p->path);
293 } else if (streq(lvalue, "ListenNetlink")) {
297 p->type = SOCKET_SOCKET;
298 k = unit_full_printf(UNIT(s), rvalue);
299 r = socket_address_parse_netlink(&p->address, k);
303 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
312 p->type = SOCKET_SOCKET;
313 k = unit_full_printf(UNIT(s), rvalue);
314 r = socket_address_parse(&p->address, k);
318 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
323 if (streq(lvalue, "ListenStream"))
324 p->address.type = SOCK_STREAM;
325 else if (streq(lvalue, "ListenDatagram"))
326 p->address.type = SOCK_DGRAM;
328 assert(streq(lvalue, "ListenSequentialPacket"));
329 p->address.type = SOCK_SEQPACKET;
332 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
333 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
342 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
343 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
345 LIST_PREPEND(SocketPort, port, s->ports, p);
350 int config_parse_socket_bind(
351 const char *filename,
361 SocketAddressBindIPv6Only b;
370 if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
373 if ((r = parse_boolean(rvalue)) < 0) {
374 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
378 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
380 s->bind_ipv6_only = b;
385 int config_parse_exec_nice(
386 const char *filename,
395 ExecContext *c = data;
403 if (safe_atoi(rvalue, &priority) < 0) {
404 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
408 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
409 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
419 int config_parse_exec_oom_score_adjust(
420 const char *filename,
429 ExecContext *c = data;
437 if (safe_atoi(rvalue, &oa) < 0) {
438 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
442 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
443 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
447 c->oom_score_adjust = oa;
448 c->oom_score_adjust_set = true;
453 int config_parse_exec(
454 const char *filename,
463 ExecCommand **e = data, *nce;
473 /* We accept an absolute path as first argument, or
474 * alternatively an absolute prefixed with @ to allow
475 * overriding of argv[0]. */
483 bool honour_argv0 = false, ignore = false;
489 rvalue += strspn(rvalue, WHITESPACE);
494 if (rvalue[0] == '-') {
499 if (rvalue[0] == '@') {
504 if (*rvalue != '/') {
505 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
510 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
511 if (strncmp(w, ";", MAX(l, 1U)) == 0)
517 n = new(char*, k + !honour_argv0);
522 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
523 if (strncmp(w, ";", MAX(l, 1U)) == 0)
526 if (honour_argv0 && w == rvalue) {
529 path = strndup(w, l);
535 if (!utf8_is_valid(path)) {
536 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
544 c = n[k++] = cunescape_length(w, l);
550 if (!utf8_is_valid(c)) {
551 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
561 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
574 assert(path_is_absolute(path));
576 nce = new0(ExecCommand, 1);
584 nce->ignore = ignore;
586 path_kill_slashes(nce->path);
588 exec_command_append_list(e, nce);
604 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
605 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
607 int config_parse_socket_bindtodevice(
608 const char *filename,
625 if (rvalue[0] && !streq(rvalue, "*")) {
626 if (!(n = strdup(rvalue)))
631 free(s->bind_to_device);
632 s->bind_to_device = n;
637 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
638 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
640 int config_parse_exec_io_class(
641 const char *filename,
650 ExecContext *c = data;
658 if ((x = ioprio_class_from_string(rvalue)) < 0) {
659 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
663 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
664 c->ioprio_set = true;
669 int config_parse_exec_io_priority(
670 const char *filename,
679 ExecContext *c = data;
687 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
688 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
692 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
693 c->ioprio_set = true;
698 int config_parse_exec_cpu_sched_policy(
699 const char *filename,
709 ExecContext *c = data;
717 if ((x = sched_policy_from_string(rvalue)) < 0) {
718 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
722 c->cpu_sched_policy = x;
723 c->cpu_sched_set = true;
728 int config_parse_exec_cpu_sched_prio(
729 const char *filename,
738 ExecContext *c = data;
746 /* On Linux RR/FIFO have the same range */
747 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
748 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
752 c->cpu_sched_priority = i;
753 c->cpu_sched_set = true;
758 int config_parse_exec_cpu_affinity(
759 const char *filename,
768 ExecContext *c = data;
778 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
783 if (!(t = strndup(w, l)))
786 r = safe_atou(t, &cpu);
790 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
793 if (r < 0 || cpu >= c->cpuset_ncpus) {
794 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
798 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
804 int config_parse_exec_capabilities(
805 const char *filename,
814 ExecContext *c = data;
822 if (!(cap = cap_from_text(rvalue))) {
826 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
831 cap_free(c->capabilities);
832 c->capabilities = cap;
837 int config_parse_exec_secure_bits(
838 const char *filename,
847 ExecContext *c = data;
857 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
858 if (first_word(w, "keep-caps"))
859 c->secure_bits |= SECURE_KEEP_CAPS;
860 else if (first_word(w, "keep-caps-locked"))
861 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
862 else if (first_word(w, "no-setuid-fixup"))
863 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
864 else if (first_word(w, "no-setuid-fixup-locked"))
865 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
866 else if (first_word(w, "noroot"))
867 c->secure_bits |= SECURE_NOROOT;
868 else if (first_word(w, "noroot-locked"))
869 c->secure_bits |= SECURE_NOROOT_LOCKED;
871 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
879 int config_parse_bounding_set(
880 const char *filename,
889 uint64_t *capability_bounding_set_drop = data;
901 if (rvalue[0] == '~') {
906 /* Note that we store this inverted internally, since the
907 * kernel wants it like this. But we actually expose it
908 * non-inverted everywhere to have a fully normalized
911 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
920 r = cap_from_name(t, &cap);
924 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
928 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
932 *capability_bounding_set_drop |= sum;
934 *capability_bounding_set_drop |= ~sum;
939 int config_parse_limit(
940 const char *filename,
949 struct rlimit **rl = data;
950 unsigned long long u;
959 if (streq(rvalue, "infinity"))
960 u = (unsigned long long) RLIM_INFINITY;
961 else if (safe_atollu(rvalue, &u) < 0) {
962 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
967 if (!(*rl = new(struct rlimit, 1)))
970 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
974 int config_parse_unit_cgroup(
975 const char *filename,
989 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
997 k = unit_full_printf(u, t);
1009 r = unit_add_cgroup_from_text(u, t);
1013 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
1021 #ifdef HAVE_SYSV_COMPAT
1022 int config_parse_sysv_priority(
1023 const char *filename,
1025 const char *section,
1032 int *priority = data;
1040 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1041 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1045 *priority = (int) i;
1050 int config_parse_fsck_passno(
1051 const char *filename,
1053 const char *section,
1068 if (safe_atoi(rvalue, &i) || i < 0) {
1069 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1077 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1079 int config_parse_kill_signal(
1080 const char *filename,
1082 const char *section,
1097 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1098 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1106 int config_parse_exec_mount_flags(
1107 const char *filename,
1109 const char *section,
1116 ExecContext *c = data;
1120 unsigned long flags = 0;
1127 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1128 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1130 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1132 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1133 flags |= MS_PRIVATE;
1135 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1140 c->mount_flags = flags;
1144 int config_parse_timer(
1145 const char *filename,
1147 const char *section,
1164 if ((b = timer_base_from_string(lvalue)) < 0) {
1165 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1169 if (parse_usec(rvalue, &u) < 0) {
1170 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1174 if (!(v = new0(TimerValue, 1)))
1180 LIST_PREPEND(TimerValue, value, t->values, v);
1185 int config_parse_timer_unit(
1186 const char *filename,
1188 const char *section,
1205 dbus_error_init(&error);
1207 if (endswith(rvalue, ".timer")) {
1208 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1212 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1214 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1215 dbus_error_free(&error);
1219 unit_ref_set(&t->unit, u);
1224 int config_parse_path_spec(
1225 const char *filename,
1227 const char *section,
1243 if ((b = path_type_from_string(lvalue)) < 0) {
1244 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1248 if (!path_is_absolute(rvalue)) {
1249 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1253 if (!(s = new0(PathSpec, 1)))
1256 if (!(s->path = strdup(rvalue))) {
1261 path_kill_slashes(s->path);
1266 LIST_PREPEND(PathSpec, spec, p->specs, s);
1271 int config_parse_path_unit(
1272 const char *filename,
1274 const char *section,
1291 dbus_error_init(&error);
1293 if (endswith(rvalue, ".path")) {
1294 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1298 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1299 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1300 dbus_error_free(&error);
1304 unit_ref_set(&t->unit, u);
1309 int config_parse_socket_service(
1310 const char *filename,
1312 const char *section,
1329 dbus_error_init(&error);
1331 if (!endswith(rvalue, ".service")) {
1332 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1336 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1338 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1339 dbus_error_free(&error);
1343 unit_ref_set(&s->service, x);
1348 int config_parse_service_sockets(
1349 const char *filename,
1351 const char *section,
1368 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1375 k = unit_name_printf(UNIT(s), t);
1381 if (!endswith(k, ".socket")) {
1382 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1387 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1389 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1391 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1401 int config_parse_service_timeout(
1402 const char *filename,
1404 const char *section,
1411 Service *s = userdata;
1419 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1422 s->timeout_defined = true;
1427 int config_parse_unit_env_file(
1428 const char *filename,
1430 const char *section,
1437 char ***env = data, **k;
1446 s = unit_full_printf(u, rvalue);
1450 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1451 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1456 k = strv_append(*env, s);
1467 int config_parse_ip_tos(
1468 const char *filename,
1470 const char *section,
1477 int *ip_tos = data, x;
1484 if ((x = ip_tos_from_string(rvalue)) < 0)
1485 if (safe_atoi(rvalue, &x) < 0) {
1486 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1494 int config_parse_unit_condition_path(
1495 const char *filename,
1497 const char *section,
1504 ConditionType cond = ltype;
1506 bool trigger, negate;
1514 trigger = rvalue[0] == '|';
1518 negate = rvalue[0] == '!';
1522 if (!path_is_absolute(rvalue)) {
1523 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1527 c = condition_new(cond, rvalue, trigger, negate);
1531 LIST_PREPEND(Condition, conditions, u->conditions, c);
1535 int config_parse_unit_condition_string(
1536 const char *filename,
1538 const char *section,
1545 ConditionType cond = ltype;
1547 bool trigger, negate;
1555 if ((trigger = rvalue[0] == '|'))
1558 if ((negate = rvalue[0] == '!'))
1561 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1564 LIST_PREPEND(Condition, conditions, u->conditions, c);
1568 int config_parse_unit_condition_null(
1569 const char *filename,
1571 const char *section,
1580 bool trigger, negate;
1588 if ((trigger = rvalue[0] == '|'))
1591 if ((negate = rvalue[0] == '!'))
1594 if ((b = parse_boolean(rvalue)) < 0) {
1595 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1602 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1605 LIST_PREPEND(Condition, conditions, u->conditions, c);
1609 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1610 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1612 int config_parse_unit_cgroup_attr(
1613 const char *filename,
1615 const char *section,
1631 l = strv_split_quoted(rvalue);
1635 if (strv_length(l) != 2) {
1636 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1641 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1645 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1652 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) {
1663 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1664 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1668 if (asprintf(&t, "%lu", ul) < 0)
1671 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1675 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1682 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) {
1693 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1694 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1698 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1701 r = unit_add_cgroup_attribute(u,
1703 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1708 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1715 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1723 l = strv_split_quoted(value);
1727 assert(strv_length(l) >= 1);
1729 if (streq(l[0], "*")) {
1731 if (asprintf(ret, "a *:*%s%s",
1732 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1740 if (stat(l[0], &st) < 0) {
1741 log_warning("Couldn't stat device %s", l[0]);
1746 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1747 log_warning("%s is not a device.", l[0]);
1752 if (asprintf(ret, "%c %u:%u%s%s",
1753 S_ISCHR(st.st_mode) ? 'c' : 'b',
1754 major(st.st_rdev), minor(st.st_rdev),
1755 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1766 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) {
1777 l = strv_split_quoted(rvalue);
1782 if (k < 1 || k > 2) {
1783 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1788 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1789 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1794 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1795 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1801 r = unit_add_cgroup_attribute(u, "devices",
1802 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1803 rvalue, device_map);
1806 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1813 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1823 l = strv_split_quoted(value);
1827 assert(strv_length(l) == 2);
1829 if (stat(l[0], &st) < 0) {
1830 log_warning("Couldn't stat device %s", l[0]);
1835 if (S_ISBLK(st.st_mode))
1837 else if (major(st.st_dev) != 0) {
1838 /* If this is not a device node then find the block
1839 * device this file is stored on */
1842 /* If this is a partition, try to get the originating
1844 block_get_whole_disk(d, &d);
1846 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1851 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1860 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) {
1864 const char *device = NULL, *weight;
1873 l = strv_split_quoted(rvalue);
1878 if (k < 1 || k > 2) {
1879 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1891 if (device && !path_is_absolute(device)) {
1892 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1897 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1898 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1904 r = asprintf(&t, "%s %lu", device, ul);
1906 r = asprintf(&t, "%lu", ul);
1913 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1915 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1919 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1926 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) {
1938 l = strv_split_quoted(rvalue);
1944 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1949 if (!path_is_absolute(l[0])) {
1950 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1955 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1956 log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
1961 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1967 r = unit_add_cgroup_attribute(u, "blkio",
1968 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1973 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1980 int config_parse_unit_requires_mounts_for(
1981 const char *filename,
1983 const char *section,
1999 empty_before = !u->requires_mounts_for;
2001 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2003 /* Make it easy to find units with requires_mounts set */
2004 if (empty_before && u->requires_mounts_for)
2005 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2010 int config_parse_documentation(
2011 const char *filename,
2013 const char *section,
2029 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2033 for (a = b = u->documentation; a && *a; a++) {
2035 if (is_valid_documentation_url(*a))
2038 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2047 #define FOLLOW_MAX 8
2049 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2060 /* This will update the filename pointer if the loaded file is
2061 * reached by a symlink. The old string will be freed. */
2064 char *target, *name;
2066 if (c++ >= FOLLOW_MAX)
2069 path_kill_slashes(*filename);
2071 /* Add the file name we are currently looking at to
2072 * the names of this unit, but only if it is a valid
2074 name = path_get_file_name(*filename);
2076 if (unit_name_is_valid(name, true)) {
2078 id = set_get(names, name);
2084 r = set_put(names, id);
2092 /* Try to open the file name, but don't if its a symlink */
2093 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
2099 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2100 if ((r = readlink_and_make_absolute(*filename, &target)) < 0)
2107 if (!(f = fdopen(fd, "re"))) {
2109 close_nointr_nofail(fd);
2118 static int merge_by_names(Unit **u, Set *names, const char *id) {
2126 /* Let's try to add in all symlink names we found */
2127 while ((k = set_steal_first(names))) {
2129 /* First try to merge in the other name into our
2131 if ((r = unit_merge_by_name(*u, k)) < 0) {
2134 /* Hmm, we couldn't merge the other unit into
2135 * ours? Then let's try it the other way
2138 other = manager_get_unit((*u)->manager, k);
2142 if ((r = unit_merge(other, *u)) >= 0) {
2144 return merge_by_names(u, names, NULL);
2151 unit_choose_id(*u, id);
2159 static int load_from_path(Unit *u, const char *path) {
2163 char *filename = NULL, *id = NULL;
2170 symlink_names = set_new(string_hash_func, string_compare_func);
2174 if (path_is_absolute(path)) {
2176 if (!(filename = strdup(path))) {
2181 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
2192 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2194 /* Instead of opening the path right away, we manually
2195 * follow all symlinks and add their name to our unit
2196 * name set while doing so */
2197 if (!(filename = path_make_absolute(path, *p))) {
2202 if (u->manager->unit_path_cache &&
2203 !set_get(u->manager->unit_path_cache, filename))
2206 r = open_follow(&filename, &f, symlink_names, &id);
2217 /* Empty the symlink names for the next run */
2218 while ((sn = set_steal_first(symlink_names)))
2229 /* Hmm, no suitable file found? */
2235 if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
2239 u->load_state = UNIT_MERGED;
2245 if (fstat(fileno(f), &st) < 0) {
2250 if (null_or_empty(&st))
2251 u->load_state = UNIT_MASKED;
2253 /* Now, parse the file contents */
2254 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2258 u->load_state = UNIT_LOADED;
2261 free(u->fragment_path);
2262 u->fragment_path = filename;
2265 u->fragment_mtime = timespec_load(&st.st_mtim);
2267 if (u->source_path) {
2268 if (stat(u->source_path, &st) >= 0)
2269 u->source_mtime = timespec_load(&st.st_mtim);
2271 u->source_mtime = 0;
2277 set_free_free(symlink_names);
2286 int unit_load_fragment(Unit *u) {
2292 assert(u->load_state == UNIT_STUB);
2295 /* First, try to find the unit under its id. We always look
2296 * for unit files in the default directories, to make it easy
2297 * to override things by placing things in /etc/systemd/system */
2298 if ((r = load_from_path(u, u->id)) < 0)
2301 /* Try to find an alias we can load this with */
2302 if (u->load_state == UNIT_STUB)
2303 SET_FOREACH(t, u->names, i) {
2308 if ((r = load_from_path(u, t)) < 0)
2311 if (u->load_state != UNIT_STUB)
2315 /* And now, try looking for it under the suggested (originally linked) path */
2316 if (u->load_state == UNIT_STUB && u->fragment_path) {
2318 if ((r = load_from_path(u, u->fragment_path)) < 0)
2321 if (u->load_state == UNIT_STUB) {
2322 /* Hmm, this didn't work? Then let's get rid
2323 * of the fragment path stored for us, so that
2324 * we don't point to an invalid location. */
2325 free(u->fragment_path);
2326 u->fragment_path = NULL;
2330 /* Look for a template */
2331 if (u->load_state == UNIT_STUB && u->instance) {
2334 if (!(k = unit_name_template(u->id)))
2337 r = load_from_path(u, k);
2343 if (u->load_state == UNIT_STUB)
2344 SET_FOREACH(t, u->names, i) {
2349 if (!(k = unit_name_template(t)))
2352 r = load_from_path(u, k);
2358 if (u->load_state != UNIT_STUB)
2366 void unit_dump_config_items(FILE *f) {
2367 static const struct {
2368 const ConfigParserCallback callback;
2371 { config_parse_int, "INTEGER" },
2372 { config_parse_unsigned, "UNSIGNED" },
2373 { config_parse_bytes_size, "SIZE" },
2374 { config_parse_bool, "BOOLEAN" },
2375 { config_parse_string, "STRING" },
2376 { config_parse_path, "PATH" },
2377 { config_parse_unit_path_printf, "PATH" },
2378 { config_parse_strv, "STRING [...]" },
2379 { config_parse_exec_nice, "NICE" },
2380 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2381 { config_parse_exec_io_class, "IOCLASS" },
2382 { config_parse_exec_io_priority, "IOPRIORITY" },
2383 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2384 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2385 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2386 { config_parse_mode, "MODE" },
2387 { config_parse_unit_env_file, "FILE" },
2388 { config_parse_output, "OUTPUT" },
2389 { config_parse_input, "INPUT" },
2390 { config_parse_facility, "FACILITY" },
2391 { config_parse_level, "LEVEL" },
2392 { config_parse_exec_capabilities, "CAPABILITIES" },
2393 { config_parse_exec_secure_bits, "SECUREBITS" },
2394 { config_parse_bounding_set, "BOUNDINGSET" },
2395 { config_parse_limit, "LIMIT" },
2396 { config_parse_unit_cgroup, "CGROUP [...]" },
2397 { config_parse_unit_deps, "UNIT [...]" },
2398 { config_parse_unit_names, "UNIT [...]" },
2399 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2400 { config_parse_service_type, "SERVICETYPE" },
2401 { config_parse_service_restart, "SERVICERESTART" },
2402 #ifdef HAVE_SYSV_COMPAT
2403 { config_parse_sysv_priority, "SYSVPRIORITY" },
2405 { config_parse_warn_compat, "NOTSUPPORTED" },
2407 { config_parse_kill_mode, "KILLMODE" },
2408 { config_parse_kill_signal, "SIGNAL" },
2409 { config_parse_socket_listen, "SOCKET [...]" },
2410 { config_parse_socket_bind, "SOCKETBIND" },
2411 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2412 { config_parse_usec, "SECONDS" },
2413 { config_parse_nsec, "NANOSECONDS" },
2414 { config_parse_path_strv, "PATH [...]" },
2415 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2416 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2417 { config_parse_unit_string_printf, "STRING" },
2418 { config_parse_timer, "TIMER" },
2419 { config_parse_timer_unit, "NAME" },
2420 { config_parse_path_spec, "PATH" },
2421 { config_parse_path_unit, "UNIT" },
2422 { config_parse_notify_access, "ACCESS" },
2423 { config_parse_ip_tos, "TOS" },
2424 { config_parse_unit_condition_path, "CONDITION" },
2425 { config_parse_unit_condition_string, "CONDITION" },
2426 { config_parse_unit_condition_null, "CONDITION" },
2429 const char *prev = NULL;
2434 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2435 const char *rvalue = "OTHER", *lvalue;
2439 const ConfigPerfItem *p;
2441 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2443 dot = strchr(i, '.');
2444 lvalue = dot ? dot + 1 : i;
2448 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2452 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2455 for (j = 0; j < ELEMENTSOF(table); j++)
2456 if (p->parse == table[j].callback) {
2457 rvalue = table[j].rvalue;
2461 fprintf(f, "%s=%s\n", lvalue, rvalue);