1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2012 Holger Hans Peter Freyther
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/oom.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
35 #include <sys/resource.h>
39 #include "conf-parser.h"
40 #include "load-fragment.h"
43 #include "securebits.h"
45 #include "unit-name.h"
46 #include "unit-printf.h"
47 #include "bus-errors.h"
49 #include "path-util.h"
50 #include "syscall-list.h"
52 #ifndef HAVE_SYSV_COMPAT
53 int config_parse_warn_compat(
63 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
68 int config_parse_unit_deps(
78 UnitDependency d = ltype;
88 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
89 char _cleanup_free_ *t = NULL, *k = NULL;
96 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",
103 filename, line, k, strerror(-r));
109 int config_parse_unit_string_printf(
110 const char *filename,
128 k = unit_full_printf(u, rvalue);
132 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
138 int config_parse_unit_strv_printf(
139 const char *filename,
157 k = unit_full_printf(u, rvalue);
161 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
167 int config_parse_unit_path_printf(
168 const char *filename,
186 k = unit_full_printf(u, rvalue);
190 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
196 int config_parse_socket_listen(
197 const char *filename,
206 SocketPort *p, *tail;
216 p = new0(SocketPort, 1);
220 if (streq(lvalue, "ListenFIFO")) {
221 p->type = SOCKET_FIFO;
223 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
228 path_kill_slashes(p->path);
230 } else if (streq(lvalue, "ListenSpecial")) {
231 p->type = SOCKET_SPECIAL;
233 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
238 path_kill_slashes(p->path);
240 } else if (streq(lvalue, "ListenMessageQueue")) {
242 p->type = SOCKET_MQUEUE;
244 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
249 path_kill_slashes(p->path);
251 } else if (streq(lvalue, "ListenNetlink")) {
255 p->type = SOCKET_SOCKET;
256 k = unit_full_printf(UNIT(s), rvalue);
257 r = socket_address_parse_netlink(&p->address, k);
261 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
270 p->type = SOCKET_SOCKET;
271 k = unit_full_printf(UNIT(s), rvalue);
272 r = socket_address_parse(&p->address, k);
276 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
281 if (streq(lvalue, "ListenStream"))
282 p->address.type = SOCK_STREAM;
283 else if (streq(lvalue, "ListenDatagram"))
284 p->address.type = SOCK_DGRAM;
286 assert(streq(lvalue, "ListenSequentialPacket"));
287 p->address.type = SOCK_SEQPACKET;
290 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
291 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
300 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
301 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
303 LIST_PREPEND(SocketPort, port, s->ports, p);
308 int config_parse_socket_bind(
309 const char *filename,
319 SocketAddressBindIPv6Only b;
328 b = socket_address_bind_ipv6_only_from_string(rvalue);
332 r = parse_boolean(rvalue);
334 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
338 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
340 s->bind_ipv6_only = b;
345 int config_parse_exec_nice(
346 const char *filename,
355 ExecContext *c = data;
363 if (safe_atoi(rvalue, &priority) < 0) {
364 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
368 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
369 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
379 int config_parse_exec_oom_score_adjust(
380 const char *filename,
389 ExecContext *c = data;
397 if (safe_atoi(rvalue, &oa) < 0) {
398 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
402 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
403 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
407 c->oom_score_adjust = oa;
408 c->oom_score_adjust_set = true;
413 int config_parse_exec(
414 const char *filename,
423 ExecCommand **e = data, *nce;
433 /* We accept an absolute path as first argument, or
434 * alternatively an absolute prefixed with @ to allow
435 * overriding of argv[0]. */
444 bool honour_argv0 = false, ignore = false;
450 rvalue += strspn(rvalue, WHITESPACE);
455 for (i = 0; i < 2; i++) {
456 if (rvalue[0] == '-' && !ignore) {
461 if (rvalue[0] == '@' && !honour_argv0) {
467 if (*rvalue != '/') {
468 log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
469 filename, line, rvalue);
474 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
475 if (strncmp(w, ";", MAX(l, 1U)) == 0)
481 n = new(char*, k + !honour_argv0);
486 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
487 if (strncmp(w, ";", MAX(l, 1U)) == 0)
489 else if (strncmp(w, "\\;", MAX(l, 1U)) == 0)
492 if (honour_argv0 && w == rvalue) {
495 path = strndup(w, l);
501 if (!utf8_is_valid(path)) {
502 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
510 c = n[k++] = cunescape_length(w, l);
516 if (!utf8_is_valid(c)) {
517 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
527 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
540 assert(path_is_absolute(path));
542 nce = new0(ExecCommand, 1);
550 nce->ignore = ignore;
552 path_kill_slashes(nce->path);
554 exec_command_append_list(e, nce);
570 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
571 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
573 int config_parse_socket_bindtodevice(
574 const char *filename,
591 if (rvalue[0] && !streq(rvalue, "*")) {
592 if (!(n = strdup(rvalue)))
597 free(s->bind_to_device);
598 s->bind_to_device = n;
603 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
604 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
606 int config_parse_exec_io_class(
607 const char *filename,
616 ExecContext *c = data;
624 x = ioprio_class_from_string(rvalue);
626 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
630 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
631 c->ioprio_set = true;
636 int config_parse_exec_io_priority(
637 const char *filename,
646 ExecContext *c = data;
654 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
655 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
659 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
660 c->ioprio_set = true;
665 int config_parse_exec_cpu_sched_policy(
666 const char *filename,
676 ExecContext *c = data;
684 x = sched_policy_from_string(rvalue);
686 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
690 c->cpu_sched_policy = x;
691 /* Moving to or from real-time policy? We need to adjust the priority */
692 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
693 c->cpu_sched_set = true;
698 int config_parse_exec_cpu_sched_prio(
699 const char *filename,
708 ExecContext *c = data;
716 if (safe_atoi(rvalue, &i) < 0) {
717 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
722 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
723 min = sched_get_priority_min(c->cpu_sched_policy);
724 max = sched_get_priority_max(c->cpu_sched_policy);
726 if (i < min || i > max) {
727 log_error("[%s:%u] CPU scheduling priority is out of range, ignoring: %s", filename, line, rvalue);
731 c->cpu_sched_priority = i;
732 c->cpu_sched_set = true;
737 int config_parse_exec_cpu_affinity(
738 const char *filename,
747 ExecContext *c = data;
757 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
758 char _cleanup_free_ *t = NULL;
766 r = safe_atou(t, &cpu);
769 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
774 if (r < 0 || cpu >= c->cpuset_ncpus) {
775 log_error("[%s:%u] Failed to parse CPU affinity %s, ignoring: %s",
776 filename, line, t, rvalue);
780 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
786 int config_parse_exec_capabilities(
787 const char *filename,
796 ExecContext *c = data;
804 if (!(cap = cap_from_text(rvalue))) {
808 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
813 cap_free(c->capabilities);
814 c->capabilities = cap;
819 int config_parse_exec_secure_bits(
820 const char *filename,
829 ExecContext *c = data;
839 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
840 if (first_word(w, "keep-caps"))
841 c->secure_bits |= SECURE_KEEP_CAPS;
842 else if (first_word(w, "keep-caps-locked"))
843 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
844 else if (first_word(w, "no-setuid-fixup"))
845 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
846 else if (first_word(w, "no-setuid-fixup-locked"))
847 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
848 else if (first_word(w, "noroot"))
849 c->secure_bits |= SECURE_NOROOT;
850 else if (first_word(w, "noroot-locked"))
851 c->secure_bits |= SECURE_NOROOT_LOCKED;
853 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s",
854 filename, line, rvalue);
862 int config_parse_bounding_set(
863 const char *filename,
872 uint64_t *capability_bounding_set_drop = data;
884 if (rvalue[0] == '~') {
889 /* Note that we store this inverted internally, since the
890 * kernel wants it like this. But we actually expose it
891 * non-inverted everywhere to have a fully normalized
894 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
895 char _cleanup_free_ *t = NULL;
903 r = cap_from_name(t, &cap);
905 log_error("[%s:%u] Failed to parse capability in bounding set, ignoring: %s",
910 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
914 *capability_bounding_set_drop |= sum;
916 *capability_bounding_set_drop |= ~sum;
921 int config_parse_limit(
922 const char *filename,
931 struct rlimit **rl = data;
932 unsigned long long u;
941 if (streq(rvalue, "infinity"))
942 u = (unsigned long long) RLIM_INFINITY;
943 else if (safe_atollu(rvalue, &u) < 0) {
944 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
949 if (!(*rl = new(struct rlimit, 1)))
952 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
956 int config_parse_unit_cgroup(
957 const char *filename,
971 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
972 char _cleanup_free_ *t = NULL, *k = NULL, *ku = NULL;
979 k = unit_full_printf(u, t);
987 r = unit_add_cgroup_from_text(u, ku);
989 log_error("[%s:%u] Failed to parse cgroup value %s, ignoring: %s",
990 filename, line, k, rvalue);
998 #ifdef HAVE_SYSV_COMPAT
999 int config_parse_sysv_priority(
1000 const char *filename,
1002 const char *section,
1009 int *priority = data;
1017 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1018 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1022 *priority = (int) i;
1027 int config_parse_fsck_passno(
1028 const char *filename,
1030 const char *section,
1045 if (safe_atoi(rvalue, &i) || i < 0) {
1046 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1054 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1056 int config_parse_kill_signal(
1057 const char *filename,
1059 const char *section,
1074 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1075 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1083 int config_parse_exec_mount_flags(
1084 const char *filename,
1086 const char *section,
1093 ExecContext *c = data;
1097 unsigned long flags = 0;
1104 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1105 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1107 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1109 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1110 flags |= MS_PRIVATE;
1112 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1117 c->mount_flags = flags;
1121 int config_parse_timer(
1122 const char *filename,
1124 const char *section,
1141 if ((b = timer_base_from_string(lvalue)) < 0) {
1142 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1146 if (parse_usec(rvalue, &u) < 0) {
1147 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1151 if (!(v = new0(TimerValue, 1)))
1157 LIST_PREPEND(TimerValue, value, t->values, v);
1162 int config_parse_timer_unit(
1163 const char *filename,
1165 const char *section,
1182 dbus_error_init(&error);
1184 if (endswith(rvalue, ".timer")) {
1185 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1189 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1191 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1192 dbus_error_free(&error);
1196 unit_ref_set(&t->unit, u);
1201 int config_parse_path_spec(
1202 const char *filename,
1204 const char *section,
1221 b = path_type_from_string(lvalue);
1223 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1227 k = unit_full_printf(UNIT(p), rvalue);
1231 if (!path_is_absolute(k)) {
1232 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1237 s = new0(PathSpec, 1);
1243 s->path = path_kill_slashes(k);
1247 LIST_PREPEND(PathSpec, spec, p->specs, s);
1252 int config_parse_path_unit(
1253 const char *filename,
1255 const char *section,
1272 dbus_error_init(&error);
1274 if (endswith(rvalue, ".path")) {
1275 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1279 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1280 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1281 dbus_error_free(&error);
1285 unit_ref_set(&t->unit, u);
1290 int config_parse_socket_service(
1291 const char *filename,
1293 const char *section,
1310 dbus_error_init(&error);
1312 if (!endswith(rvalue, ".service")) {
1313 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1317 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1319 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1320 dbus_error_free(&error);
1324 unit_ref_set(&s->service, x);
1329 int config_parse_service_sockets(
1330 const char *filename,
1332 const char *section,
1349 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1350 char _cleanup_free_ *t = NULL, *k = NULL;
1356 k = unit_name_printf(UNIT(s), t);
1360 if (!endswith(k, ".socket")) {
1361 log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1366 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1368 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1369 filename, line, k, strerror(-r));
1371 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1379 int config_parse_service_timeout(
1380 const char *filename,
1382 const char *section,
1389 Service *s = userdata;
1397 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1402 if (streq(lvalue, "TimeoutSec")) {
1403 s->start_timeout_defined = true;
1404 s->timeout_stop_usec = s->timeout_start_usec;
1405 } else if (streq(lvalue, "TimeoutStartSec"))
1406 s->start_timeout_defined = true;
1411 int config_parse_unit_env_file(
1412 const char *filename,
1414 const char *section,
1421 char ***env = data, **k;
1430 s = unit_full_printf(u, rvalue);
1434 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1435 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1440 k = strv_append(*env, s);
1451 int config_parse_ip_tos(
1452 const char *filename,
1454 const char *section,
1461 int *ip_tos = data, x;
1468 x = ip_tos_from_string(rvalue);
1470 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1478 int config_parse_unit_condition_path(
1479 const char *filename,
1481 const char *section,
1488 ConditionType cond = ltype;
1490 bool trigger, negate;
1492 _cleanup_free_ char *p = NULL;
1499 trigger = rvalue[0] == '|';
1503 negate = rvalue[0] == '!';
1507 p = unit_full_printf(u, rvalue);
1511 if (!path_is_absolute(p)) {
1512 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1516 c = condition_new(cond, p, trigger, negate);
1520 LIST_PREPEND(Condition, conditions, u->conditions, c);
1524 int config_parse_unit_condition_string(
1525 const char *filename,
1527 const char *section,
1534 ConditionType cond = ltype;
1536 bool trigger, negate;
1538 _cleanup_free_ char *s = NULL;
1545 trigger = rvalue[0] == '|';
1549 negate = rvalue[0] == '!';
1553 s = unit_full_printf(u, rvalue);
1557 c = condition_new(cond, s, trigger, negate);
1561 LIST_PREPEND(Condition, conditions, u->conditions, c);
1565 int config_parse_unit_condition_null(
1566 const char *filename,
1568 const char *section,
1577 bool trigger, negate;
1585 if ((trigger = rvalue[0] == '|'))
1588 if ((negate = rvalue[0] == '!'))
1591 if ((b = parse_boolean(rvalue)) < 0) {
1592 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1599 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1602 LIST_PREPEND(Condition, conditions, u->conditions, c);
1606 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1607 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1609 int config_parse_unit_cgroup_attr(
1610 const char *filename,
1612 const char *section,
1628 l = strv_split_quoted(rvalue);
1632 if (strv_length(l) != 2) {
1633 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1638 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1642 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1649 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) {
1660 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1661 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1665 if (asprintf(&t, "%lu", ul) < 0)
1668 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1672 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1679 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) {
1690 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1691 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1695 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1698 r = unit_add_cgroup_attribute(u,
1700 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1705 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1712 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1720 l = strv_split_quoted(value);
1724 assert(strv_length(l) >= 1);
1726 if (streq(l[0], "*")) {
1728 if (asprintf(ret, "a *:*%s%s",
1729 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1737 if (stat(l[0], &st) < 0) {
1738 log_warning("Couldn't stat device %s", l[0]);
1743 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1744 log_warning("%s is not a device.", l[0]);
1749 if (asprintf(ret, "%c %u:%u%s%s",
1750 S_ISCHR(st.st_mode) ? 'c' : 'b',
1751 major(st.st_rdev), minor(st.st_rdev),
1752 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1763 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) {
1774 l = strv_split_quoted(rvalue);
1779 if (k < 1 || k > 2) {
1780 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1785 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1786 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1791 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1792 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1798 r = unit_add_cgroup_attribute(u, "devices",
1799 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1800 rvalue, device_map);
1803 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1810 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1820 l = strv_split_quoted(value);
1824 assert(strv_length(l) == 2);
1826 if (stat(l[0], &st) < 0) {
1827 log_warning("Couldn't stat device %s", l[0]);
1832 if (S_ISBLK(st.st_mode))
1834 else if (major(st.st_dev) != 0) {
1835 /* If this is not a device node then find the block
1836 * device this file is stored on */
1839 /* If this is a partition, try to get the originating
1841 block_get_whole_disk(d, &d);
1843 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1848 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1857 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) {
1861 const char *device = NULL, *weight;
1870 l = strv_split_quoted(rvalue);
1875 if (k < 1 || k > 2) {
1876 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1888 if (device && !path_is_absolute(device)) {
1889 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1894 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1895 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1901 r = asprintf(&t, "%s %lu", device, ul);
1903 r = asprintf(&t, "%lu", ul);
1910 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1912 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1916 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1923 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) {
1935 l = strv_split_quoted(rvalue);
1941 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1946 if (!path_is_absolute(l[0])) {
1947 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1952 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1953 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1958 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1964 r = unit_add_cgroup_attribute(u, "blkio",
1965 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1970 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1977 int config_parse_unit_requires_mounts_for(
1978 const char *filename,
1980 const char *section,
1996 empty_before = !u->requires_mounts_for;
1998 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2000 /* Make it easy to find units with requires_mounts set */
2001 if (empty_before && u->requires_mounts_for)
2002 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2007 int config_parse_documentation(
2008 const char *filename,
2010 const char *section,
2026 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2030 for (a = b = u->documentation; a && *a; a++) {
2032 if (is_valid_documentation_url(*a))
2035 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2044 static void syscall_set(uint32_t *p, int nr) {
2045 p[nr >> 4] |= 1 << (nr & 31);
2048 static void syscall_unset(uint32_t *p, int nr) {
2049 p[nr >> 4] &= ~(1 << (nr & 31));
2052 int config_parse_syscall_filter(
2053 const char *filename,
2055 const char *section,
2062 ExecContext *c = data;
2064 bool invert = false;
2074 if (rvalue[0] == '~') {
2079 if (!c->syscall_filter) {
2082 n = (syscall_max() + 31) >> 4;
2083 c->syscall_filter = new(uint32_t, n);
2084 if (!c->syscall_filter)
2087 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2089 /* Add these by default */
2090 syscall_set(c->syscall_filter, __NR_execve);
2091 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2092 #ifdef __NR_sigreturn
2093 syscall_set(c->syscall_filter, __NR_sigreturn);
2095 syscall_set(c->syscall_filter, __NR_exit_group);
2096 syscall_set(c->syscall_filter, __NR_exit);
2099 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2101 char _cleanup_free_ *t = NULL;
2107 id = syscall_from_name(t);
2110 log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2116 syscall_unset(c->syscall_filter, id);
2118 syscall_set(c->syscall_filter, id);
2121 c->no_new_privileges = true;
2126 #define FOLLOW_MAX 8
2128 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2139 /* This will update the filename pointer if the loaded file is
2140 * reached by a symlink. The old string will be freed. */
2143 char *target, *name;
2145 if (c++ >= FOLLOW_MAX)
2148 path_kill_slashes(*filename);
2150 /* Add the file name we are currently looking at to
2151 * the names of this unit, but only if it is a valid
2153 name = path_get_file_name(*filename);
2155 if (unit_name_is_valid(name, true)) {
2157 id = set_get(names, name);
2163 r = set_put(names, id);
2171 /* Try to open the file name, but don't if its a symlink */
2172 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2179 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2180 r = readlink_and_make_absolute(*filename, &target);
2188 f = fdopen(fd, "re");
2191 close_nointr_nofail(fd);
2200 static int merge_by_names(Unit **u, Set *names, const char *id) {
2208 /* Let's try to add in all symlink names we found */
2209 while ((k = set_steal_first(names))) {
2211 /* First try to merge in the other name into our
2213 r = unit_merge_by_name(*u, k);
2217 /* Hmm, we couldn't merge the other unit into
2218 * ours? Then let's try it the other way
2221 other = manager_get_unit((*u)->manager, k);
2225 r = unit_merge(other, *u);
2228 return merge_by_names(u, names, NULL);
2236 unit_choose_id(*u, id);
2244 static int load_from_path(Unit *u, const char *path) {
2248 char *filename = NULL, *id = NULL;
2255 symlink_names = set_new(string_hash_func, string_compare_func);
2259 if (path_is_absolute(path)) {
2261 filename = strdup(path);
2267 r = open_follow(&filename, &f, symlink_names, &id);
2279 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2281 /* Instead of opening the path right away, we manually
2282 * follow all symlinks and add their name to our unit
2283 * name set while doing so */
2284 filename = path_make_absolute(path, *p);
2290 if (u->manager->unit_path_cache &&
2291 !set_get(u->manager->unit_path_cache, filename))
2294 r = open_follow(&filename, &f, symlink_names, &id);
2303 /* Empty the symlink names for the next run */
2304 set_clear_free(symlink_names);
2313 /* Hmm, no suitable file found? */
2319 r = merge_by_names(&merged, symlink_names, id);
2324 u->load_state = UNIT_MERGED;
2329 if (fstat(fileno(f), &st) < 0) {
2334 if (null_or_empty(&st))
2335 u->load_state = UNIT_MASKED;
2337 /* Now, parse the file contents */
2338 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2342 u->load_state = UNIT_LOADED;
2345 free(u->fragment_path);
2346 u->fragment_path = filename;
2349 u->fragment_mtime = timespec_load(&st.st_mtim);
2351 if (u->source_path) {
2352 if (stat(u->source_path, &st) >= 0)
2353 u->source_mtime = timespec_load(&st.st_mtim);
2355 u->source_mtime = 0;
2361 set_free_free(symlink_names);
2370 int unit_load_fragment(Unit *u) {
2376 assert(u->load_state == UNIT_STUB);
2379 /* First, try to find the unit under its id. We always look
2380 * for unit files in the default directories, to make it easy
2381 * to override things by placing things in /etc/systemd/system */
2382 r = load_from_path(u, u->id);
2386 /* Try to find an alias we can load this with */
2387 if (u->load_state == UNIT_STUB)
2388 SET_FOREACH(t, u->names, i) {
2393 r = load_from_path(u, t);
2397 if (u->load_state != UNIT_STUB)
2401 /* And now, try looking for it under the suggested (originally linked) path */
2402 if (u->load_state == UNIT_STUB && u->fragment_path) {
2404 r = load_from_path(u, u->fragment_path);
2408 if (u->load_state == UNIT_STUB) {
2409 /* Hmm, this didn't work? Then let's get rid
2410 * of the fragment path stored for us, so that
2411 * we don't point to an invalid location. */
2412 free(u->fragment_path);
2413 u->fragment_path = NULL;
2417 /* Look for a template */
2418 if (u->load_state == UNIT_STUB && u->instance) {
2421 k = unit_name_template(u->id);
2425 r = load_from_path(u, k);
2431 if (u->load_state == UNIT_STUB)
2432 SET_FOREACH(t, u->names, i) {
2437 k = unit_name_template(t);
2441 r = load_from_path(u, k);
2447 if (u->load_state != UNIT_STUB)
2455 void unit_dump_config_items(FILE *f) {
2456 static const struct {
2457 const ConfigParserCallback callback;
2460 { config_parse_int, "INTEGER" },
2461 { config_parse_unsigned, "UNSIGNED" },
2462 { config_parse_bytes_size, "SIZE" },
2463 { config_parse_bool, "BOOLEAN" },
2464 { config_parse_string, "STRING" },
2465 { config_parse_path, "PATH" },
2466 { config_parse_unit_path_printf, "PATH" },
2467 { config_parse_strv, "STRING [...]" },
2468 { config_parse_exec_nice, "NICE" },
2469 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2470 { config_parse_exec_io_class, "IOCLASS" },
2471 { config_parse_exec_io_priority, "IOPRIORITY" },
2472 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2473 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2474 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2475 { config_parse_mode, "MODE" },
2476 { config_parse_unit_env_file, "FILE" },
2477 { config_parse_output, "OUTPUT" },
2478 { config_parse_input, "INPUT" },
2479 { config_parse_facility, "FACILITY" },
2480 { config_parse_level, "LEVEL" },
2481 { config_parse_exec_capabilities, "CAPABILITIES" },
2482 { config_parse_exec_secure_bits, "SECUREBITS" },
2483 { config_parse_bounding_set, "BOUNDINGSET" },
2484 { config_parse_limit, "LIMIT" },
2485 { config_parse_unit_cgroup, "CGROUP [...]" },
2486 { config_parse_unit_deps, "UNIT [...]" },
2487 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2488 { config_parse_service_type, "SERVICETYPE" },
2489 { config_parse_service_restart, "SERVICERESTART" },
2490 #ifdef HAVE_SYSV_COMPAT
2491 { config_parse_sysv_priority, "SYSVPRIORITY" },
2493 { config_parse_warn_compat, "NOTSUPPORTED" },
2495 { config_parse_kill_mode, "KILLMODE" },
2496 { config_parse_kill_signal, "SIGNAL" },
2497 { config_parse_socket_listen, "SOCKET [...]" },
2498 { config_parse_socket_bind, "SOCKETBIND" },
2499 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2500 { config_parse_usec, "SECONDS" },
2501 { config_parse_nsec, "NANOSECONDS" },
2502 { config_parse_path_strv, "PATH [...]" },
2503 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2504 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2505 { config_parse_unit_string_printf, "STRING" },
2506 { config_parse_timer, "TIMER" },
2507 { config_parse_timer_unit, "NAME" },
2508 { config_parse_path_spec, "PATH" },
2509 { config_parse_path_unit, "UNIT" },
2510 { config_parse_notify_access, "ACCESS" },
2511 { config_parse_ip_tos, "TOS" },
2512 { config_parse_unit_condition_path, "CONDITION" },
2513 { config_parse_unit_condition_string, "CONDITION" },
2514 { config_parse_unit_condition_null, "CONDITION" },
2517 const char *prev = NULL;
2522 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2523 const char *rvalue = "OTHER", *lvalue;
2527 const ConfigPerfItem *p;
2529 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2531 dot = strchr(i, '.');
2532 lvalue = dot ? dot + 1 : i;
2536 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2540 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2543 for (j = 0; j < ELEMENTSOF(table); j++)
2544 if (p->parse == table[j].callback) {
2545 rvalue = table[j].rvalue;
2549 fprintf(f, "%s=%s\n", lvalue, rvalue);