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 "unit-printf.h"
46 #include "bus-errors.h"
48 #include "path-util.h"
49 #include "syscall-list.h"
51 #ifndef HAVE_SYSV_COMPAT
52 int config_parse_warn_compat(
62 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
67 int config_parse_unit_deps(
77 UnitDependency d = ltype;
87 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
95 k = unit_name_printf(u, t);
100 r = unit_add_dependency_by_name(u, d, k, NULL, true);
102 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
110 int config_parse_unit_string_printf(
111 const char *filename,
129 k = unit_full_printf(u, rvalue);
133 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
139 int config_parse_unit_strv_printf(
140 const char *filename,
158 k = unit_full_printf(u, rvalue);
162 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
168 int config_parse_unit_path_printf(
169 const char *filename,
187 k = unit_full_printf(u, rvalue);
191 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
197 int config_parse_socket_listen(
198 const char *filename,
207 SocketPort *p, *tail;
217 p = new0(SocketPort, 1);
221 if (streq(lvalue, "ListenFIFO")) {
222 p->type = SOCKET_FIFO;
224 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
229 path_kill_slashes(p->path);
231 } else if (streq(lvalue, "ListenSpecial")) {
232 p->type = SOCKET_SPECIAL;
234 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
239 path_kill_slashes(p->path);
241 } else if (streq(lvalue, "ListenMessageQueue")) {
243 p->type = SOCKET_MQUEUE;
245 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
250 path_kill_slashes(p->path);
252 } else if (streq(lvalue, "ListenNetlink")) {
256 p->type = SOCKET_SOCKET;
257 k = unit_full_printf(UNIT(s), rvalue);
258 r = socket_address_parse_netlink(&p->address, k);
262 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
271 p->type = SOCKET_SOCKET;
272 k = unit_full_printf(UNIT(s), rvalue);
273 r = socket_address_parse(&p->address, k);
277 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
282 if (streq(lvalue, "ListenStream"))
283 p->address.type = SOCK_STREAM;
284 else if (streq(lvalue, "ListenDatagram"))
285 p->address.type = SOCK_DGRAM;
287 assert(streq(lvalue, "ListenSequentialPacket"));
288 p->address.type = SOCK_SEQPACKET;
291 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
292 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
301 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
302 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
304 LIST_PREPEND(SocketPort, port, s->ports, p);
309 int config_parse_socket_bind(
310 const char *filename,
320 SocketAddressBindIPv6Only b;
329 b = socket_address_bind_ipv6_only_from_string(rvalue);
333 r = parse_boolean(rvalue);
335 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
339 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
341 s->bind_ipv6_only = b;
346 int config_parse_exec_nice(
347 const char *filename,
356 ExecContext *c = data;
364 if (safe_atoi(rvalue, &priority) < 0) {
365 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
369 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
370 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
380 int config_parse_exec_oom_score_adjust(
381 const char *filename,
390 ExecContext *c = data;
398 if (safe_atoi(rvalue, &oa) < 0) {
399 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
403 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
404 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
408 c->oom_score_adjust = oa;
409 c->oom_score_adjust_set = true;
414 int config_parse_exec(
415 const char *filename,
424 ExecCommand **e = data, *nce;
434 /* We accept an absolute path as first argument, or
435 * alternatively an absolute prefixed with @ to allow
436 * overriding of argv[0]. */
445 bool honour_argv0 = false, ignore = false;
451 rvalue += strspn(rvalue, WHITESPACE);
456 for (i = 0; i < 2; i++) {
457 if (rvalue[0] == '-' && !ignore) {
462 if (rvalue[0] == '@' && !honour_argv0) {
468 if (*rvalue != '/') {
469 log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
470 filename, line, rvalue);
475 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
476 if (strncmp(w, ";", MAX(l, 1U)) == 0)
482 n = new(char*, k + !honour_argv0);
487 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
488 if (strncmp(w, ";", MAX(l, 1U)) == 0)
490 else if (strncmp(w, "\\;", MAX(l, 1U)) == 0)
493 if (honour_argv0 && w == rvalue) {
496 path = strndup(w, l);
502 if (!utf8_is_valid(path)) {
503 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
511 c = n[k++] = cunescape_length(w, l);
517 if (!utf8_is_valid(c)) {
518 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
528 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
541 assert(path_is_absolute(path));
543 nce = new0(ExecCommand, 1);
551 nce->ignore = ignore;
553 path_kill_slashes(nce->path);
555 exec_command_append_list(e, nce);
571 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
572 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
574 int config_parse_socket_bindtodevice(
575 const char *filename,
592 if (rvalue[0] && !streq(rvalue, "*")) {
593 if (!(n = strdup(rvalue)))
598 free(s->bind_to_device);
599 s->bind_to_device = n;
604 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
605 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
607 int config_parse_exec_io_class(
608 const char *filename,
617 ExecContext *c = data;
625 x = ioprio_class_from_string(rvalue);
627 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
631 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
632 c->ioprio_set = true;
637 int config_parse_exec_io_priority(
638 const char *filename,
647 ExecContext *c = data;
655 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
656 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
660 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
661 c->ioprio_set = true;
666 int config_parse_exec_cpu_sched_policy(
667 const char *filename,
677 ExecContext *c = data;
685 x = sched_policy_from_string(rvalue);
687 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
691 c->cpu_sched_policy = x;
692 c->cpu_sched_set = true;
697 int config_parse_exec_cpu_sched_prio(
698 const char *filename,
707 ExecContext *c = data;
715 /* On Linux RR/FIFO have the same range */
716 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
717 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
721 c->cpu_sched_priority = i;
722 c->cpu_sched_set = true;
727 int config_parse_exec_cpu_affinity(
728 const char *filename,
737 ExecContext *c = data;
747 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
752 if (!(t = strndup(w, l)))
755 r = safe_atou(t, &cpu);
759 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
762 if (r < 0 || cpu >= c->cpuset_ncpus) {
763 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
767 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
773 int config_parse_exec_capabilities(
774 const char *filename,
783 ExecContext *c = data;
791 if (!(cap = cap_from_text(rvalue))) {
795 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
800 cap_free(c->capabilities);
801 c->capabilities = cap;
806 int config_parse_exec_secure_bits(
807 const char *filename,
816 ExecContext *c = data;
826 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
827 if (first_word(w, "keep-caps"))
828 c->secure_bits |= SECURE_KEEP_CAPS;
829 else if (first_word(w, "keep-caps-locked"))
830 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
831 else if (first_word(w, "no-setuid-fixup"))
832 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
833 else if (first_word(w, "no-setuid-fixup-locked"))
834 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
835 else if (first_word(w, "noroot"))
836 c->secure_bits |= SECURE_NOROOT;
837 else if (first_word(w, "noroot-locked"))
838 c->secure_bits |= SECURE_NOROOT_LOCKED;
840 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
848 int config_parse_bounding_set(
849 const char *filename,
858 uint64_t *capability_bounding_set_drop = data;
870 if (rvalue[0] == '~') {
875 /* Note that we store this inverted internally, since the
876 * kernel wants it like this. But we actually expose it
877 * non-inverted everywhere to have a fully normalized
880 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
889 r = cap_from_name(t, &cap);
893 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
897 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
901 *capability_bounding_set_drop |= sum;
903 *capability_bounding_set_drop |= ~sum;
908 int config_parse_limit(
909 const char *filename,
918 struct rlimit **rl = data;
919 unsigned long long u;
928 if (streq(rvalue, "infinity"))
929 u = (unsigned long long) RLIM_INFINITY;
930 else if (safe_atollu(rvalue, &u) < 0) {
931 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
936 if (!(*rl = new(struct rlimit, 1)))
939 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
943 int config_parse_unit_cgroup(
944 const char *filename,
958 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
966 k = unit_full_printf(u, t);
978 r = unit_add_cgroup_from_text(u, t);
982 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
990 #ifdef HAVE_SYSV_COMPAT
991 int config_parse_sysv_priority(
992 const char *filename,
1001 int *priority = data;
1009 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1010 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1014 *priority = (int) i;
1019 int config_parse_fsck_passno(
1020 const char *filename,
1022 const char *section,
1037 if (safe_atoi(rvalue, &i) || i < 0) {
1038 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1046 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1048 int config_parse_kill_signal(
1049 const char *filename,
1051 const char *section,
1066 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1067 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1075 int config_parse_exec_mount_flags(
1076 const char *filename,
1078 const char *section,
1085 ExecContext *c = data;
1089 unsigned long flags = 0;
1096 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1097 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1099 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1101 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1102 flags |= MS_PRIVATE;
1104 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1109 c->mount_flags = flags;
1113 int config_parse_timer(
1114 const char *filename,
1116 const char *section,
1133 if ((b = timer_base_from_string(lvalue)) < 0) {
1134 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1138 if (parse_usec(rvalue, &u) < 0) {
1139 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1143 if (!(v = new0(TimerValue, 1)))
1149 LIST_PREPEND(TimerValue, value, t->values, v);
1154 int config_parse_timer_unit(
1155 const char *filename,
1157 const char *section,
1174 dbus_error_init(&error);
1176 if (endswith(rvalue, ".timer")) {
1177 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1181 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1183 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1184 dbus_error_free(&error);
1188 unit_ref_set(&t->unit, u);
1193 int config_parse_path_spec(
1194 const char *filename,
1196 const char *section,
1213 b = path_type_from_string(lvalue);
1215 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1219 k = unit_full_printf(UNIT(p), rvalue);
1223 if (!path_is_absolute(k)) {
1224 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1229 s = new0(PathSpec, 1);
1235 s->path = path_kill_slashes(k);
1239 LIST_PREPEND(PathSpec, spec, p->specs, s);
1244 int config_parse_path_unit(
1245 const char *filename,
1247 const char *section,
1264 dbus_error_init(&error);
1266 if (endswith(rvalue, ".path")) {
1267 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1271 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1272 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1273 dbus_error_free(&error);
1277 unit_ref_set(&t->unit, u);
1282 int config_parse_socket_service(
1283 const char *filename,
1285 const char *section,
1302 dbus_error_init(&error);
1304 if (!endswith(rvalue, ".service")) {
1305 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1309 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1311 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1312 dbus_error_free(&error);
1316 unit_ref_set(&s->service, x);
1321 int config_parse_service_sockets(
1322 const char *filename,
1324 const char *section,
1341 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1348 k = unit_name_printf(UNIT(s), t);
1354 if (!endswith(k, ".socket")) {
1355 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1360 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1362 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1364 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1374 int config_parse_service_timeout(
1375 const char *filename,
1377 const char *section,
1384 Service *s = userdata;
1392 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1397 if (streq(lvalue, "TimeoutSec")) {
1398 s->start_timeout_defined = true;
1399 s->timeout_stop_usec = s->timeout_start_usec;
1400 } else if (streq(lvalue, "TimeoutStartSec"))
1401 s->start_timeout_defined = true;
1406 int config_parse_unit_env_file(
1407 const char *filename,
1409 const char *section,
1416 char ***env = data, **k;
1425 s = unit_full_printf(u, rvalue);
1429 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1430 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1435 k = strv_append(*env, s);
1446 int config_parse_ip_tos(
1447 const char *filename,
1449 const char *section,
1456 int *ip_tos = data, x;
1463 x = ip_tos_from_string(rvalue);
1465 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1473 int config_parse_unit_condition_path(
1474 const char *filename,
1476 const char *section,
1483 ConditionType cond = ltype;
1485 bool trigger, negate;
1487 _cleanup_free_ char *p = NULL;
1494 trigger = rvalue[0] == '|';
1498 negate = rvalue[0] == '!';
1502 p = unit_full_printf(u, rvalue);
1506 if (!path_is_absolute(p)) {
1507 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1511 c = condition_new(cond, p, trigger, negate);
1515 LIST_PREPEND(Condition, conditions, u->conditions, c);
1519 int config_parse_unit_condition_string(
1520 const char *filename,
1522 const char *section,
1529 ConditionType cond = ltype;
1531 bool trigger, negate;
1533 _cleanup_free_ char *s = NULL;
1540 trigger = rvalue[0] == '|';
1544 negate = rvalue[0] == '!';
1548 s = unit_full_printf(u, rvalue);
1552 c = condition_new(cond, s, trigger, negate);
1556 LIST_PREPEND(Condition, conditions, u->conditions, c);
1560 int config_parse_unit_condition_null(
1561 const char *filename,
1563 const char *section,
1572 bool trigger, negate;
1580 if ((trigger = rvalue[0] == '|'))
1583 if ((negate = rvalue[0] == '!'))
1586 if ((b = parse_boolean(rvalue)) < 0) {
1587 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1594 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1597 LIST_PREPEND(Condition, conditions, u->conditions, c);
1601 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1602 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1604 int config_parse_unit_cgroup_attr(
1605 const char *filename,
1607 const char *section,
1623 l = strv_split_quoted(rvalue);
1627 if (strv_length(l) != 2) {
1628 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1633 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1637 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1644 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) {
1655 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1656 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1660 if (asprintf(&t, "%lu", ul) < 0)
1663 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1667 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1674 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) {
1685 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1686 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1690 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1693 r = unit_add_cgroup_attribute(u,
1695 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1700 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1707 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1715 l = strv_split_quoted(value);
1719 assert(strv_length(l) >= 1);
1721 if (streq(l[0], "*")) {
1723 if (asprintf(ret, "a *:*%s%s",
1724 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1732 if (stat(l[0], &st) < 0) {
1733 log_warning("Couldn't stat device %s", l[0]);
1738 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1739 log_warning("%s is not a device.", l[0]);
1744 if (asprintf(ret, "%c %u:%u%s%s",
1745 S_ISCHR(st.st_mode) ? 'c' : 'b',
1746 major(st.st_rdev), minor(st.st_rdev),
1747 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1758 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) {
1769 l = strv_split_quoted(rvalue);
1774 if (k < 1 || k > 2) {
1775 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1780 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1781 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1786 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1787 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1793 r = unit_add_cgroup_attribute(u, "devices",
1794 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1795 rvalue, device_map);
1798 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1805 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1815 l = strv_split_quoted(value);
1819 assert(strv_length(l) == 2);
1821 if (stat(l[0], &st) < 0) {
1822 log_warning("Couldn't stat device %s", l[0]);
1827 if (S_ISBLK(st.st_mode))
1829 else if (major(st.st_dev) != 0) {
1830 /* If this is not a device node then find the block
1831 * device this file is stored on */
1834 /* If this is a partition, try to get the originating
1836 block_get_whole_disk(d, &d);
1838 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1843 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1852 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) {
1856 const char *device = NULL, *weight;
1865 l = strv_split_quoted(rvalue);
1870 if (k < 1 || k > 2) {
1871 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1883 if (device && !path_is_absolute(device)) {
1884 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1889 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1890 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1896 r = asprintf(&t, "%s %lu", device, ul);
1898 r = asprintf(&t, "%lu", ul);
1905 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1907 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1911 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1918 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) {
1930 l = strv_split_quoted(rvalue);
1936 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1941 if (!path_is_absolute(l[0])) {
1942 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1947 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1948 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1953 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1959 r = unit_add_cgroup_attribute(u, "blkio",
1960 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1965 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1972 int config_parse_unit_requires_mounts_for(
1973 const char *filename,
1975 const char *section,
1991 empty_before = !u->requires_mounts_for;
1993 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1995 /* Make it easy to find units with requires_mounts set */
1996 if (empty_before && u->requires_mounts_for)
1997 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2002 int config_parse_documentation(
2003 const char *filename,
2005 const char *section,
2021 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2025 for (a = b = u->documentation; a && *a; a++) {
2027 if (is_valid_documentation_url(*a))
2030 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2039 static void syscall_set(uint32_t *p, int nr) {
2040 p[nr >> 4] |= 1 << (nr & 31);
2043 static void syscall_unset(uint32_t *p, int nr) {
2044 p[nr >> 4] &= ~(1 << (nr & 31));
2047 int config_parse_syscall_filter(
2048 const char *filename,
2050 const char *section,
2057 ExecContext *c = data;
2059 bool invert = false;
2069 if (rvalue[0] == '~') {
2074 if (!c->syscall_filter) {
2077 n = (syscall_max() + 31) >> 4;
2078 c->syscall_filter = new(uint32_t, n);
2079 if (!c->syscall_filter)
2082 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2084 /* Add these by default */
2085 syscall_set(c->syscall_filter, __NR_execve);
2086 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2087 #ifdef __NR_sigreturn
2088 syscall_set(c->syscall_filter, __NR_sigreturn);
2090 syscall_set(c->syscall_filter, __NR_exit_group);
2091 syscall_set(c->syscall_filter, __NR_exit);
2094 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2102 id = syscall_from_name(t);
2106 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2111 syscall_unset(c->syscall_filter, id);
2113 syscall_set(c->syscall_filter, id);
2116 c->no_new_privileges = true;
2121 #define FOLLOW_MAX 8
2123 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2134 /* This will update the filename pointer if the loaded file is
2135 * reached by a symlink. The old string will be freed. */
2138 char *target, *name;
2140 if (c++ >= FOLLOW_MAX)
2143 path_kill_slashes(*filename);
2145 /* Add the file name we are currently looking at to
2146 * the names of this unit, but only if it is a valid
2148 name = path_get_file_name(*filename);
2150 if (unit_name_is_valid(name, true)) {
2152 id = set_get(names, name);
2158 r = set_put(names, id);
2166 /* Try to open the file name, but don't if its a symlink */
2167 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2174 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2175 r = readlink_and_make_absolute(*filename, &target);
2183 f = fdopen(fd, "re");
2186 close_nointr_nofail(fd);
2195 static int merge_by_names(Unit **u, Set *names, const char *id) {
2203 /* Let's try to add in all symlink names we found */
2204 while ((k = set_steal_first(names))) {
2206 /* First try to merge in the other name into our
2208 r = unit_merge_by_name(*u, k);
2212 /* Hmm, we couldn't merge the other unit into
2213 * ours? Then let's try it the other way
2216 other = manager_get_unit((*u)->manager, k);
2220 r = unit_merge(other, *u);
2223 return merge_by_names(u, names, NULL);
2231 unit_choose_id(*u, id);
2239 static int load_from_path(Unit *u, const char *path) {
2243 char *filename = NULL, *id = NULL;
2250 symlink_names = set_new(string_hash_func, string_compare_func);
2254 if (path_is_absolute(path)) {
2256 filename = strdup(path);
2262 r = open_follow(&filename, &f, symlink_names, &id);
2274 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2276 /* Instead of opening the path right away, we manually
2277 * follow all symlinks and add their name to our unit
2278 * name set while doing so */
2279 filename = path_make_absolute(path, *p);
2285 if (u->manager->unit_path_cache &&
2286 !set_get(u->manager->unit_path_cache, filename))
2289 r = open_follow(&filename, &f, symlink_names, &id);
2298 /* Empty the symlink names for the next run */
2299 set_clear_free(symlink_names);
2308 /* Hmm, no suitable file found? */
2314 r = merge_by_names(&merged, symlink_names, id);
2319 u->load_state = UNIT_MERGED;
2324 if (fstat(fileno(f), &st) < 0) {
2329 if (null_or_empty(&st))
2330 u->load_state = UNIT_MASKED;
2332 /* Now, parse the file contents */
2333 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2337 u->load_state = UNIT_LOADED;
2340 free(u->fragment_path);
2341 u->fragment_path = filename;
2344 u->fragment_mtime = timespec_load(&st.st_mtim);
2346 if (u->source_path) {
2347 if (stat(u->source_path, &st) >= 0)
2348 u->source_mtime = timespec_load(&st.st_mtim);
2350 u->source_mtime = 0;
2356 set_free_free(symlink_names);
2365 int unit_load_fragment(Unit *u) {
2371 assert(u->load_state == UNIT_STUB);
2374 /* First, try to find the unit under its id. We always look
2375 * for unit files in the default directories, to make it easy
2376 * to override things by placing things in /etc/systemd/system */
2377 r = load_from_path(u, u->id);
2381 /* Try to find an alias we can load this with */
2382 if (u->load_state == UNIT_STUB)
2383 SET_FOREACH(t, u->names, i) {
2388 r = load_from_path(u, t);
2392 if (u->load_state != UNIT_STUB)
2396 /* And now, try looking for it under the suggested (originally linked) path */
2397 if (u->load_state == UNIT_STUB && u->fragment_path) {
2399 r = load_from_path(u, u->fragment_path);
2403 if (u->load_state == UNIT_STUB) {
2404 /* Hmm, this didn't work? Then let's get rid
2405 * of the fragment path stored for us, so that
2406 * we don't point to an invalid location. */
2407 free(u->fragment_path);
2408 u->fragment_path = NULL;
2412 /* Look for a template */
2413 if (u->load_state == UNIT_STUB && u->instance) {
2416 k = unit_name_template(u->id);
2420 r = load_from_path(u, k);
2426 if (u->load_state == UNIT_STUB)
2427 SET_FOREACH(t, u->names, i) {
2432 k = unit_name_template(t);
2436 r = load_from_path(u, k);
2442 if (u->load_state != UNIT_STUB)
2450 void unit_dump_config_items(FILE *f) {
2451 static const struct {
2452 const ConfigParserCallback callback;
2455 { config_parse_int, "INTEGER" },
2456 { config_parse_unsigned, "UNSIGNED" },
2457 { config_parse_bytes_size, "SIZE" },
2458 { config_parse_bool, "BOOLEAN" },
2459 { config_parse_string, "STRING" },
2460 { config_parse_path, "PATH" },
2461 { config_parse_unit_path_printf, "PATH" },
2462 { config_parse_strv, "STRING [...]" },
2463 { config_parse_exec_nice, "NICE" },
2464 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2465 { config_parse_exec_io_class, "IOCLASS" },
2466 { config_parse_exec_io_priority, "IOPRIORITY" },
2467 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2468 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2469 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2470 { config_parse_mode, "MODE" },
2471 { config_parse_unit_env_file, "FILE" },
2472 { config_parse_output, "OUTPUT" },
2473 { config_parse_input, "INPUT" },
2474 { config_parse_facility, "FACILITY" },
2475 { config_parse_level, "LEVEL" },
2476 { config_parse_exec_capabilities, "CAPABILITIES" },
2477 { config_parse_exec_secure_bits, "SECUREBITS" },
2478 { config_parse_bounding_set, "BOUNDINGSET" },
2479 { config_parse_limit, "LIMIT" },
2480 { config_parse_unit_cgroup, "CGROUP [...]" },
2481 { config_parse_unit_deps, "UNIT [...]" },
2482 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2483 { config_parse_service_type, "SERVICETYPE" },
2484 { config_parse_service_restart, "SERVICERESTART" },
2485 #ifdef HAVE_SYSV_COMPAT
2486 { config_parse_sysv_priority, "SYSVPRIORITY" },
2488 { config_parse_warn_compat, "NOTSUPPORTED" },
2490 { config_parse_kill_mode, "KILLMODE" },
2491 { config_parse_kill_signal, "SIGNAL" },
2492 { config_parse_socket_listen, "SOCKET [...]" },
2493 { config_parse_socket_bind, "SOCKETBIND" },
2494 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2495 { config_parse_usec, "SECONDS" },
2496 { config_parse_nsec, "NANOSECONDS" },
2497 { config_parse_path_strv, "PATH [...]" },
2498 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2499 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2500 { config_parse_unit_string_printf, "STRING" },
2501 { config_parse_timer, "TIMER" },
2502 { config_parse_timer_unit, "NAME" },
2503 { config_parse_path_spec, "PATH" },
2504 { config_parse_path_unit, "UNIT" },
2505 { config_parse_notify_access, "ACCESS" },
2506 { config_parse_ip_tos, "TOS" },
2507 { config_parse_unit_condition_path, "CONDITION" },
2508 { config_parse_unit_condition_string, "CONDITION" },
2509 { config_parse_unit_condition_null, "CONDITION" },
2512 const char *prev = NULL;
2517 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2518 const char *rvalue = "OTHER", *lvalue;
2522 const ConfigPerfItem *p;
2524 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2526 dot = strchr(i, '.');
2527 lvalue = dot ? dot + 1 : i;
2531 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2535 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2538 for (j = 0; j < ELEMENTSOF(table); j++)
2539 if (p->parse == table[j].callback) {
2540 rvalue = table[j].rvalue;
2544 fprintf(f, "%s=%s\n", lvalue, rvalue);