1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/oom.h>
29 #include <sys/prctl.h>
30 #include <sys/mount.h>
34 #include <sys/resource.h>
38 #include "conf-parser.h"
39 #include "load-fragment.h"
42 #include "securebits.h"
44 #include "unit-name.h"
45 #include "bus-errors.h"
47 #include "path-util.h"
48 #include "syscall-list.h"
50 #ifndef HAVE_SYSV_COMPAT
51 int config_parse_warn_compat(
61 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
66 int config_parse_unit_deps(
76 UnitDependency d = ltype;
86 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94 k = unit_name_printf(u, t);
99 r = unit_add_dependency_by_name(u, d, k, NULL, true);
101 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", 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 if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
331 if ((r = parse_boolean(rvalue)) < 0) {
332 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
336 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
338 s->bind_ipv6_only = b;
343 int config_parse_exec_nice(
344 const char *filename,
353 ExecContext *c = data;
361 if (safe_atoi(rvalue, &priority) < 0) {
362 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
366 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
367 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
377 int config_parse_exec_oom_score_adjust(
378 const char *filename,
387 ExecContext *c = data;
395 if (safe_atoi(rvalue, &oa) < 0) {
396 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
400 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
401 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
405 c->oom_score_adjust = oa;
406 c->oom_score_adjust_set = true;
411 int config_parse_exec(
412 const char *filename,
421 ExecCommand **e = data, *nce;
431 /* We accept an absolute path as first argument, or
432 * alternatively an absolute prefixed with @ to allow
433 * overriding of argv[0]. */
441 bool honour_argv0 = false, ignore = false;
447 rvalue += strspn(rvalue, WHITESPACE);
452 if (rvalue[0] == '-') {
457 if (rvalue[0] == '@') {
462 if (*rvalue != '/') {
463 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
468 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
469 if (strncmp(w, ";", MAX(l, 1U)) == 0)
475 n = new(char*, k + !honour_argv0);
480 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
481 if (strncmp(w, ";", MAX(l, 1U)) == 0)
484 if (honour_argv0 && w == rvalue) {
487 path = strndup(w, l);
493 if (!utf8_is_valid(path)) {
494 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
502 c = n[k++] = cunescape_length(w, l);
508 if (!utf8_is_valid(c)) {
509 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
519 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
532 assert(path_is_absolute(path));
534 nce = new0(ExecCommand, 1);
542 nce->ignore = ignore;
544 path_kill_slashes(nce->path);
546 exec_command_append_list(e, nce);
562 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
563 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
565 int config_parse_socket_bindtodevice(
566 const char *filename,
583 if (rvalue[0] && !streq(rvalue, "*")) {
584 if (!(n = strdup(rvalue)))
589 free(s->bind_to_device);
590 s->bind_to_device = n;
595 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
596 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
598 int config_parse_exec_io_class(
599 const char *filename,
608 ExecContext *c = data;
616 if ((x = ioprio_class_from_string(rvalue)) < 0) {
617 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
621 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
622 c->ioprio_set = true;
627 int config_parse_exec_io_priority(
628 const char *filename,
637 ExecContext *c = data;
645 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
646 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
650 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
651 c->ioprio_set = true;
656 int config_parse_exec_cpu_sched_policy(
657 const char *filename,
667 ExecContext *c = data;
675 if ((x = sched_policy_from_string(rvalue)) < 0) {
676 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
680 c->cpu_sched_policy = x;
681 c->cpu_sched_set = true;
686 int config_parse_exec_cpu_sched_prio(
687 const char *filename,
696 ExecContext *c = data;
704 /* On Linux RR/FIFO have the same range */
705 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
706 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
710 c->cpu_sched_priority = i;
711 c->cpu_sched_set = true;
716 int config_parse_exec_cpu_affinity(
717 const char *filename,
726 ExecContext *c = data;
736 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
741 if (!(t = strndup(w, l)))
744 r = safe_atou(t, &cpu);
748 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
751 if (r < 0 || cpu >= c->cpuset_ncpus) {
752 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
756 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
762 int config_parse_exec_capabilities(
763 const char *filename,
772 ExecContext *c = data;
780 if (!(cap = cap_from_text(rvalue))) {
784 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
789 cap_free(c->capabilities);
790 c->capabilities = cap;
795 int config_parse_exec_secure_bits(
796 const char *filename,
805 ExecContext *c = data;
815 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
816 if (first_word(w, "keep-caps"))
817 c->secure_bits |= SECURE_KEEP_CAPS;
818 else if (first_word(w, "keep-caps-locked"))
819 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
820 else if (first_word(w, "no-setuid-fixup"))
821 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
822 else if (first_word(w, "no-setuid-fixup-locked"))
823 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
824 else if (first_word(w, "noroot"))
825 c->secure_bits |= SECURE_NOROOT;
826 else if (first_word(w, "noroot-locked"))
827 c->secure_bits |= SECURE_NOROOT_LOCKED;
829 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
837 int config_parse_bounding_set(
838 const char *filename,
847 uint64_t *capability_bounding_set_drop = data;
859 if (rvalue[0] == '~') {
864 /* Note that we store this inverted internally, since the
865 * kernel wants it like this. But we actually expose it
866 * non-inverted everywhere to have a fully normalized
869 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
878 r = cap_from_name(t, &cap);
882 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
886 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
890 *capability_bounding_set_drop |= sum;
892 *capability_bounding_set_drop |= ~sum;
897 int config_parse_limit(
898 const char *filename,
907 struct rlimit **rl = data;
908 unsigned long long u;
917 if (streq(rvalue, "infinity"))
918 u = (unsigned long long) RLIM_INFINITY;
919 else if (safe_atollu(rvalue, &u) < 0) {
920 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
925 if (!(*rl = new(struct rlimit, 1)))
928 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
932 int config_parse_unit_cgroup(
933 const char *filename,
947 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
955 k = unit_full_printf(u, t);
967 r = unit_add_cgroup_from_text(u, t);
971 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
979 #ifdef HAVE_SYSV_COMPAT
980 int config_parse_sysv_priority(
981 const char *filename,
990 int *priority = data;
998 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
999 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1003 *priority = (int) i;
1008 int config_parse_fsck_passno(
1009 const char *filename,
1011 const char *section,
1026 if (safe_atoi(rvalue, &i) || i < 0) {
1027 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1035 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1037 int config_parse_kill_signal(
1038 const char *filename,
1040 const char *section,
1055 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1056 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1064 int config_parse_exec_mount_flags(
1065 const char *filename,
1067 const char *section,
1074 ExecContext *c = data;
1078 unsigned long flags = 0;
1085 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1086 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1088 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1090 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1091 flags |= MS_PRIVATE;
1093 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1098 c->mount_flags = flags;
1102 int config_parse_timer(
1103 const char *filename,
1105 const char *section,
1122 if ((b = timer_base_from_string(lvalue)) < 0) {
1123 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1127 if (parse_usec(rvalue, &u) < 0) {
1128 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1132 if (!(v = new0(TimerValue, 1)))
1138 LIST_PREPEND(TimerValue, value, t->values, v);
1143 int config_parse_timer_unit(
1144 const char *filename,
1146 const char *section,
1163 dbus_error_init(&error);
1165 if (endswith(rvalue, ".timer")) {
1166 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1170 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1172 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1173 dbus_error_free(&error);
1177 unit_ref_set(&t->unit, u);
1182 int config_parse_path_spec(
1183 const char *filename,
1185 const char *section,
1201 if ((b = path_type_from_string(lvalue)) < 0) {
1202 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1206 if (!path_is_absolute(rvalue)) {
1207 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1211 if (!(s = new0(PathSpec, 1)))
1214 if (!(s->path = strdup(rvalue))) {
1219 path_kill_slashes(s->path);
1224 LIST_PREPEND(PathSpec, spec, p->specs, s);
1229 int config_parse_path_unit(
1230 const char *filename,
1232 const char *section,
1249 dbus_error_init(&error);
1251 if (endswith(rvalue, ".path")) {
1252 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1256 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1257 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1258 dbus_error_free(&error);
1262 unit_ref_set(&t->unit, u);
1267 int config_parse_socket_service(
1268 const char *filename,
1270 const char *section,
1287 dbus_error_init(&error);
1289 if (!endswith(rvalue, ".service")) {
1290 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1294 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1296 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1297 dbus_error_free(&error);
1301 unit_ref_set(&s->service, x);
1306 int config_parse_service_sockets(
1307 const char *filename,
1309 const char *section,
1326 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1333 k = unit_name_printf(UNIT(s), t);
1339 if (!endswith(k, ".socket")) {
1340 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1345 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1347 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1349 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1359 int config_parse_service_timeout(
1360 const char *filename,
1362 const char *section,
1369 Service *s = userdata;
1377 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1380 s->timeout_defined = true;
1385 int config_parse_unit_env_file(
1386 const char *filename,
1388 const char *section,
1395 char ***env = data, **k;
1404 s = unit_full_printf(u, rvalue);
1408 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1409 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1414 k = strv_append(*env, s);
1425 int config_parse_ip_tos(
1426 const char *filename,
1428 const char *section,
1435 int *ip_tos = data, x;
1442 if ((x = ip_tos_from_string(rvalue)) < 0)
1443 if (safe_atoi(rvalue, &x) < 0) {
1444 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1452 int config_parse_unit_condition_path(
1453 const char *filename,
1455 const char *section,
1462 ConditionType cond = ltype;
1464 bool trigger, negate;
1472 trigger = rvalue[0] == '|';
1476 negate = rvalue[0] == '!';
1480 if (!path_is_absolute(rvalue)) {
1481 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1485 c = condition_new(cond, rvalue, trigger, negate);
1489 LIST_PREPEND(Condition, conditions, u->conditions, c);
1493 int config_parse_unit_condition_string(
1494 const char *filename,
1496 const char *section,
1503 ConditionType cond = ltype;
1505 bool trigger, negate;
1513 if ((trigger = rvalue[0] == '|'))
1516 if ((negate = rvalue[0] == '!'))
1519 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1522 LIST_PREPEND(Condition, conditions, u->conditions, c);
1526 int config_parse_unit_condition_null(
1527 const char *filename,
1529 const char *section,
1538 bool trigger, negate;
1546 if ((trigger = rvalue[0] == '|'))
1549 if ((negate = rvalue[0] == '!'))
1552 if ((b = parse_boolean(rvalue)) < 0) {
1553 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1560 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1563 LIST_PREPEND(Condition, conditions, u->conditions, c);
1567 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1568 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1570 int config_parse_unit_cgroup_attr(
1571 const char *filename,
1573 const char *section,
1589 l = strv_split_quoted(rvalue);
1593 if (strv_length(l) != 2) {
1594 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1599 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1603 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1610 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) {
1621 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1622 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1626 if (asprintf(&t, "%lu", ul) < 0)
1629 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1633 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1640 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) {
1651 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1652 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1656 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1659 r = unit_add_cgroup_attribute(u,
1661 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1666 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1673 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1681 l = strv_split_quoted(value);
1685 assert(strv_length(l) >= 1);
1687 if (streq(l[0], "*")) {
1689 if (asprintf(ret, "a *:*%s%s",
1690 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1698 if (stat(l[0], &st) < 0) {
1699 log_warning("Couldn't stat device %s", l[0]);
1704 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1705 log_warning("%s is not a device.", l[0]);
1710 if (asprintf(ret, "%c %u:%u%s%s",
1711 S_ISCHR(st.st_mode) ? 'c' : 'b',
1712 major(st.st_rdev), minor(st.st_rdev),
1713 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1724 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) {
1735 l = strv_split_quoted(rvalue);
1740 if (k < 1 || k > 2) {
1741 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1746 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1747 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1752 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1753 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1759 r = unit_add_cgroup_attribute(u, "devices",
1760 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1761 rvalue, device_map);
1764 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1771 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1781 l = strv_split_quoted(value);
1785 assert(strv_length(l) == 2);
1787 if (stat(l[0], &st) < 0) {
1788 log_warning("Couldn't stat device %s", l[0]);
1793 if (S_ISBLK(st.st_mode))
1795 else if (major(st.st_dev) != 0) {
1796 /* If this is not a device node then find the block
1797 * device this file is stored on */
1800 /* If this is a partition, try to get the originating
1802 block_get_whole_disk(d, &d);
1804 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1809 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1818 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) {
1822 const char *device = NULL, *weight;
1831 l = strv_split_quoted(rvalue);
1836 if (k < 1 || k > 2) {
1837 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1849 if (device && !path_is_absolute(device)) {
1850 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1855 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1856 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1862 r = asprintf(&t, "%s %lu", device, ul);
1864 r = asprintf(&t, "%lu", ul);
1871 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1873 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1877 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1884 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) {
1896 l = strv_split_quoted(rvalue);
1902 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1907 if (!path_is_absolute(l[0])) {
1908 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1913 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1914 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1919 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1925 r = unit_add_cgroup_attribute(u, "blkio",
1926 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1931 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1938 int config_parse_unit_requires_mounts_for(
1939 const char *filename,
1941 const char *section,
1957 empty_before = !u->requires_mounts_for;
1959 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1961 /* Make it easy to find units with requires_mounts set */
1962 if (empty_before && u->requires_mounts_for)
1963 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1968 int config_parse_documentation(
1969 const char *filename,
1971 const char *section,
1987 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1991 for (a = b = u->documentation; a && *a; a++) {
1993 if (is_valid_documentation_url(*a))
1996 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2005 static void syscall_set(uint32_t *p, int nr) {
2006 p[nr >> 4] |= 1 << (nr & 31);
2009 static void syscall_unset(uint32_t *p, int nr) {
2010 p[nr >> 4] &= ~(1 << (nr & 31));
2013 int config_parse_syscall_filter(
2014 const char *filename,
2016 const char *section,
2023 ExecContext *c = data;
2035 if (rvalue[0] == '~') {
2040 if (!c->syscall_filter) {
2043 n = (syscall_max() + 31) >> 4;
2044 c->syscall_filter = new(uint32_t, n);
2045 if (!c->syscall_filter)
2048 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2050 /* Add these by default */
2051 syscall_set(c->syscall_filter, __NR_execve);
2052 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2053 #ifdef __NR_sigreturn
2054 syscall_set(c->syscall_filter, __NR_sigreturn);
2056 syscall_set(c->syscall_filter, __NR_exit_group);
2057 syscall_set(c->syscall_filter, __NR_exit);
2060 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2068 id = syscall_from_name(t);
2072 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2077 syscall_unset(c->syscall_filter, id);
2079 syscall_set(c->syscall_filter, id);
2082 c->no_new_privileges = true;
2087 #define FOLLOW_MAX 8
2089 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2100 /* This will update the filename pointer if the loaded file is
2101 * reached by a symlink. The old string will be freed. */
2104 char *target, *name;
2106 if (c++ >= FOLLOW_MAX)
2109 path_kill_slashes(*filename);
2111 /* Add the file name we are currently looking at to
2112 * the names of this unit, but only if it is a valid
2114 name = path_get_file_name(*filename);
2116 if (unit_name_is_valid(name, true)) {
2118 id = set_get(names, name);
2124 r = set_put(names, id);
2132 /* Try to open the file name, but don't if its a symlink */
2133 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2140 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2141 r = readlink_and_make_absolute(*filename, &target);
2149 f = fdopen(fd, "re");
2152 close_nointr_nofail(fd);
2161 static int merge_by_names(Unit **u, Set *names, const char *id) {
2169 /* Let's try to add in all symlink names we found */
2170 while ((k = set_steal_first(names))) {
2172 /* First try to merge in the other name into our
2174 r = unit_merge_by_name(*u, k);
2178 /* Hmm, we couldn't merge the other unit into
2179 * ours? Then let's try it the other way
2182 other = manager_get_unit((*u)->manager, k);
2186 r = unit_merge(other, *u);
2189 return merge_by_names(u, names, NULL);
2197 unit_choose_id(*u, id);
2205 static int load_from_path(Unit *u, const char *path) {
2209 char *filename = NULL, *id = NULL;
2216 symlink_names = set_new(string_hash_func, string_compare_func);
2220 if (path_is_absolute(path)) {
2222 filename = strdup(path);
2228 r = open_follow(&filename, &f, symlink_names, &id);
2240 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2242 /* Instead of opening the path right away, we manually
2243 * follow all symlinks and add their name to our unit
2244 * name set while doing so */
2245 filename = path_make_absolute(path, *p);
2251 if (u->manager->unit_path_cache &&
2252 !set_get(u->manager->unit_path_cache, filename))
2255 r = open_follow(&filename, &f, symlink_names, &id);
2264 /* Empty the symlink names for the next run */
2265 set_clear_free(symlink_names);
2274 /* Hmm, no suitable file found? */
2280 r = merge_by_names(&merged, symlink_names, id);
2285 u->load_state = UNIT_MERGED;
2290 if (fstat(fileno(f), &st) < 0) {
2295 if (null_or_empty(&st))
2296 u->load_state = UNIT_MASKED;
2298 /* Now, parse the file contents */
2299 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2303 u->load_state = UNIT_LOADED;
2306 free(u->fragment_path);
2307 u->fragment_path = filename;
2310 u->fragment_mtime = timespec_load(&st.st_mtim);
2312 if (u->source_path) {
2313 if (stat(u->source_path, &st) >= 0)
2314 u->source_mtime = timespec_load(&st.st_mtim);
2316 u->source_mtime = 0;
2322 set_free_free(symlink_names);
2331 int unit_load_fragment(Unit *u) {
2337 assert(u->load_state == UNIT_STUB);
2340 /* First, try to find the unit under its id. We always look
2341 * for unit files in the default directories, to make it easy
2342 * to override things by placing things in /etc/systemd/system */
2343 r = load_from_path(u, u->id);
2347 /* Try to find an alias we can load this with */
2348 if (u->load_state == UNIT_STUB)
2349 SET_FOREACH(t, u->names, i) {
2354 r = load_from_path(u, t);
2358 if (u->load_state != UNIT_STUB)
2362 /* And now, try looking for it under the suggested (originally linked) path */
2363 if (u->load_state == UNIT_STUB && u->fragment_path) {
2365 r = load_from_path(u, u->fragment_path);
2369 if (u->load_state == UNIT_STUB) {
2370 /* Hmm, this didn't work? Then let's get rid
2371 * of the fragment path stored for us, so that
2372 * we don't point to an invalid location. */
2373 free(u->fragment_path);
2374 u->fragment_path = NULL;
2378 /* Look for a template */
2379 if (u->load_state == UNIT_STUB && u->instance) {
2382 k = unit_name_template(u->id);
2386 r = load_from_path(u, k);
2392 if (u->load_state == UNIT_STUB)
2393 SET_FOREACH(t, u->names, i) {
2398 k = unit_name_template(t);
2402 r = load_from_path(u, k);
2408 if (u->load_state != UNIT_STUB)
2416 void unit_dump_config_items(FILE *f) {
2417 static const struct {
2418 const ConfigParserCallback callback;
2421 { config_parse_int, "INTEGER" },
2422 { config_parse_unsigned, "UNSIGNED" },
2423 { config_parse_bytes_size, "SIZE" },
2424 { config_parse_bool, "BOOLEAN" },
2425 { config_parse_string, "STRING" },
2426 { config_parse_path, "PATH" },
2427 { config_parse_unit_path_printf, "PATH" },
2428 { config_parse_strv, "STRING [...]" },
2429 { config_parse_exec_nice, "NICE" },
2430 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2431 { config_parse_exec_io_class, "IOCLASS" },
2432 { config_parse_exec_io_priority, "IOPRIORITY" },
2433 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2434 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2435 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2436 { config_parse_mode, "MODE" },
2437 { config_parse_unit_env_file, "FILE" },
2438 { config_parse_output, "OUTPUT" },
2439 { config_parse_input, "INPUT" },
2440 { config_parse_facility, "FACILITY" },
2441 { config_parse_level, "LEVEL" },
2442 { config_parse_exec_capabilities, "CAPABILITIES" },
2443 { config_parse_exec_secure_bits, "SECUREBITS" },
2444 { config_parse_bounding_set, "BOUNDINGSET" },
2445 { config_parse_limit, "LIMIT" },
2446 { config_parse_unit_cgroup, "CGROUP [...]" },
2447 { config_parse_unit_deps, "UNIT [...]" },
2448 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2449 { config_parse_service_type, "SERVICETYPE" },
2450 { config_parse_service_restart, "SERVICERESTART" },
2451 #ifdef HAVE_SYSV_COMPAT
2452 { config_parse_sysv_priority, "SYSVPRIORITY" },
2454 { config_parse_warn_compat, "NOTSUPPORTED" },
2456 { config_parse_kill_mode, "KILLMODE" },
2457 { config_parse_kill_signal, "SIGNAL" },
2458 { config_parse_socket_listen, "SOCKET [...]" },
2459 { config_parse_socket_bind, "SOCKETBIND" },
2460 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2461 { config_parse_usec, "SECONDS" },
2462 { config_parse_nsec, "NANOSECONDS" },
2463 { config_parse_path_strv, "PATH [...]" },
2464 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2465 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2466 { config_parse_unit_string_printf, "STRING" },
2467 { config_parse_timer, "TIMER" },
2468 { config_parse_timer_unit, "NAME" },
2469 { config_parse_path_spec, "PATH" },
2470 { config_parse_path_unit, "UNIT" },
2471 { config_parse_notify_access, "ACCESS" },
2472 { config_parse_ip_tos, "TOS" },
2473 { config_parse_unit_condition_path, "CONDITION" },
2474 { config_parse_unit_condition_string, "CONDITION" },
2475 { config_parse_unit_condition_null, "CONDITION" },
2478 const char *prev = NULL;
2483 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2484 const char *rvalue = "OTHER", *lvalue;
2488 const ConfigPerfItem *p;
2490 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2492 dot = strchr(i, '.');
2493 lvalue = dot ? dot + 1 : i;
2497 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2501 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2504 for (j = 0; j < ELEMENTSOF(table); j++)
2505 if (p->parse == table[j].callback) {
2506 rvalue = table[j].rvalue;
2510 fprintf(f, "%s=%s\n", lvalue, rvalue);