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]. */
444 bool honour_argv0 = false, ignore = false;
450 rvalue += strspn(rvalue, WHITESPACE);
455 if (rvalue[0] == '-') {
460 if (rvalue[0] == '@') {
465 if (*rvalue != '/') {
466 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
471 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
472 if (strncmp(w, ";", MAX(l, 1U)) == 0)
478 n = new(char*, k + !honour_argv0);
483 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
484 if (strncmp(w, ";", MAX(l, 1U)) == 0)
486 else if (strncmp(w, "\\;", MAX(l, 1U)) == 0)
489 if (honour_argv0 && w == rvalue) {
492 path = strndup(w, l);
498 if (!utf8_is_valid(path)) {
499 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
507 c = n[k++] = cunescape_length(w, l);
513 if (!utf8_is_valid(c)) {
514 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
524 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
537 assert(path_is_absolute(path));
539 nce = new0(ExecCommand, 1);
547 nce->ignore = ignore;
549 path_kill_slashes(nce->path);
551 exec_command_append_list(e, nce);
567 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
568 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
570 int config_parse_socket_bindtodevice(
571 const char *filename,
588 if (rvalue[0] && !streq(rvalue, "*")) {
589 if (!(n = strdup(rvalue)))
594 free(s->bind_to_device);
595 s->bind_to_device = n;
600 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
601 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
603 int config_parse_exec_io_class(
604 const char *filename,
613 ExecContext *c = data;
621 x = ioprio_class_from_string(rvalue);
623 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
627 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
628 c->ioprio_set = true;
633 int config_parse_exec_io_priority(
634 const char *filename,
643 ExecContext *c = data;
651 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
652 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
656 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
657 c->ioprio_set = true;
662 int config_parse_exec_cpu_sched_policy(
663 const char *filename,
673 ExecContext *c = data;
681 x = sched_policy_from_string(rvalue);
683 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
687 c->cpu_sched_policy = x;
688 c->cpu_sched_set = true;
693 int config_parse_exec_cpu_sched_prio(
694 const char *filename,
703 ExecContext *c = data;
711 /* On Linux RR/FIFO have the same range */
712 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
713 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
717 c->cpu_sched_priority = i;
718 c->cpu_sched_set = true;
723 int config_parse_exec_cpu_affinity(
724 const char *filename,
733 ExecContext *c = data;
743 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
748 if (!(t = strndup(w, l)))
751 r = safe_atou(t, &cpu);
755 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
758 if (r < 0 || cpu >= c->cpuset_ncpus) {
759 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
763 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
769 int config_parse_exec_capabilities(
770 const char *filename,
779 ExecContext *c = data;
787 if (!(cap = cap_from_text(rvalue))) {
791 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
796 cap_free(c->capabilities);
797 c->capabilities = cap;
802 int config_parse_exec_secure_bits(
803 const char *filename,
812 ExecContext *c = data;
822 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
823 if (first_word(w, "keep-caps"))
824 c->secure_bits |= SECURE_KEEP_CAPS;
825 else if (first_word(w, "keep-caps-locked"))
826 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
827 else if (first_word(w, "no-setuid-fixup"))
828 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
829 else if (first_word(w, "no-setuid-fixup-locked"))
830 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
831 else if (first_word(w, "noroot"))
832 c->secure_bits |= SECURE_NOROOT;
833 else if (first_word(w, "noroot-locked"))
834 c->secure_bits |= SECURE_NOROOT_LOCKED;
836 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
844 int config_parse_bounding_set(
845 const char *filename,
854 uint64_t *capability_bounding_set_drop = data;
866 if (rvalue[0] == '~') {
871 /* Note that we store this inverted internally, since the
872 * kernel wants it like this. But we actually expose it
873 * non-inverted everywhere to have a fully normalized
876 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
885 r = cap_from_name(t, &cap);
889 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
893 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
897 *capability_bounding_set_drop |= sum;
899 *capability_bounding_set_drop |= ~sum;
904 int config_parse_limit(
905 const char *filename,
914 struct rlimit **rl = data;
915 unsigned long long u;
924 if (streq(rvalue, "infinity"))
925 u = (unsigned long long) RLIM_INFINITY;
926 else if (safe_atollu(rvalue, &u) < 0) {
927 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
932 if (!(*rl = new(struct rlimit, 1)))
935 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
939 int config_parse_unit_cgroup(
940 const char *filename,
954 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
962 k = unit_full_printf(u, t);
974 r = unit_add_cgroup_from_text(u, t);
978 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
986 #ifdef HAVE_SYSV_COMPAT
987 int config_parse_sysv_priority(
988 const char *filename,
997 int *priority = data;
1005 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1006 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1010 *priority = (int) i;
1015 int config_parse_fsck_passno(
1016 const char *filename,
1018 const char *section,
1033 if (safe_atoi(rvalue, &i) || i < 0) {
1034 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1042 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1044 int config_parse_kill_signal(
1045 const char *filename,
1047 const char *section,
1062 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1063 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1071 int config_parse_exec_mount_flags(
1072 const char *filename,
1074 const char *section,
1081 ExecContext *c = data;
1085 unsigned long flags = 0;
1092 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1093 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1095 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1097 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1098 flags |= MS_PRIVATE;
1100 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1105 c->mount_flags = flags;
1109 int config_parse_timer(
1110 const char *filename,
1112 const char *section,
1129 if ((b = timer_base_from_string(lvalue)) < 0) {
1130 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1134 if (parse_usec(rvalue, &u) < 0) {
1135 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1139 if (!(v = new0(TimerValue, 1)))
1145 LIST_PREPEND(TimerValue, value, t->values, v);
1150 int config_parse_timer_unit(
1151 const char *filename,
1153 const char *section,
1170 dbus_error_init(&error);
1172 if (endswith(rvalue, ".timer")) {
1173 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1177 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1179 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1180 dbus_error_free(&error);
1184 unit_ref_set(&t->unit, u);
1189 int config_parse_path_spec(
1190 const char *filename,
1192 const char *section,
1209 b = path_type_from_string(lvalue);
1211 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1215 k = unit_full_printf(UNIT(p), rvalue);
1219 if (!path_is_absolute(k)) {
1220 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1225 s = new0(PathSpec, 1);
1231 s->path = path_kill_slashes(k);
1235 LIST_PREPEND(PathSpec, spec, p->specs, s);
1240 int config_parse_path_unit(
1241 const char *filename,
1243 const char *section,
1260 dbus_error_init(&error);
1262 if (endswith(rvalue, ".path")) {
1263 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1267 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1268 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1269 dbus_error_free(&error);
1273 unit_ref_set(&t->unit, u);
1278 int config_parse_socket_service(
1279 const char *filename,
1281 const char *section,
1298 dbus_error_init(&error);
1300 if (!endswith(rvalue, ".service")) {
1301 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1305 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1307 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1308 dbus_error_free(&error);
1312 unit_ref_set(&s->service, x);
1317 int config_parse_service_sockets(
1318 const char *filename,
1320 const char *section,
1337 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1344 k = unit_name_printf(UNIT(s), t);
1350 if (!endswith(k, ".socket")) {
1351 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1356 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1358 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1360 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1370 int config_parse_service_timeout(
1371 const char *filename,
1373 const char *section,
1380 Service *s = userdata;
1388 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1393 if (streq(lvalue, "TimeoutSec")) {
1394 s->start_timeout_defined = true;
1395 s->timeout_stop_usec = s->timeout_start_usec;
1396 } else if (streq(lvalue, "TimeoutStartSec"))
1397 s->start_timeout_defined = true;
1402 int config_parse_unit_env_file(
1403 const char *filename,
1405 const char *section,
1412 char ***env = data, **k;
1421 s = unit_full_printf(u, rvalue);
1425 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1426 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1431 k = strv_append(*env, s);
1442 int config_parse_ip_tos(
1443 const char *filename,
1445 const char *section,
1452 int *ip_tos = data, x;
1459 x = ip_tos_from_string(rvalue);
1461 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1469 int config_parse_unit_condition_path(
1470 const char *filename,
1472 const char *section,
1479 ConditionType cond = ltype;
1481 bool trigger, negate;
1483 _cleanup_free_ char *p = NULL;
1490 trigger = rvalue[0] == '|';
1494 negate = rvalue[0] == '!';
1498 p = unit_full_printf(u, rvalue);
1502 if (!path_is_absolute(p)) {
1503 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1507 c = condition_new(cond, p, trigger, negate);
1511 LIST_PREPEND(Condition, conditions, u->conditions, c);
1515 int config_parse_unit_condition_string(
1516 const char *filename,
1518 const char *section,
1525 ConditionType cond = ltype;
1527 bool trigger, negate;
1529 _cleanup_free_ char *s = NULL;
1536 trigger = rvalue[0] == '|';
1540 negate = rvalue[0] == '!';
1544 s = unit_full_printf(u, rvalue);
1548 c = condition_new(cond, s, trigger, negate);
1552 LIST_PREPEND(Condition, conditions, u->conditions, c);
1556 int config_parse_unit_condition_null(
1557 const char *filename,
1559 const char *section,
1568 bool trigger, negate;
1576 if ((trigger = rvalue[0] == '|'))
1579 if ((negate = rvalue[0] == '!'))
1582 if ((b = parse_boolean(rvalue)) < 0) {
1583 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1590 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1593 LIST_PREPEND(Condition, conditions, u->conditions, c);
1597 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1598 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1600 int config_parse_unit_cgroup_attr(
1601 const char *filename,
1603 const char *section,
1619 l = strv_split_quoted(rvalue);
1623 if (strv_length(l) != 2) {
1624 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1629 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1633 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1640 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) {
1651 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1652 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1656 if (asprintf(&t, "%lu", ul) < 0)
1659 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1663 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1670 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) {
1681 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1682 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1686 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1689 r = unit_add_cgroup_attribute(u,
1691 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1696 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1703 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1711 l = strv_split_quoted(value);
1715 assert(strv_length(l) >= 1);
1717 if (streq(l[0], "*")) {
1719 if (asprintf(ret, "a *:*%s%s",
1720 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1728 if (stat(l[0], &st) < 0) {
1729 log_warning("Couldn't stat device %s", l[0]);
1734 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1735 log_warning("%s is not a device.", l[0]);
1740 if (asprintf(ret, "%c %u:%u%s%s",
1741 S_ISCHR(st.st_mode) ? 'c' : 'b',
1742 major(st.st_rdev), minor(st.st_rdev),
1743 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1754 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) {
1765 l = strv_split_quoted(rvalue);
1770 if (k < 1 || k > 2) {
1771 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1776 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1777 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1782 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1783 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1789 r = unit_add_cgroup_attribute(u, "devices",
1790 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1791 rvalue, device_map);
1794 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1801 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1811 l = strv_split_quoted(value);
1815 assert(strv_length(l) == 2);
1817 if (stat(l[0], &st) < 0) {
1818 log_warning("Couldn't stat device %s", l[0]);
1823 if (S_ISBLK(st.st_mode))
1825 else if (major(st.st_dev) != 0) {
1826 /* If this is not a device node then find the block
1827 * device this file is stored on */
1830 /* If this is a partition, try to get the originating
1832 block_get_whole_disk(d, &d);
1834 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1839 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1848 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) {
1852 const char *device = NULL, *weight;
1861 l = strv_split_quoted(rvalue);
1866 if (k < 1 || k > 2) {
1867 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1879 if (device && !path_is_absolute(device)) {
1880 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1885 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1886 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1892 r = asprintf(&t, "%s %lu", device, ul);
1894 r = asprintf(&t, "%lu", ul);
1901 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1903 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1907 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1914 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) {
1926 l = strv_split_quoted(rvalue);
1932 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1937 if (!path_is_absolute(l[0])) {
1938 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1943 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1944 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1949 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1955 r = unit_add_cgroup_attribute(u, "blkio",
1956 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1961 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1968 int config_parse_unit_requires_mounts_for(
1969 const char *filename,
1971 const char *section,
1987 empty_before = !u->requires_mounts_for;
1989 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1991 /* Make it easy to find units with requires_mounts set */
1992 if (empty_before && u->requires_mounts_for)
1993 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1998 int config_parse_documentation(
1999 const char *filename,
2001 const char *section,
2017 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2021 for (a = b = u->documentation; a && *a; a++) {
2023 if (is_valid_documentation_url(*a))
2026 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2035 static void syscall_set(uint32_t *p, int nr) {
2036 p[nr >> 4] |= 1 << (nr & 31);
2039 static void syscall_unset(uint32_t *p, int nr) {
2040 p[nr >> 4] &= ~(1 << (nr & 31));
2043 int config_parse_syscall_filter(
2044 const char *filename,
2046 const char *section,
2053 ExecContext *c = data;
2055 bool invert = false;
2065 if (rvalue[0] == '~') {
2070 if (!c->syscall_filter) {
2073 n = (syscall_max() + 31) >> 4;
2074 c->syscall_filter = new(uint32_t, n);
2075 if (!c->syscall_filter)
2078 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2080 /* Add these by default */
2081 syscall_set(c->syscall_filter, __NR_execve);
2082 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2083 #ifdef __NR_sigreturn
2084 syscall_set(c->syscall_filter, __NR_sigreturn);
2086 syscall_set(c->syscall_filter, __NR_exit_group);
2087 syscall_set(c->syscall_filter, __NR_exit);
2090 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2098 id = syscall_from_name(t);
2102 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2107 syscall_unset(c->syscall_filter, id);
2109 syscall_set(c->syscall_filter, id);
2112 c->no_new_privileges = true;
2117 #define FOLLOW_MAX 8
2119 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2130 /* This will update the filename pointer if the loaded file is
2131 * reached by a symlink. The old string will be freed. */
2134 char *target, *name;
2136 if (c++ >= FOLLOW_MAX)
2139 path_kill_slashes(*filename);
2141 /* Add the file name we are currently looking at to
2142 * the names of this unit, but only if it is a valid
2144 name = path_get_file_name(*filename);
2146 if (unit_name_is_valid(name, true)) {
2148 id = set_get(names, name);
2154 r = set_put(names, id);
2162 /* Try to open the file name, but don't if its a symlink */
2163 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2170 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2171 r = readlink_and_make_absolute(*filename, &target);
2179 f = fdopen(fd, "re");
2182 close_nointr_nofail(fd);
2191 static int merge_by_names(Unit **u, Set *names, const char *id) {
2199 /* Let's try to add in all symlink names we found */
2200 while ((k = set_steal_first(names))) {
2202 /* First try to merge in the other name into our
2204 r = unit_merge_by_name(*u, k);
2208 /* Hmm, we couldn't merge the other unit into
2209 * ours? Then let's try it the other way
2212 other = manager_get_unit((*u)->manager, k);
2216 r = unit_merge(other, *u);
2219 return merge_by_names(u, names, NULL);
2227 unit_choose_id(*u, id);
2235 static int load_from_path(Unit *u, const char *path) {
2239 char *filename = NULL, *id = NULL;
2246 symlink_names = set_new(string_hash_func, string_compare_func);
2250 if (path_is_absolute(path)) {
2252 filename = strdup(path);
2258 r = open_follow(&filename, &f, symlink_names, &id);
2270 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2272 /* Instead of opening the path right away, we manually
2273 * follow all symlinks and add their name to our unit
2274 * name set while doing so */
2275 filename = path_make_absolute(path, *p);
2281 if (u->manager->unit_path_cache &&
2282 !set_get(u->manager->unit_path_cache, filename))
2285 r = open_follow(&filename, &f, symlink_names, &id);
2294 /* Empty the symlink names for the next run */
2295 set_clear_free(symlink_names);
2304 /* Hmm, no suitable file found? */
2310 r = merge_by_names(&merged, symlink_names, id);
2315 u->load_state = UNIT_MERGED;
2320 if (fstat(fileno(f), &st) < 0) {
2325 if (null_or_empty(&st))
2326 u->load_state = UNIT_MASKED;
2328 /* Now, parse the file contents */
2329 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2333 u->load_state = UNIT_LOADED;
2336 free(u->fragment_path);
2337 u->fragment_path = filename;
2340 u->fragment_mtime = timespec_load(&st.st_mtim);
2342 if (u->source_path) {
2343 if (stat(u->source_path, &st) >= 0)
2344 u->source_mtime = timespec_load(&st.st_mtim);
2346 u->source_mtime = 0;
2352 set_free_free(symlink_names);
2361 int unit_load_fragment(Unit *u) {
2367 assert(u->load_state == UNIT_STUB);
2370 /* First, try to find the unit under its id. We always look
2371 * for unit files in the default directories, to make it easy
2372 * to override things by placing things in /etc/systemd/system */
2373 r = load_from_path(u, u->id);
2377 /* Try to find an alias we can load this with */
2378 if (u->load_state == UNIT_STUB)
2379 SET_FOREACH(t, u->names, i) {
2384 r = load_from_path(u, t);
2388 if (u->load_state != UNIT_STUB)
2392 /* And now, try looking for it under the suggested (originally linked) path */
2393 if (u->load_state == UNIT_STUB && u->fragment_path) {
2395 r = load_from_path(u, u->fragment_path);
2399 if (u->load_state == UNIT_STUB) {
2400 /* Hmm, this didn't work? Then let's get rid
2401 * of the fragment path stored for us, so that
2402 * we don't point to an invalid location. */
2403 free(u->fragment_path);
2404 u->fragment_path = NULL;
2408 /* Look for a template */
2409 if (u->load_state == UNIT_STUB && u->instance) {
2412 k = unit_name_template(u->id);
2416 r = load_from_path(u, k);
2422 if (u->load_state == UNIT_STUB)
2423 SET_FOREACH(t, u->names, i) {
2428 k = unit_name_template(t);
2432 r = load_from_path(u, k);
2438 if (u->load_state != UNIT_STUB)
2446 void unit_dump_config_items(FILE *f) {
2447 static const struct {
2448 const ConfigParserCallback callback;
2451 { config_parse_int, "INTEGER" },
2452 { config_parse_unsigned, "UNSIGNED" },
2453 { config_parse_bytes_size, "SIZE" },
2454 { config_parse_bool, "BOOLEAN" },
2455 { config_parse_string, "STRING" },
2456 { config_parse_path, "PATH" },
2457 { config_parse_unit_path_printf, "PATH" },
2458 { config_parse_strv, "STRING [...]" },
2459 { config_parse_exec_nice, "NICE" },
2460 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2461 { config_parse_exec_io_class, "IOCLASS" },
2462 { config_parse_exec_io_priority, "IOPRIORITY" },
2463 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2464 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2465 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2466 { config_parse_mode, "MODE" },
2467 { config_parse_unit_env_file, "FILE" },
2468 { config_parse_output, "OUTPUT" },
2469 { config_parse_input, "INPUT" },
2470 { config_parse_facility, "FACILITY" },
2471 { config_parse_level, "LEVEL" },
2472 { config_parse_exec_capabilities, "CAPABILITIES" },
2473 { config_parse_exec_secure_bits, "SECUREBITS" },
2474 { config_parse_bounding_set, "BOUNDINGSET" },
2475 { config_parse_limit, "LIMIT" },
2476 { config_parse_unit_cgroup, "CGROUP [...]" },
2477 { config_parse_unit_deps, "UNIT [...]" },
2478 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2479 { config_parse_service_type, "SERVICETYPE" },
2480 { config_parse_service_restart, "SERVICERESTART" },
2481 #ifdef HAVE_SYSV_COMPAT
2482 { config_parse_sysv_priority, "SYSVPRIORITY" },
2484 { config_parse_warn_compat, "NOTSUPPORTED" },
2486 { config_parse_kill_mode, "KILLMODE" },
2487 { config_parse_kill_signal, "SIGNAL" },
2488 { config_parse_socket_listen, "SOCKET [...]" },
2489 { config_parse_socket_bind, "SOCKETBIND" },
2490 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2491 { config_parse_usec, "SECONDS" },
2492 { config_parse_nsec, "NANOSECONDS" },
2493 { config_parse_path_strv, "PATH [...]" },
2494 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2495 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2496 { config_parse_unit_string_printf, "STRING" },
2497 { config_parse_timer, "TIMER" },
2498 { config_parse_timer_unit, "NAME" },
2499 { config_parse_path_spec, "PATH" },
2500 { config_parse_path_unit, "UNIT" },
2501 { config_parse_notify_access, "ACCESS" },
2502 { config_parse_ip_tos, "TOS" },
2503 { config_parse_unit_condition_path, "CONDITION" },
2504 { config_parse_unit_condition_string, "CONDITION" },
2505 { config_parse_unit_condition_null, "CONDITION" },
2508 const char *prev = NULL;
2513 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2514 const char *rvalue = "OTHER", *lvalue;
2518 const ConfigPerfItem *p;
2520 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2522 dot = strchr(i, '.');
2523 lvalue = dot ? dot + 1 : i;
2527 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2531 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2534 for (j = 0; j < ELEMENTSOF(table); j++)
2535 if (p->parse == table[j].callback) {
2536 rvalue = table[j].rvalue;
2540 fprintf(f, "%s=%s\n", lvalue, rvalue);