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_string_printf(
109 const char *filename,
127 k = unit_full_printf(u, rvalue);
131 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
137 int config_parse_unit_strv_printf(
138 const char *filename,
156 k = unit_full_printf(u, rvalue);
160 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
166 int config_parse_unit_path_printf(
167 const char *filename,
185 k = unit_full_printf(u, rvalue);
189 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
195 int config_parse_socket_listen(
196 const char *filename,
205 SocketPort *p, *tail;
215 p = new0(SocketPort, 1);
219 if (streq(lvalue, "ListenFIFO")) {
220 p->type = SOCKET_FIFO;
222 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
227 path_kill_slashes(p->path);
229 } else if (streq(lvalue, "ListenSpecial")) {
230 p->type = SOCKET_SPECIAL;
232 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
237 path_kill_slashes(p->path);
239 } else if (streq(lvalue, "ListenMessageQueue")) {
241 p->type = SOCKET_MQUEUE;
243 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
248 path_kill_slashes(p->path);
250 } else if (streq(lvalue, "ListenNetlink")) {
254 p->type = SOCKET_SOCKET;
255 k = unit_full_printf(UNIT(s), rvalue);
256 r = socket_address_parse_netlink(&p->address, k);
260 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
269 p->type = SOCKET_SOCKET;
270 k = unit_full_printf(UNIT(s), rvalue);
271 r = socket_address_parse(&p->address, k);
275 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
280 if (streq(lvalue, "ListenStream"))
281 p->address.type = SOCK_STREAM;
282 else if (streq(lvalue, "ListenDatagram"))
283 p->address.type = SOCK_DGRAM;
285 assert(streq(lvalue, "ListenSequentialPacket"));
286 p->address.type = SOCK_SEQPACKET;
289 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
290 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
299 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
300 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
302 LIST_PREPEND(SocketPort, port, s->ports, p);
307 int config_parse_socket_bind(
308 const char *filename,
318 SocketAddressBindIPv6Only b;
327 if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
330 if ((r = parse_boolean(rvalue)) < 0) {
331 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
335 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
337 s->bind_ipv6_only = b;
342 int config_parse_exec_nice(
343 const char *filename,
352 ExecContext *c = data;
360 if (safe_atoi(rvalue, &priority) < 0) {
361 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
365 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
366 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
376 int config_parse_exec_oom_score_adjust(
377 const char *filename,
386 ExecContext *c = data;
394 if (safe_atoi(rvalue, &oa) < 0) {
395 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
399 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
400 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
404 c->oom_score_adjust = oa;
405 c->oom_score_adjust_set = true;
410 int config_parse_exec(
411 const char *filename,
420 ExecCommand **e = data, *nce;
430 /* We accept an absolute path as first argument, or
431 * alternatively an absolute prefixed with @ to allow
432 * overriding of argv[0]. */
440 bool honour_argv0 = false, ignore = false;
446 rvalue += strspn(rvalue, WHITESPACE);
451 if (rvalue[0] == '-') {
456 if (rvalue[0] == '@') {
461 if (*rvalue != '/') {
462 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
467 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
468 if (strncmp(w, ";", MAX(l, 1U)) == 0)
474 n = new(char*, k + !honour_argv0);
479 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
480 if (strncmp(w, ";", MAX(l, 1U)) == 0)
483 if (honour_argv0 && w == rvalue) {
486 path = strndup(w, l);
492 if (!utf8_is_valid(path)) {
493 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
501 c = n[k++] = cunescape_length(w, l);
507 if (!utf8_is_valid(c)) {
508 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
518 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
531 assert(path_is_absolute(path));
533 nce = new0(ExecCommand, 1);
541 nce->ignore = ignore;
543 path_kill_slashes(nce->path);
545 exec_command_append_list(e, nce);
561 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
562 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
564 int config_parse_socket_bindtodevice(
565 const char *filename,
582 if (rvalue[0] && !streq(rvalue, "*")) {
583 if (!(n = strdup(rvalue)))
588 free(s->bind_to_device);
589 s->bind_to_device = n;
594 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
595 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
597 int config_parse_exec_io_class(
598 const char *filename,
607 ExecContext *c = data;
615 if ((x = ioprio_class_from_string(rvalue)) < 0) {
616 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
620 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
621 c->ioprio_set = true;
626 int config_parse_exec_io_priority(
627 const char *filename,
636 ExecContext *c = data;
644 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
645 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
649 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
650 c->ioprio_set = true;
655 int config_parse_exec_cpu_sched_policy(
656 const char *filename,
666 ExecContext *c = data;
674 if ((x = sched_policy_from_string(rvalue)) < 0) {
675 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
679 c->cpu_sched_policy = x;
680 c->cpu_sched_set = true;
685 int config_parse_exec_cpu_sched_prio(
686 const char *filename,
695 ExecContext *c = data;
703 /* On Linux RR/FIFO have the same range */
704 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
705 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
709 c->cpu_sched_priority = i;
710 c->cpu_sched_set = true;
715 int config_parse_exec_cpu_affinity(
716 const char *filename,
725 ExecContext *c = data;
735 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
740 if (!(t = strndup(w, l)))
743 r = safe_atou(t, &cpu);
747 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
750 if (r < 0 || cpu >= c->cpuset_ncpus) {
751 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
755 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
761 int config_parse_exec_capabilities(
762 const char *filename,
771 ExecContext *c = data;
779 if (!(cap = cap_from_text(rvalue))) {
783 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
788 cap_free(c->capabilities);
789 c->capabilities = cap;
794 int config_parse_exec_secure_bits(
795 const char *filename,
804 ExecContext *c = data;
814 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
815 if (first_word(w, "keep-caps"))
816 c->secure_bits |= SECURE_KEEP_CAPS;
817 else if (first_word(w, "keep-caps-locked"))
818 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
819 else if (first_word(w, "no-setuid-fixup"))
820 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
821 else if (first_word(w, "no-setuid-fixup-locked"))
822 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
823 else if (first_word(w, "noroot"))
824 c->secure_bits |= SECURE_NOROOT;
825 else if (first_word(w, "noroot-locked"))
826 c->secure_bits |= SECURE_NOROOT_LOCKED;
828 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
836 int config_parse_bounding_set(
837 const char *filename,
846 uint64_t *capability_bounding_set_drop = data;
858 if (rvalue[0] == '~') {
863 /* Note that we store this inverted internally, since the
864 * kernel wants it like this. But we actually expose it
865 * non-inverted everywhere to have a fully normalized
868 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
877 r = cap_from_name(t, &cap);
881 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
885 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
889 *capability_bounding_set_drop |= sum;
891 *capability_bounding_set_drop |= ~sum;
896 int config_parse_limit(
897 const char *filename,
906 struct rlimit **rl = data;
907 unsigned long long u;
916 if (streq(rvalue, "infinity"))
917 u = (unsigned long long) RLIM_INFINITY;
918 else if (safe_atollu(rvalue, &u) < 0) {
919 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
924 if (!(*rl = new(struct rlimit, 1)))
927 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
931 int config_parse_unit_cgroup(
932 const char *filename,
946 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
954 k = unit_full_printf(u, t);
966 r = unit_add_cgroup_from_text(u, t);
970 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
978 #ifdef HAVE_SYSV_COMPAT
979 int config_parse_sysv_priority(
980 const char *filename,
989 int *priority = data;
997 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
998 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1002 *priority = (int) i;
1007 int config_parse_fsck_passno(
1008 const char *filename,
1010 const char *section,
1025 if (safe_atoi(rvalue, &i) || i < 0) {
1026 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1034 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1036 int config_parse_kill_signal(
1037 const char *filename,
1039 const char *section,
1054 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1055 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1063 int config_parse_exec_mount_flags(
1064 const char *filename,
1066 const char *section,
1073 ExecContext *c = data;
1077 unsigned long flags = 0;
1084 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1085 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1087 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1089 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1090 flags |= MS_PRIVATE;
1092 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1097 c->mount_flags = flags;
1101 int config_parse_timer(
1102 const char *filename,
1104 const char *section,
1121 if ((b = timer_base_from_string(lvalue)) < 0) {
1122 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1126 if (parse_usec(rvalue, &u) < 0) {
1127 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1131 if (!(v = new0(TimerValue, 1)))
1137 LIST_PREPEND(TimerValue, value, t->values, v);
1142 int config_parse_timer_unit(
1143 const char *filename,
1145 const char *section,
1162 dbus_error_init(&error);
1164 if (endswith(rvalue, ".timer")) {
1165 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1169 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1171 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1172 dbus_error_free(&error);
1176 unit_ref_set(&t->unit, u);
1181 int config_parse_path_spec(
1182 const char *filename,
1184 const char *section,
1200 if ((b = path_type_from_string(lvalue)) < 0) {
1201 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1205 if (!path_is_absolute(rvalue)) {
1206 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1210 if (!(s = new0(PathSpec, 1)))
1213 if (!(s->path = strdup(rvalue))) {
1218 path_kill_slashes(s->path);
1223 LIST_PREPEND(PathSpec, spec, p->specs, s);
1228 int config_parse_path_unit(
1229 const char *filename,
1231 const char *section,
1248 dbus_error_init(&error);
1250 if (endswith(rvalue, ".path")) {
1251 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1255 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1256 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1257 dbus_error_free(&error);
1261 unit_ref_set(&t->unit, u);
1266 int config_parse_socket_service(
1267 const char *filename,
1269 const char *section,
1286 dbus_error_init(&error);
1288 if (!endswith(rvalue, ".service")) {
1289 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1293 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
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(&s->service, x);
1305 int config_parse_service_sockets(
1306 const char *filename,
1308 const char *section,
1325 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1332 k = unit_name_printf(UNIT(s), t);
1338 if (!endswith(k, ".socket")) {
1339 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1344 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1346 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1348 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1358 int config_parse_service_timeout(
1359 const char *filename,
1361 const char *section,
1368 Service *s = userdata;
1376 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1379 s->timeout_defined = true;
1384 int config_parse_unit_env_file(
1385 const char *filename,
1387 const char *section,
1394 char ***env = data, **k;
1403 s = unit_full_printf(u, rvalue);
1407 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1408 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1413 k = strv_append(*env, s);
1424 int config_parse_ip_tos(
1425 const char *filename,
1427 const char *section,
1434 int *ip_tos = data, x;
1441 if ((x = ip_tos_from_string(rvalue)) < 0)
1442 if (safe_atoi(rvalue, &x) < 0) {
1443 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1451 int config_parse_unit_condition_path(
1452 const char *filename,
1454 const char *section,
1461 ConditionType cond = ltype;
1463 bool trigger, negate;
1471 trigger = rvalue[0] == '|';
1475 negate = rvalue[0] == '!';
1479 if (!path_is_absolute(rvalue)) {
1480 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1484 c = condition_new(cond, rvalue, trigger, negate);
1488 LIST_PREPEND(Condition, conditions, u->conditions, c);
1492 int config_parse_unit_condition_string(
1493 const char *filename,
1495 const char *section,
1502 ConditionType cond = ltype;
1504 bool trigger, negate;
1512 if ((trigger = rvalue[0] == '|'))
1515 if ((negate = rvalue[0] == '!'))
1518 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1521 LIST_PREPEND(Condition, conditions, u->conditions, c);
1525 int config_parse_unit_condition_null(
1526 const char *filename,
1528 const char *section,
1537 bool trigger, negate;
1545 if ((trigger = rvalue[0] == '|'))
1548 if ((negate = rvalue[0] == '!'))
1551 if ((b = parse_boolean(rvalue)) < 0) {
1552 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1559 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1562 LIST_PREPEND(Condition, conditions, u->conditions, c);
1566 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1567 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1569 int config_parse_unit_cgroup_attr(
1570 const char *filename,
1572 const char *section,
1588 l = strv_split_quoted(rvalue);
1592 if (strv_length(l) != 2) {
1593 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1598 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1602 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1609 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) {
1620 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1621 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1625 if (asprintf(&t, "%lu", ul) < 0)
1628 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1632 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1639 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) {
1650 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1651 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1655 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1658 r = unit_add_cgroup_attribute(u,
1660 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1665 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1672 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1680 l = strv_split_quoted(value);
1684 assert(strv_length(l) >= 1);
1686 if (streq(l[0], "*")) {
1688 if (asprintf(ret, "a *:*%s%s",
1689 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1697 if (stat(l[0], &st) < 0) {
1698 log_warning("Couldn't stat device %s", l[0]);
1703 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1704 log_warning("%s is not a device.", l[0]);
1709 if (asprintf(ret, "%c %u:%u%s%s",
1710 S_ISCHR(st.st_mode) ? 'c' : 'b',
1711 major(st.st_rdev), minor(st.st_rdev),
1712 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1723 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) {
1734 l = strv_split_quoted(rvalue);
1739 if (k < 1 || k > 2) {
1740 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1745 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1746 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1751 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1752 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1758 r = unit_add_cgroup_attribute(u, "devices",
1759 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1760 rvalue, device_map);
1763 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1770 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1780 l = strv_split_quoted(value);
1784 assert(strv_length(l) == 2);
1786 if (stat(l[0], &st) < 0) {
1787 log_warning("Couldn't stat device %s", l[0]);
1792 if (S_ISBLK(st.st_mode))
1794 else if (major(st.st_dev) != 0) {
1795 /* If this is not a device node then find the block
1796 * device this file is stored on */
1799 /* If this is a partition, try to get the originating
1801 block_get_whole_disk(d, &d);
1803 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1808 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1817 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) {
1821 const char *device = NULL, *weight;
1830 l = strv_split_quoted(rvalue);
1835 if (k < 1 || k > 2) {
1836 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1848 if (device && !path_is_absolute(device)) {
1849 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1854 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1855 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1861 r = asprintf(&t, "%s %lu", device, ul);
1863 r = asprintf(&t, "%lu", ul);
1870 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1872 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1876 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1883 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) {
1895 l = strv_split_quoted(rvalue);
1901 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1906 if (!path_is_absolute(l[0])) {
1907 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1912 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1913 log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
1918 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1924 r = unit_add_cgroup_attribute(u, "blkio",
1925 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1930 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1937 int config_parse_unit_requires_mounts_for(
1938 const char *filename,
1940 const char *section,
1956 empty_before = !u->requires_mounts_for;
1958 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1960 /* Make it easy to find units with requires_mounts set */
1961 if (empty_before && u->requires_mounts_for)
1962 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1967 int config_parse_documentation(
1968 const char *filename,
1970 const char *section,
1986 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1990 for (a = b = u->documentation; a && *a; a++) {
1992 if (is_valid_documentation_url(*a))
1995 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2004 #define FOLLOW_MAX 8
2006 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2017 /* This will update the filename pointer if the loaded file is
2018 * reached by a symlink. The old string will be freed. */
2021 char *target, *name;
2023 if (c++ >= FOLLOW_MAX)
2026 path_kill_slashes(*filename);
2028 /* Add the file name we are currently looking at to
2029 * the names of this unit, but only if it is a valid
2031 name = path_get_file_name(*filename);
2033 if (unit_name_is_valid(name, true)) {
2035 id = set_get(names, name);
2041 r = set_put(names, id);
2049 /* Try to open the file name, but don't if its a symlink */
2050 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2057 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2058 r = readlink_and_make_absolute(*filename, &target);
2066 f = fdopen(fd, "re");
2069 close_nointr_nofail(fd);
2078 static int merge_by_names(Unit **u, Set *names, const char *id) {
2086 /* Let's try to add in all symlink names we found */
2087 while ((k = set_steal_first(names))) {
2089 /* First try to merge in the other name into our
2091 r = unit_merge_by_name(*u, k);
2095 /* Hmm, we couldn't merge the other unit into
2096 * ours? Then let's try it the other way
2099 other = manager_get_unit((*u)->manager, k);
2103 r = unit_merge(other, *u);
2106 return merge_by_names(u, names, NULL);
2114 unit_choose_id(*u, id);
2122 static int load_from_path(Unit *u, const char *path) {
2126 char *filename = NULL, *id = NULL;
2133 symlink_names = set_new(string_hash_func, string_compare_func);
2137 if (path_is_absolute(path)) {
2139 filename = strdup(path);
2145 r = open_follow(&filename, &f, symlink_names, &id);
2157 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2159 /* Instead of opening the path right away, we manually
2160 * follow all symlinks and add their name to our unit
2161 * name set while doing so */
2162 filename = path_make_absolute(path, *p);
2168 if (u->manager->unit_path_cache &&
2169 !set_get(u->manager->unit_path_cache, filename))
2172 r = open_follow(&filename, &f, symlink_names, &id);
2181 /* Empty the symlink names for the next run */
2182 set_clear_free(symlink_names);
2191 /* Hmm, no suitable file found? */
2197 r = merge_by_names(&merged, symlink_names, id);
2202 u->load_state = UNIT_MERGED;
2208 if (fstat(fileno(f), &st) < 0) {
2213 if (null_or_empty(&st))
2214 u->load_state = UNIT_MASKED;
2216 /* Now, parse the file contents */
2217 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2221 u->load_state = UNIT_LOADED;
2224 free(u->fragment_path);
2225 u->fragment_path = filename;
2228 u->fragment_mtime = timespec_load(&st.st_mtim);
2230 if (u->source_path) {
2231 if (stat(u->source_path, &st) >= 0)
2232 u->source_mtime = timespec_load(&st.st_mtim);
2234 u->source_mtime = 0;
2240 set_free_free(symlink_names);
2249 int unit_load_fragment(Unit *u) {
2255 assert(u->load_state == UNIT_STUB);
2258 /* First, try to find the unit under its id. We always look
2259 * for unit files in the default directories, to make it easy
2260 * to override things by placing things in /etc/systemd/system */
2261 r = load_from_path(u, u->id);
2265 /* Try to find an alias we can load this with */
2266 if (u->load_state == UNIT_STUB)
2267 SET_FOREACH(t, u->names, i) {
2272 r = load_from_path(u, t);
2276 if (u->load_state != UNIT_STUB)
2280 /* And now, try looking for it under the suggested (originally linked) path */
2281 if (u->load_state == UNIT_STUB && u->fragment_path) {
2283 r = load_from_path(u, u->fragment_path);
2287 if (u->load_state == UNIT_STUB) {
2288 /* Hmm, this didn't work? Then let's get rid
2289 * of the fragment path stored for us, so that
2290 * we don't point to an invalid location. */
2291 free(u->fragment_path);
2292 u->fragment_path = NULL;
2296 /* Look for a template */
2297 if (u->load_state == UNIT_STUB && u->instance) {
2300 k = unit_name_template(u->id);
2304 r = load_from_path(u, k);
2310 if (u->load_state == UNIT_STUB)
2311 SET_FOREACH(t, u->names, i) {
2316 k = unit_name_template(t);
2320 r = load_from_path(u, k);
2326 if (u->load_state != UNIT_STUB)
2334 void unit_dump_config_items(FILE *f) {
2335 static const struct {
2336 const ConfigParserCallback callback;
2339 { config_parse_int, "INTEGER" },
2340 { config_parse_unsigned, "UNSIGNED" },
2341 { config_parse_bytes_size, "SIZE" },
2342 { config_parse_bool, "BOOLEAN" },
2343 { config_parse_string, "STRING" },
2344 { config_parse_path, "PATH" },
2345 { config_parse_unit_path_printf, "PATH" },
2346 { config_parse_strv, "STRING [...]" },
2347 { config_parse_exec_nice, "NICE" },
2348 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2349 { config_parse_exec_io_class, "IOCLASS" },
2350 { config_parse_exec_io_priority, "IOPRIORITY" },
2351 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2352 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2353 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2354 { config_parse_mode, "MODE" },
2355 { config_parse_unit_env_file, "FILE" },
2356 { config_parse_output, "OUTPUT" },
2357 { config_parse_input, "INPUT" },
2358 { config_parse_facility, "FACILITY" },
2359 { config_parse_level, "LEVEL" },
2360 { config_parse_exec_capabilities, "CAPABILITIES" },
2361 { config_parse_exec_secure_bits, "SECUREBITS" },
2362 { config_parse_bounding_set, "BOUNDINGSET" },
2363 { config_parse_limit, "LIMIT" },
2364 { config_parse_unit_cgroup, "CGROUP [...]" },
2365 { config_parse_unit_deps, "UNIT [...]" },
2366 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2367 { config_parse_service_type, "SERVICETYPE" },
2368 { config_parse_service_restart, "SERVICERESTART" },
2369 #ifdef HAVE_SYSV_COMPAT
2370 { config_parse_sysv_priority, "SYSVPRIORITY" },
2372 { config_parse_warn_compat, "NOTSUPPORTED" },
2374 { config_parse_kill_mode, "KILLMODE" },
2375 { config_parse_kill_signal, "SIGNAL" },
2376 { config_parse_socket_listen, "SOCKET [...]" },
2377 { config_parse_socket_bind, "SOCKETBIND" },
2378 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2379 { config_parse_usec, "SECONDS" },
2380 { config_parse_nsec, "NANOSECONDS" },
2381 { config_parse_path_strv, "PATH [...]" },
2382 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2383 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2384 { config_parse_unit_string_printf, "STRING" },
2385 { config_parse_timer, "TIMER" },
2386 { config_parse_timer_unit, "NAME" },
2387 { config_parse_path_spec, "PATH" },
2388 { config_parse_path_unit, "UNIT" },
2389 { config_parse_notify_access, "ACCESS" },
2390 { config_parse_ip_tos, "TOS" },
2391 { config_parse_unit_condition_path, "CONDITION" },
2392 { config_parse_unit_condition_string, "CONDITION" },
2393 { config_parse_unit_condition_null, "CONDITION" },
2396 const char *prev = NULL;
2401 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2402 const char *rvalue = "OTHER", *lvalue;
2406 const ConfigPerfItem *p;
2408 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2410 dot = strchr(i, '.');
2411 lvalue = dot ? dot + 1 : i;
2415 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2419 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2422 for (j = 0; j < ELEMENTSOF(table); j++)
2423 if (p->parse == table[j].callback) {
2424 rvalue = table[j].rvalue;
2428 fprintf(f, "%s=%s\n", lvalue, rvalue);