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_unit_env_file(
1402 const char *filename,
1404 const char *section,
1411 char ***env = data, **k;
1420 s = unit_full_printf(u, rvalue);
1424 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1425 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1430 k = strv_append(*env, s);
1441 int config_parse_ip_tos(
1442 const char *filename,
1444 const char *section,
1451 int *ip_tos = data, x;
1458 if ((x = ip_tos_from_string(rvalue)) < 0)
1459 if (safe_atoi(rvalue, &x) < 0) {
1460 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1468 int config_parse_unit_condition_path(
1469 const char *filename,
1471 const char *section,
1478 ConditionType cond = ltype;
1480 bool trigger, negate;
1488 trigger = rvalue[0] == '|';
1492 negate = rvalue[0] == '!';
1496 if (!path_is_absolute(rvalue)) {
1497 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1501 c = condition_new(cond, rvalue, trigger, negate);
1505 LIST_PREPEND(Condition, conditions, u->conditions, c);
1509 int config_parse_unit_condition_string(
1510 const char *filename,
1512 const char *section,
1519 ConditionType cond = ltype;
1521 bool trigger, negate;
1529 if ((trigger = rvalue[0] == '|'))
1532 if ((negate = rvalue[0] == '!'))
1535 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1538 LIST_PREPEND(Condition, conditions, u->conditions, c);
1542 int config_parse_unit_condition_null(
1543 const char *filename,
1545 const char *section,
1554 bool trigger, negate;
1562 if ((trigger = rvalue[0] == '|'))
1565 if ((negate = rvalue[0] == '!'))
1568 if ((b = parse_boolean(rvalue)) < 0) {
1569 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1576 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1579 LIST_PREPEND(Condition, conditions, u->conditions, c);
1583 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1584 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1586 int config_parse_unit_cgroup_attr(
1587 const char *filename,
1589 const char *section,
1605 l = strv_split_quoted(rvalue);
1609 if (strv_length(l) != 2) {
1610 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1615 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1619 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1626 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) {
1637 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1638 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1642 if (asprintf(&t, "%lu", ul) < 0)
1645 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1649 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1656 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) {
1667 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1668 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1672 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1675 r = unit_add_cgroup_attribute(u,
1677 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1682 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1689 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1697 l = strv_split_quoted(value);
1701 assert(strv_length(l) >= 1);
1703 if (streq(l[0], "*")) {
1705 if (asprintf(ret, "a *:*%s%s",
1706 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1714 if (stat(l[0], &st) < 0) {
1715 log_warning("Couldn't stat device %s", l[0]);
1720 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1721 log_warning("%s is not a device.", l[0]);
1726 if (asprintf(ret, "%c %u:%u%s%s",
1727 S_ISCHR(st.st_mode) ? 'c' : 'b',
1728 major(st.st_rdev), minor(st.st_rdev),
1729 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1740 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) {
1751 l = strv_split_quoted(rvalue);
1756 if (k < 1 || k > 2) {
1757 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1762 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1763 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1768 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1769 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1775 r = unit_add_cgroup_attribute(u, "devices",
1776 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1777 rvalue, device_map);
1780 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1787 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1797 l = strv_split_quoted(value);
1801 assert(strv_length(l) == 2);
1803 if (stat(l[0], &st) < 0) {
1804 log_warning("Couldn't stat device %s", l[0]);
1809 if (S_ISBLK(st.st_mode))
1811 else if (major(st.st_dev) != 0) {
1812 /* If this is not a device node then find the block
1813 * device this file is stored on */
1816 /* If this is a partition, try to get the originating
1818 block_get_whole_disk(d, &d);
1820 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1825 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1834 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) {
1838 const char *device = NULL, *weight;
1847 l = strv_split_quoted(rvalue);
1852 if (k < 1 || k > 2) {
1853 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1865 if (device && !path_is_absolute(device)) {
1866 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1871 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1872 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1878 r = asprintf(&t, "%s %lu", device, ul);
1880 r = asprintf(&t, "%lu", ul);
1887 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1889 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1893 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1900 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) {
1912 l = strv_split_quoted(rvalue);
1918 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1923 if (!path_is_absolute(l[0])) {
1924 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1929 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1930 log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
1935 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1941 r = unit_add_cgroup_attribute(u, "blkio",
1942 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1947 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1954 int config_parse_unit_requires_mounts_for(
1955 const char *filename,
1957 const char *section,
1973 empty_before = !u->requires_mounts_for;
1975 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1977 /* Make it easy to find units with requires_mounts set */
1978 if (empty_before && u->requires_mounts_for)
1979 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1984 int config_parse_documentation(
1985 const char *filename,
1987 const char *section,
2003 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2007 for (a = b = u->documentation; a && *a; a++) {
2009 if (is_valid_documentation_url(*a))
2012 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2021 #define FOLLOW_MAX 8
2023 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2034 /* This will update the filename pointer if the loaded file is
2035 * reached by a symlink. The old string will be freed. */
2038 char *target, *name;
2040 if (c++ >= FOLLOW_MAX)
2043 path_kill_slashes(*filename);
2045 /* Add the file name we are currently looking at to
2046 * the names of this unit, but only if it is a valid
2048 name = path_get_file_name(*filename);
2050 if (unit_name_is_valid(name, true)) {
2052 id = set_get(names, name);
2058 r = set_put(names, id);
2066 /* Try to open the file name, but don't if its a symlink */
2067 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
2073 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2074 if ((r = readlink_and_make_absolute(*filename, &target)) < 0)
2081 if (!(f = fdopen(fd, "re"))) {
2083 close_nointr_nofail(fd);
2092 static int merge_by_names(Unit **u, Set *names, const char *id) {
2100 /* Let's try to add in all symlink names we found */
2101 while ((k = set_steal_first(names))) {
2103 /* First try to merge in the other name into our
2105 if ((r = unit_merge_by_name(*u, k)) < 0) {
2108 /* Hmm, we couldn't merge the other unit into
2109 * ours? Then let's try it the other way
2112 other = manager_get_unit((*u)->manager, k);
2116 if ((r = unit_merge(other, *u)) >= 0) {
2118 return merge_by_names(u, names, NULL);
2125 unit_choose_id(*u, id);
2133 static int load_from_path(Unit *u, const char *path) {
2137 char *filename = NULL, *id = NULL;
2144 symlink_names = set_new(string_hash_func, string_compare_func);
2148 if (path_is_absolute(path)) {
2150 if (!(filename = strdup(path))) {
2155 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
2166 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2168 /* Instead of opening the path right away, we manually
2169 * follow all symlinks and add their name to our unit
2170 * name set while doing so */
2171 if (!(filename = path_make_absolute(path, *p))) {
2176 if (u->manager->unit_path_cache &&
2177 !set_get(u->manager->unit_path_cache, filename))
2180 r = open_follow(&filename, &f, symlink_names, &id);
2191 /* Empty the symlink names for the next run */
2192 while ((sn = set_steal_first(symlink_names)))
2203 /* Hmm, no suitable file found? */
2209 if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
2213 u->load_state = UNIT_MERGED;
2219 if (fstat(fileno(f), &st) < 0) {
2224 if (null_or_empty(&st))
2225 u->load_state = UNIT_MASKED;
2227 /* Now, parse the file contents */
2228 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2232 u->load_state = UNIT_LOADED;
2235 free(u->fragment_path);
2236 u->fragment_path = filename;
2239 u->fragment_mtime = timespec_load(&st.st_mtim);
2241 if (u->source_path) {
2242 if (stat(u->source_path, &st) >= 0)
2243 u->source_mtime = timespec_load(&st.st_mtim);
2245 u->source_mtime = 0;
2251 set_free_free(symlink_names);
2260 int unit_load_fragment(Unit *u) {
2266 assert(u->load_state == UNIT_STUB);
2269 /* First, try to find the unit under its id. We always look
2270 * for unit files in the default directories, to make it easy
2271 * to override things by placing things in /etc/systemd/system */
2272 if ((r = load_from_path(u, u->id)) < 0)
2275 /* Try to find an alias we can load this with */
2276 if (u->load_state == UNIT_STUB)
2277 SET_FOREACH(t, u->names, i) {
2282 if ((r = load_from_path(u, t)) < 0)
2285 if (u->load_state != UNIT_STUB)
2289 /* And now, try looking for it under the suggested (originally linked) path */
2290 if (u->load_state == UNIT_STUB && u->fragment_path) {
2292 if ((r = load_from_path(u, u->fragment_path)) < 0)
2295 if (u->load_state == UNIT_STUB) {
2296 /* Hmm, this didn't work? Then let's get rid
2297 * of the fragment path stored for us, so that
2298 * we don't point to an invalid location. */
2299 free(u->fragment_path);
2300 u->fragment_path = NULL;
2304 /* Look for a template */
2305 if (u->load_state == UNIT_STUB && u->instance) {
2308 if (!(k = unit_name_template(u->id)))
2311 r = load_from_path(u, k);
2317 if (u->load_state == UNIT_STUB)
2318 SET_FOREACH(t, u->names, i) {
2323 if (!(k = unit_name_template(t)))
2326 r = load_from_path(u, k);
2332 if (u->load_state != UNIT_STUB)
2340 void unit_dump_config_items(FILE *f) {
2341 static const struct {
2342 const ConfigParserCallback callback;
2345 { config_parse_int, "INTEGER" },
2346 { config_parse_unsigned, "UNSIGNED" },
2347 { config_parse_bytes_size, "SIZE" },
2348 { config_parse_bool, "BOOLEAN" },
2349 { config_parse_string, "STRING" },
2350 { config_parse_path, "PATH" },
2351 { config_parse_unit_path_printf, "PATH" },
2352 { config_parse_strv, "STRING [...]" },
2353 { config_parse_exec_nice, "NICE" },
2354 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2355 { config_parse_exec_io_class, "IOCLASS" },
2356 { config_parse_exec_io_priority, "IOPRIORITY" },
2357 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2358 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2359 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2360 { config_parse_mode, "MODE" },
2361 { config_parse_unit_env_file, "FILE" },
2362 { config_parse_output, "OUTPUT" },
2363 { config_parse_input, "INPUT" },
2364 { config_parse_facility, "FACILITY" },
2365 { config_parse_level, "LEVEL" },
2366 { config_parse_exec_capabilities, "CAPABILITIES" },
2367 { config_parse_exec_secure_bits, "SECUREBITS" },
2368 { config_parse_bounding_set, "BOUNDINGSET" },
2369 { config_parse_limit, "LIMIT" },
2370 { config_parse_unit_cgroup, "CGROUP [...]" },
2371 { config_parse_unit_deps, "UNIT [...]" },
2372 { config_parse_unit_names, "UNIT [...]" },
2373 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2374 { config_parse_service_type, "SERVICETYPE" },
2375 { config_parse_service_restart, "SERVICERESTART" },
2376 #ifdef HAVE_SYSV_COMPAT
2377 { config_parse_sysv_priority, "SYSVPRIORITY" },
2379 { config_parse_warn_compat, "NOTSUPPORTED" },
2381 { config_parse_kill_mode, "KILLMODE" },
2382 { config_parse_kill_signal, "SIGNAL" },
2383 { config_parse_socket_listen, "SOCKET [...]" },
2384 { config_parse_socket_bind, "SOCKETBIND" },
2385 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2386 { config_parse_usec, "SECONDS" },
2387 { config_parse_nsec, "NANOSECONDS" },
2388 { config_parse_path_strv, "PATH [...]" },
2389 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2390 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2391 { config_parse_unit_string_printf, "STRING" },
2392 { config_parse_timer, "TIMER" },
2393 { config_parse_timer_unit, "NAME" },
2394 { config_parse_path_spec, "PATH" },
2395 { config_parse_path_unit, "UNIT" },
2396 { config_parse_notify_access, "ACCESS" },
2397 { config_parse_ip_tos, "TOS" },
2398 { config_parse_unit_condition_path, "CONDITION" },
2399 { config_parse_unit_condition_string, "CONDITION" },
2400 { config_parse_unit_condition_null, "CONDITION" },
2403 const char *prev = NULL;
2408 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2409 const char *rvalue = "OTHER", *lvalue;
2413 const ConfigPerfItem *p;
2415 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2417 dot = strchr(i, '.');
2418 lvalue = dot ? dot + 1 : i;
2422 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2426 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2429 for (j = 0; j < ELEMENTSOF(table); j++)
2430 if (p->parse == table[j].callback) {
2431 rvalue = table[j].rvalue;
2435 fprintf(f, "%s=%s\n", lvalue, rvalue);