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,
1148 if ((b = timer_base_from_string(lvalue)) < 0) {
1149 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1153 if (parse_usec(rvalue, &u) < 0) {
1154 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1158 if (!(v = new0(TimerValue, 1)))
1164 LIST_PREPEND(TimerValue, value, t->values, v);
1169 int config_parse_timer_unit(
1170 const char *filename,
1172 const char *section,
1189 dbus_error_init(&error);
1191 if (endswith(rvalue, ".timer")) {
1192 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1196 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1198 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1199 dbus_error_free(&error);
1203 unit_ref_set(&t->unit, u);
1208 int config_parse_path_spec(
1209 const char *filename,
1211 const char *section,
1228 b = path_type_from_string(lvalue);
1230 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1234 k = unit_full_printf(UNIT(p), rvalue);
1238 if (!path_is_absolute(k)) {
1239 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1244 s = new0(PathSpec, 1);
1250 s->path = path_kill_slashes(k);
1254 LIST_PREPEND(PathSpec, spec, p->specs, s);
1259 int config_parse_path_unit(
1260 const char *filename,
1262 const char *section,
1279 dbus_error_init(&error);
1281 if (endswith(rvalue, ".path")) {
1282 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1286 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1287 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1288 dbus_error_free(&error);
1292 unit_ref_set(&t->unit, u);
1297 int config_parse_socket_service(
1298 const char *filename,
1300 const char *section,
1317 dbus_error_init(&error);
1319 if (!endswith(rvalue, ".service")) {
1320 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1324 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1326 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1327 dbus_error_free(&error);
1331 unit_ref_set(&s->service, x);
1336 int config_parse_service_sockets(
1337 const char *filename,
1339 const char *section,
1356 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1357 char _cleanup_free_ *t = NULL, *k = NULL;
1363 k = unit_name_printf(UNIT(s), t);
1367 if (!endswith(k, ".socket")) {
1368 log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1373 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1375 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1376 filename, line, k, strerror(-r));
1378 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1386 int config_parse_service_timeout(
1387 const char *filename,
1389 const char *section,
1396 Service *s = userdata;
1404 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1409 if (streq(lvalue, "TimeoutSec")) {
1410 s->start_timeout_defined = true;
1411 s->timeout_stop_usec = s->timeout_start_usec;
1412 } else if (streq(lvalue, "TimeoutStartSec"))
1413 s->start_timeout_defined = true;
1418 int config_parse_unit_env_file(
1419 const char *filename,
1421 const char *section,
1428 char ***env = data, **k;
1437 s = unit_full_printf(u, rvalue);
1441 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1442 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1447 k = strv_append(*env, s);
1458 int config_parse_ip_tos(
1459 const char *filename,
1461 const char *section,
1468 int *ip_tos = data, x;
1475 x = ip_tos_from_string(rvalue);
1477 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1485 int config_parse_unit_condition_path(
1486 const char *filename,
1488 const char *section,
1495 ConditionType cond = ltype;
1497 bool trigger, negate;
1499 _cleanup_free_ char *p = NULL;
1506 trigger = rvalue[0] == '|';
1510 negate = rvalue[0] == '!';
1514 p = unit_full_printf(u, rvalue);
1518 if (!path_is_absolute(p)) {
1519 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1523 c = condition_new(cond, p, trigger, negate);
1527 LIST_PREPEND(Condition, conditions, u->conditions, c);
1531 int config_parse_unit_condition_string(
1532 const char *filename,
1534 const char *section,
1541 ConditionType cond = ltype;
1543 bool trigger, negate;
1545 _cleanup_free_ char *s = NULL;
1552 trigger = rvalue[0] == '|';
1556 negate = rvalue[0] == '!';
1560 s = unit_full_printf(u, rvalue);
1564 c = condition_new(cond, s, trigger, negate);
1568 LIST_PREPEND(Condition, conditions, u->conditions, c);
1572 int config_parse_unit_condition_null(
1573 const char *filename,
1575 const char *section,
1584 bool trigger, negate;
1592 if ((trigger = rvalue[0] == '|'))
1595 if ((negate = rvalue[0] == '!'))
1598 if ((b = parse_boolean(rvalue)) < 0) {
1599 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1606 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1609 LIST_PREPEND(Condition, conditions, u->conditions, c);
1613 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1614 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1616 int config_parse_unit_cgroup_attr(
1617 const char *filename,
1619 const char *section,
1635 l = strv_split_quoted(rvalue);
1639 if (strv_length(l) != 2) {
1640 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1645 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1649 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1656 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) {
1667 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1668 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1672 if (asprintf(&t, "%lu", ul) < 0)
1675 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1679 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1686 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) {
1697 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1698 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1702 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1705 r = unit_add_cgroup_attribute(u,
1707 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1712 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1719 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1727 l = strv_split_quoted(value);
1731 assert(strv_length(l) >= 1);
1733 if (streq(l[0], "*")) {
1735 if (asprintf(ret, "a *:*%s%s",
1736 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1744 if (stat(l[0], &st) < 0) {
1745 log_warning("Couldn't stat device %s", l[0]);
1750 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1751 log_warning("%s is not a device.", l[0]);
1756 if (asprintf(ret, "%c %u:%u%s%s",
1757 S_ISCHR(st.st_mode) ? 'c' : 'b',
1758 major(st.st_rdev), minor(st.st_rdev),
1759 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1770 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) {
1781 l = strv_split_quoted(rvalue);
1786 if (k < 1 || k > 2) {
1787 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1792 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1793 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1798 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1799 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1805 r = unit_add_cgroup_attribute(u, "devices",
1806 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1807 rvalue, device_map);
1810 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1817 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1827 l = strv_split_quoted(value);
1831 assert(strv_length(l) == 2);
1833 if (stat(l[0], &st) < 0) {
1834 log_warning("Couldn't stat device %s", l[0]);
1839 if (S_ISBLK(st.st_mode))
1841 else if (major(st.st_dev) != 0) {
1842 /* If this is not a device node then find the block
1843 * device this file is stored on */
1846 /* If this is a partition, try to get the originating
1848 block_get_whole_disk(d, &d);
1850 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1855 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1864 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) {
1868 const char *device = NULL, *weight;
1877 l = strv_split_quoted(rvalue);
1882 if (k < 1 || k > 2) {
1883 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1895 if (device && !path_is_absolute(device)) {
1896 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1901 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1902 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1908 r = asprintf(&t, "%s %lu", device, ul);
1910 r = asprintf(&t, "%lu", ul);
1917 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1919 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1923 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1930 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) {
1942 l = strv_split_quoted(rvalue);
1948 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1953 if (!path_is_absolute(l[0])) {
1954 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1959 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1960 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1965 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1971 r = unit_add_cgroup_attribute(u, "blkio",
1972 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1977 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1984 int config_parse_unit_requires_mounts_for(
1985 const char *filename,
1987 const char *section,
2003 empty_before = !u->requires_mounts_for;
2005 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2007 /* Make it easy to find units with requires_mounts set */
2008 if (empty_before && u->requires_mounts_for)
2009 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2014 int config_parse_documentation(
2015 const char *filename,
2017 const char *section,
2033 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2037 for (a = b = u->documentation; a && *a; a++) {
2039 if (is_valid_documentation_url(*a))
2042 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2051 static void syscall_set(uint32_t *p, int nr) {
2052 p[nr >> 4] |= 1 << (nr & 31);
2055 static void syscall_unset(uint32_t *p, int nr) {
2056 p[nr >> 4] &= ~(1 << (nr & 31));
2059 int config_parse_syscall_filter(
2060 const char *filename,
2062 const char *section,
2069 ExecContext *c = data;
2071 bool invert = false;
2081 if (rvalue[0] == '~') {
2086 if (!c->syscall_filter) {
2089 n = (syscall_max() + 31) >> 4;
2090 c->syscall_filter = new(uint32_t, n);
2091 if (!c->syscall_filter)
2094 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2096 /* Add these by default */
2097 syscall_set(c->syscall_filter, __NR_execve);
2098 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2099 #ifdef __NR_sigreturn
2100 syscall_set(c->syscall_filter, __NR_sigreturn);
2102 syscall_set(c->syscall_filter, __NR_exit_group);
2103 syscall_set(c->syscall_filter, __NR_exit);
2106 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2108 char _cleanup_free_ *t = NULL;
2114 id = syscall_from_name(t);
2117 log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2123 syscall_unset(c->syscall_filter, id);
2125 syscall_set(c->syscall_filter, id);
2128 c->no_new_privileges = true;
2133 #define FOLLOW_MAX 8
2135 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2146 /* This will update the filename pointer if the loaded file is
2147 * reached by a symlink. The old string will be freed. */
2150 char *target, *name;
2152 if (c++ >= FOLLOW_MAX)
2155 path_kill_slashes(*filename);
2157 /* Add the file name we are currently looking at to
2158 * the names of this unit, but only if it is a valid
2160 name = path_get_file_name(*filename);
2162 if (unit_name_is_valid(name, true)) {
2164 id = set_get(names, name);
2170 r = set_put(names, id);
2178 /* Try to open the file name, but don't if its a symlink */
2179 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2186 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2187 r = readlink_and_make_absolute(*filename, &target);
2195 f = fdopen(fd, "re");
2198 close_nointr_nofail(fd);
2207 static int merge_by_names(Unit **u, Set *names, const char *id) {
2215 /* Let's try to add in all symlink names we found */
2216 while ((k = set_steal_first(names))) {
2218 /* First try to merge in the other name into our
2220 r = unit_merge_by_name(*u, k);
2224 /* Hmm, we couldn't merge the other unit into
2225 * ours? Then let's try it the other way
2228 other = manager_get_unit((*u)->manager, k);
2232 r = unit_merge(other, *u);
2235 return merge_by_names(u, names, NULL);
2243 unit_choose_id(*u, id);
2251 static int load_from_path(Unit *u, const char *path) {
2255 char *filename = NULL, *id = NULL;
2262 symlink_names = set_new(string_hash_func, string_compare_func);
2266 if (path_is_absolute(path)) {
2268 filename = strdup(path);
2274 r = open_follow(&filename, &f, symlink_names, &id);
2286 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2288 /* Instead of opening the path right away, we manually
2289 * follow all symlinks and add their name to our unit
2290 * name set while doing so */
2291 filename = path_make_absolute(path, *p);
2297 if (u->manager->unit_path_cache &&
2298 !set_get(u->manager->unit_path_cache, filename))
2301 r = open_follow(&filename, &f, symlink_names, &id);
2310 /* Empty the symlink names for the next run */
2311 set_clear_free(symlink_names);
2320 /* Hmm, no suitable file found? */
2326 r = merge_by_names(&merged, symlink_names, id);
2331 u->load_state = UNIT_MERGED;
2336 if (fstat(fileno(f), &st) < 0) {
2341 if (null_or_empty(&st))
2342 u->load_state = UNIT_MASKED;
2344 /* Now, parse the file contents */
2345 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2349 u->load_state = UNIT_LOADED;
2352 free(u->fragment_path);
2353 u->fragment_path = filename;
2356 u->fragment_mtime = timespec_load(&st.st_mtim);
2358 if (u->source_path) {
2359 if (stat(u->source_path, &st) >= 0)
2360 u->source_mtime = timespec_load(&st.st_mtim);
2362 u->source_mtime = 0;
2368 set_free_free(symlink_names);
2377 int unit_load_fragment(Unit *u) {
2383 assert(u->load_state == UNIT_STUB);
2386 /* First, try to find the unit under its id. We always look
2387 * for unit files in the default directories, to make it easy
2388 * to override things by placing things in /etc/systemd/system */
2389 r = load_from_path(u, u->id);
2393 /* Try to find an alias we can load this with */
2394 if (u->load_state == UNIT_STUB)
2395 SET_FOREACH(t, u->names, i) {
2400 r = load_from_path(u, t);
2404 if (u->load_state != UNIT_STUB)
2408 /* And now, try looking for it under the suggested (originally linked) path */
2409 if (u->load_state == UNIT_STUB && u->fragment_path) {
2411 r = load_from_path(u, u->fragment_path);
2415 if (u->load_state == UNIT_STUB) {
2416 /* Hmm, this didn't work? Then let's get rid
2417 * of the fragment path stored for us, so that
2418 * we don't point to an invalid location. */
2419 free(u->fragment_path);
2420 u->fragment_path = NULL;
2424 /* Look for a template */
2425 if (u->load_state == UNIT_STUB && u->instance) {
2428 k = unit_name_template(u->id);
2432 r = load_from_path(u, k);
2438 if (u->load_state == UNIT_STUB)
2439 SET_FOREACH(t, u->names, i) {
2444 k = unit_name_template(t);
2448 r = load_from_path(u, k);
2454 if (u->load_state != UNIT_STUB)
2462 void unit_dump_config_items(FILE *f) {
2463 static const struct {
2464 const ConfigParserCallback callback;
2467 { config_parse_int, "INTEGER" },
2468 { config_parse_unsigned, "UNSIGNED" },
2469 { config_parse_bytes_size, "SIZE" },
2470 { config_parse_bool, "BOOLEAN" },
2471 { config_parse_string, "STRING" },
2472 { config_parse_path, "PATH" },
2473 { config_parse_unit_path_printf, "PATH" },
2474 { config_parse_strv, "STRING [...]" },
2475 { config_parse_exec_nice, "NICE" },
2476 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2477 { config_parse_exec_io_class, "IOCLASS" },
2478 { config_parse_exec_io_priority, "IOPRIORITY" },
2479 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2480 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2481 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2482 { config_parse_mode, "MODE" },
2483 { config_parse_unit_env_file, "FILE" },
2484 { config_parse_output, "OUTPUT" },
2485 { config_parse_input, "INPUT" },
2486 { config_parse_facility, "FACILITY" },
2487 { config_parse_level, "LEVEL" },
2488 { config_parse_exec_capabilities, "CAPABILITIES" },
2489 { config_parse_exec_secure_bits, "SECUREBITS" },
2490 { config_parse_bounding_set, "BOUNDINGSET" },
2491 { config_parse_limit, "LIMIT" },
2492 { config_parse_unit_cgroup, "CGROUP [...]" },
2493 { config_parse_unit_deps, "UNIT [...]" },
2494 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2495 { config_parse_service_type, "SERVICETYPE" },
2496 { config_parse_service_restart, "SERVICERESTART" },
2497 #ifdef HAVE_SYSV_COMPAT
2498 { config_parse_sysv_priority, "SYSVPRIORITY" },
2500 { config_parse_warn_compat, "NOTSUPPORTED" },
2502 { config_parse_kill_mode, "KILLMODE" },
2503 { config_parse_kill_signal, "SIGNAL" },
2504 { config_parse_socket_listen, "SOCKET [...]" },
2505 { config_parse_socket_bind, "SOCKETBIND" },
2506 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2507 { config_parse_usec, "SECONDS" },
2508 { config_parse_nsec, "NANOSECONDS" },
2509 { config_parse_path_strv, "PATH [...]" },
2510 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2511 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2512 { config_parse_unit_string_printf, "STRING" },
2513 { config_parse_timer, "TIMER" },
2514 { config_parse_timer_unit, "NAME" },
2515 { config_parse_path_spec, "PATH" },
2516 { config_parse_path_unit, "UNIT" },
2517 { config_parse_notify_access, "ACCESS" },
2518 { config_parse_ip_tos, "TOS" },
2519 { config_parse_unit_condition_path, "CONDITION" },
2520 { config_parse_unit_condition_string, "CONDITION" },
2521 { config_parse_unit_condition_null, "CONDITION" },
2524 const char *prev = NULL;
2529 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2530 const char *rvalue = "OTHER", *lvalue;
2534 const ConfigPerfItem *p;
2536 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2538 dot = strchr(i, '.');
2539 lvalue = dot ? dot + 1 : i;
2543 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2547 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2550 for (j = 0; j < ELEMENTSOF(table); j++)
2551 if (p->parse == table[j].callback) {
2552 rvalue = table[j].rvalue;
2556 fprintf(f, "%s=%s\n", lvalue, rvalue);