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_SEPARATOR(w, l, rvalue, ", ", state) {
1105 char _cleanup_free_ *t;
1111 if (streq(t, "shared"))
1113 else if (streq(t, "slave"))
1115 else if (streq(w, "private"))
1116 flags |= MS_PRIVATE;
1118 log_error("[%s:%u] Failed to parse mount flag %s, ignoring: %s",
1119 filename, line, t, rvalue);
1124 c->mount_flags = flags;
1128 int config_parse_timer(
1129 const char *filename,
1131 const char *section,
1142 CalendarSpec *c = NULL;
1150 b = timer_base_from_string(lvalue);
1152 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1156 if (b == TIMER_CALENDAR) {
1157 if (calendar_spec_from_string(rvalue, &c) < 0) {
1158 log_error("[%s:%u] Failed to parse calendar specification, ignoring: %s", filename, line, rvalue);
1162 id = CLOCK_REALTIME;
1164 if (parse_usec(rvalue, &u) < 0) {
1165 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1169 id = CLOCK_MONOTONIC;
1172 v = new0(TimerValue, 1);
1179 v->calendar_spec = c;
1181 LIST_PREPEND(TimerValue, value, t->values, v);
1186 int config_parse_timer_unit(
1187 const char *filename,
1189 const char *section,
1206 dbus_error_init(&error);
1208 if (endswith(rvalue, ".timer")) {
1209 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1213 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1215 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1216 dbus_error_free(&error);
1220 unit_ref_set(&t->unit, u);
1225 int config_parse_path_spec(
1226 const char *filename,
1228 const char *section,
1245 b = path_type_from_string(lvalue);
1247 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1251 k = unit_full_printf(UNIT(p), rvalue);
1255 if (!path_is_absolute(k)) {
1256 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1261 s = new0(PathSpec, 1);
1267 s->path = path_kill_slashes(k);
1271 LIST_PREPEND(PathSpec, spec, p->specs, s);
1276 int config_parse_path_unit(
1277 const char *filename,
1279 const char *section,
1296 dbus_error_init(&error);
1298 if (endswith(rvalue, ".path")) {
1299 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1303 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1304 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1305 dbus_error_free(&error);
1309 unit_ref_set(&t->unit, u);
1314 int config_parse_socket_service(
1315 const char *filename,
1317 const char *section,
1334 dbus_error_init(&error);
1336 if (!endswith(rvalue, ".service")) {
1337 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1341 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1343 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1344 dbus_error_free(&error);
1348 unit_ref_set(&s->service, x);
1353 int config_parse_service_sockets(
1354 const char *filename,
1356 const char *section,
1373 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1374 char _cleanup_free_ *t = NULL, *k = NULL;
1380 k = unit_name_printf(UNIT(s), t);
1384 if (!endswith(k, ".socket")) {
1385 log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1390 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1392 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1393 filename, line, k, strerror(-r));
1395 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1403 int config_parse_service_timeout(
1404 const char *filename,
1406 const char *section,
1413 Service *s = userdata;
1421 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1426 if (streq(lvalue, "TimeoutSec")) {
1427 s->start_timeout_defined = true;
1428 s->timeout_stop_usec = s->timeout_start_usec;
1429 } else if (streq(lvalue, "TimeoutStartSec"))
1430 s->start_timeout_defined = true;
1435 int config_parse_unit_env_file(
1436 const char *filename,
1438 const char *section,
1445 char ***env = data, **k;
1454 s = unit_full_printf(u, rvalue);
1458 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1459 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1464 k = strv_append(*env, s);
1475 int config_parse_ip_tos(
1476 const char *filename,
1478 const char *section,
1485 int *ip_tos = data, x;
1492 x = ip_tos_from_string(rvalue);
1494 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1502 int config_parse_unit_condition_path(
1503 const char *filename,
1505 const char *section,
1512 ConditionType cond = ltype;
1514 bool trigger, negate;
1516 _cleanup_free_ char *p = NULL;
1523 trigger = rvalue[0] == '|';
1527 negate = rvalue[0] == '!';
1531 p = unit_full_printf(u, rvalue);
1535 if (!path_is_absolute(p)) {
1536 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1540 c = condition_new(cond, p, trigger, negate);
1544 LIST_PREPEND(Condition, conditions, u->conditions, c);
1548 int config_parse_unit_condition_string(
1549 const char *filename,
1551 const char *section,
1558 ConditionType cond = ltype;
1560 bool trigger, negate;
1562 _cleanup_free_ char *s = NULL;
1569 trigger = rvalue[0] == '|';
1573 negate = rvalue[0] == '!';
1577 s = unit_full_printf(u, rvalue);
1581 c = condition_new(cond, s, trigger, negate);
1585 LIST_PREPEND(Condition, conditions, u->conditions, c);
1589 int config_parse_unit_condition_null(
1590 const char *filename,
1592 const char *section,
1601 bool trigger, negate;
1609 if ((trigger = rvalue[0] == '|'))
1612 if ((negate = rvalue[0] == '!'))
1615 if ((b = parse_boolean(rvalue)) < 0) {
1616 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1623 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1626 LIST_PREPEND(Condition, conditions, u->conditions, c);
1630 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1631 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1633 int config_parse_unit_cgroup_attr(
1634 const char *filename,
1636 const char *section,
1652 l = strv_split_quoted(rvalue);
1656 if (strv_length(l) != 2) {
1657 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1662 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1666 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1673 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) {
1684 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1685 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1689 if (asprintf(&t, "%lu", ul) < 0)
1692 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1696 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1703 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) {
1714 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1715 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1719 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1722 r = unit_add_cgroup_attribute(u,
1724 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1729 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1736 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1744 l = strv_split_quoted(value);
1748 assert(strv_length(l) >= 1);
1750 if (streq(l[0], "*")) {
1752 if (asprintf(ret, "a *:*%s%s",
1753 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1761 if (stat(l[0], &st) < 0) {
1762 log_warning("Couldn't stat device %s", l[0]);
1767 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1768 log_warning("%s is not a device.", l[0]);
1773 if (asprintf(ret, "%c %u:%u%s%s",
1774 S_ISCHR(st.st_mode) ? 'c' : 'b',
1775 major(st.st_rdev), minor(st.st_rdev),
1776 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1787 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) {
1798 l = strv_split_quoted(rvalue);
1803 if (k < 1 || k > 2) {
1804 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1809 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1810 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1815 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1816 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1822 r = unit_add_cgroup_attribute(u, "devices",
1823 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1824 rvalue, device_map);
1827 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1834 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1844 l = strv_split_quoted(value);
1848 assert(strv_length(l) == 2);
1850 if (stat(l[0], &st) < 0) {
1851 log_warning("Couldn't stat device %s", l[0]);
1856 if (S_ISBLK(st.st_mode))
1858 else if (major(st.st_dev) != 0) {
1859 /* If this is not a device node then find the block
1860 * device this file is stored on */
1863 /* If this is a partition, try to get the originating
1865 block_get_whole_disk(d, &d);
1867 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1872 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1881 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) {
1885 const char *device = NULL, *weight;
1894 l = strv_split_quoted(rvalue);
1899 if (k < 1 || k > 2) {
1900 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1912 if (device && !path_is_absolute(device)) {
1913 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1918 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1919 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1925 r = asprintf(&t, "%s %lu", device, ul);
1927 r = asprintf(&t, "%lu", ul);
1934 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1936 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1940 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1947 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) {
1959 l = strv_split_quoted(rvalue);
1965 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1970 if (!path_is_absolute(l[0])) {
1971 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1976 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1977 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1982 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1988 r = unit_add_cgroup_attribute(u, "blkio",
1989 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1994 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
2001 int config_parse_unit_requires_mounts_for(
2002 const char *filename,
2004 const char *section,
2020 empty_before = !u->requires_mounts_for;
2022 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2024 /* Make it easy to find units with requires_mounts set */
2025 if (empty_before && u->requires_mounts_for)
2026 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2031 int config_parse_documentation(
2032 const char *filename,
2034 const char *section,
2050 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2054 for (a = b = u->documentation; a && *a; a++) {
2056 if (is_valid_documentation_url(*a))
2059 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2068 static void syscall_set(uint32_t *p, int nr) {
2069 p[nr >> 4] |= 1 << (nr & 31);
2072 static void syscall_unset(uint32_t *p, int nr) {
2073 p[nr >> 4] &= ~(1 << (nr & 31));
2076 int config_parse_syscall_filter(
2077 const char *filename,
2079 const char *section,
2086 ExecContext *c = data;
2088 bool invert = false;
2098 if (rvalue[0] == '~') {
2103 if (!c->syscall_filter) {
2106 n = (syscall_max() + 31) >> 4;
2107 c->syscall_filter = new(uint32_t, n);
2108 if (!c->syscall_filter)
2111 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2113 /* Add these by default */
2114 syscall_set(c->syscall_filter, __NR_execve);
2115 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2116 #ifdef __NR_sigreturn
2117 syscall_set(c->syscall_filter, __NR_sigreturn);
2119 syscall_set(c->syscall_filter, __NR_exit_group);
2120 syscall_set(c->syscall_filter, __NR_exit);
2123 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2125 char _cleanup_free_ *t = NULL;
2131 id = syscall_from_name(t);
2134 log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2140 syscall_unset(c->syscall_filter, id);
2142 syscall_set(c->syscall_filter, id);
2145 c->no_new_privileges = true;
2150 #define FOLLOW_MAX 8
2152 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2163 /* This will update the filename pointer if the loaded file is
2164 * reached by a symlink. The old string will be freed. */
2167 char *target, *name;
2169 if (c++ >= FOLLOW_MAX)
2172 path_kill_slashes(*filename);
2174 /* Add the file name we are currently looking at to
2175 * the names of this unit, but only if it is a valid
2177 name = path_get_file_name(*filename);
2179 if (unit_name_is_valid(name, true)) {
2181 id = set_get(names, name);
2187 r = set_put(names, id);
2195 /* Try to open the file name, but don't if its a symlink */
2196 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2203 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2204 r = readlink_and_make_absolute(*filename, &target);
2212 f = fdopen(fd, "re");
2215 close_nointr_nofail(fd);
2224 static int merge_by_names(Unit **u, Set *names, const char *id) {
2232 /* Let's try to add in all symlink names we found */
2233 while ((k = set_steal_first(names))) {
2235 /* First try to merge in the other name into our
2237 r = unit_merge_by_name(*u, k);
2241 /* Hmm, we couldn't merge the other unit into
2242 * ours? Then let's try it the other way
2245 other = manager_get_unit((*u)->manager, k);
2249 r = unit_merge(other, *u);
2252 return merge_by_names(u, names, NULL);
2260 unit_choose_id(*u, id);
2268 static int load_from_path(Unit *u, const char *path) {
2272 char *filename = NULL, *id = NULL;
2279 symlink_names = set_new(string_hash_func, string_compare_func);
2283 if (path_is_absolute(path)) {
2285 filename = strdup(path);
2291 r = open_follow(&filename, &f, symlink_names, &id);
2303 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2305 /* Instead of opening the path right away, we manually
2306 * follow all symlinks and add their name to our unit
2307 * name set while doing so */
2308 filename = path_make_absolute(path, *p);
2314 if (u->manager->unit_path_cache &&
2315 !set_get(u->manager->unit_path_cache, filename))
2318 r = open_follow(&filename, &f, symlink_names, &id);
2327 /* Empty the symlink names for the next run */
2328 set_clear_free(symlink_names);
2337 /* Hmm, no suitable file found? */
2343 r = merge_by_names(&merged, symlink_names, id);
2348 u->load_state = UNIT_MERGED;
2353 if (fstat(fileno(f), &st) < 0) {
2358 if (null_or_empty(&st))
2359 u->load_state = UNIT_MASKED;
2361 /* Now, parse the file contents */
2362 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2366 u->load_state = UNIT_LOADED;
2369 free(u->fragment_path);
2370 u->fragment_path = filename;
2373 u->fragment_mtime = timespec_load(&st.st_mtim);
2375 if (u->source_path) {
2376 if (stat(u->source_path, &st) >= 0)
2377 u->source_mtime = timespec_load(&st.st_mtim);
2379 u->source_mtime = 0;
2385 set_free_free(symlink_names);
2394 int unit_load_fragment(Unit *u) {
2400 assert(u->load_state == UNIT_STUB);
2403 /* First, try to find the unit under its id. We always look
2404 * for unit files in the default directories, to make it easy
2405 * to override things by placing things in /etc/systemd/system */
2406 r = load_from_path(u, u->id);
2410 /* Try to find an alias we can load this with */
2411 if (u->load_state == UNIT_STUB)
2412 SET_FOREACH(t, u->names, i) {
2417 r = load_from_path(u, t);
2421 if (u->load_state != UNIT_STUB)
2425 /* And now, try looking for it under the suggested (originally linked) path */
2426 if (u->load_state == UNIT_STUB && u->fragment_path) {
2428 r = load_from_path(u, u->fragment_path);
2432 if (u->load_state == UNIT_STUB) {
2433 /* Hmm, this didn't work? Then let's get rid
2434 * of the fragment path stored for us, so that
2435 * we don't point to an invalid location. */
2436 free(u->fragment_path);
2437 u->fragment_path = NULL;
2441 /* Look for a template */
2442 if (u->load_state == UNIT_STUB && u->instance) {
2445 k = unit_name_template(u->id);
2449 r = load_from_path(u, k);
2455 if (u->load_state == UNIT_STUB)
2456 SET_FOREACH(t, u->names, i) {
2461 k = unit_name_template(t);
2465 r = load_from_path(u, k);
2471 if (u->load_state != UNIT_STUB)
2479 void unit_dump_config_items(FILE *f) {
2480 static const struct {
2481 const ConfigParserCallback callback;
2484 { config_parse_int, "INTEGER" },
2485 { config_parse_unsigned, "UNSIGNED" },
2486 { config_parse_bytes_size, "SIZE" },
2487 { config_parse_bool, "BOOLEAN" },
2488 { config_parse_string, "STRING" },
2489 { config_parse_path, "PATH" },
2490 { config_parse_unit_path_printf, "PATH" },
2491 { config_parse_strv, "STRING [...]" },
2492 { config_parse_exec_nice, "NICE" },
2493 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2494 { config_parse_exec_io_class, "IOCLASS" },
2495 { config_parse_exec_io_priority, "IOPRIORITY" },
2496 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2497 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2498 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2499 { config_parse_mode, "MODE" },
2500 { config_parse_unit_env_file, "FILE" },
2501 { config_parse_output, "OUTPUT" },
2502 { config_parse_input, "INPUT" },
2503 { config_parse_facility, "FACILITY" },
2504 { config_parse_level, "LEVEL" },
2505 { config_parse_exec_capabilities, "CAPABILITIES" },
2506 { config_parse_exec_secure_bits, "SECUREBITS" },
2507 { config_parse_bounding_set, "BOUNDINGSET" },
2508 { config_parse_limit, "LIMIT" },
2509 { config_parse_unit_cgroup, "CGROUP [...]" },
2510 { config_parse_unit_deps, "UNIT [...]" },
2511 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2512 { config_parse_service_type, "SERVICETYPE" },
2513 { config_parse_service_restart, "SERVICERESTART" },
2514 #ifdef HAVE_SYSV_COMPAT
2515 { config_parse_sysv_priority, "SYSVPRIORITY" },
2517 { config_parse_warn_compat, "NOTSUPPORTED" },
2519 { config_parse_kill_mode, "KILLMODE" },
2520 { config_parse_kill_signal, "SIGNAL" },
2521 { config_parse_socket_listen, "SOCKET [...]" },
2522 { config_parse_socket_bind, "SOCKETBIND" },
2523 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2524 { config_parse_usec, "SECONDS" },
2525 { config_parse_nsec, "NANOSECONDS" },
2526 { config_parse_path_strv, "PATH [...]" },
2527 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2528 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2529 { config_parse_unit_string_printf, "STRING" },
2530 { config_parse_timer, "TIMER" },
2531 { config_parse_timer_unit, "NAME" },
2532 { config_parse_path_spec, "PATH" },
2533 { config_parse_path_unit, "UNIT" },
2534 { config_parse_notify_access, "ACCESS" },
2535 { config_parse_ip_tos, "TOS" },
2536 { config_parse_unit_condition_path, "CONDITION" },
2537 { config_parse_unit_condition_string, "CONDITION" },
2538 { config_parse_unit_condition_null, "CONDITION" },
2541 const char *prev = NULL;
2546 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2547 const char *rvalue = "OTHER", *lvalue;
2551 const ConfigPerfItem *p;
2553 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2555 dot = strchr(i, '.');
2556 lvalue = dot ? dot + 1 : i;
2560 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2564 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2567 for (j = 0; j < ELEMENTSOF(table); j++)
2568 if (p->parse == table[j].callback) {
2569 rvalue = table[j].rvalue;
2573 fprintf(f, "%s=%s\n", lvalue, rvalue);