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);
1382 if (streq(lvalue, "TimeoutSec")) {
1383 s->start_timeout_defined = true;
1384 s->timeout_stop_usec = s->timeout_start_usec;
1385 } else if (streq(lvalue, "TimeoutStartSec"))
1386 s->start_timeout_defined = true;
1391 int config_parse_unit_env_file(
1392 const char *filename,
1394 const char *section,
1401 char ***env = data, **k;
1410 s = unit_full_printf(u, rvalue);
1414 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1415 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1420 k = strv_append(*env, s);
1431 int config_parse_ip_tos(
1432 const char *filename,
1434 const char *section,
1441 int *ip_tos = data, x;
1448 if ((x = ip_tos_from_string(rvalue)) < 0)
1449 if (safe_atoi(rvalue, &x) < 0) {
1450 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1458 int config_parse_unit_condition_path(
1459 const char *filename,
1461 const char *section,
1468 ConditionType cond = ltype;
1470 bool trigger, negate;
1472 _cleanup_free_ char *p = NULL;
1479 trigger = rvalue[0] == '|';
1483 negate = rvalue[0] == '!';
1487 p = unit_full_printf(u, rvalue);
1491 if (!path_is_absolute(p)) {
1492 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1496 c = condition_new(cond, p, trigger, negate);
1500 LIST_PREPEND(Condition, conditions, u->conditions, c);
1504 int config_parse_unit_condition_string(
1505 const char *filename,
1507 const char *section,
1514 ConditionType cond = ltype;
1516 bool trigger, negate;
1518 _cleanup_free_ char *s = NULL;
1525 trigger = rvalue[0] == '|';
1529 negate = rvalue[0] == '!';
1533 s = unit_full_printf(u, rvalue);
1537 c = condition_new(cond, s, trigger, negate);
1541 LIST_PREPEND(Condition, conditions, u->conditions, c);
1545 int config_parse_unit_condition_null(
1546 const char *filename,
1548 const char *section,
1557 bool trigger, negate;
1565 if ((trigger = rvalue[0] == '|'))
1568 if ((negate = rvalue[0] == '!'))
1571 if ((b = parse_boolean(rvalue)) < 0) {
1572 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1579 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1582 LIST_PREPEND(Condition, conditions, u->conditions, c);
1586 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1587 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1589 int config_parse_unit_cgroup_attr(
1590 const char *filename,
1592 const char *section,
1608 l = strv_split_quoted(rvalue);
1612 if (strv_length(l) != 2) {
1613 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1618 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1622 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1629 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) {
1640 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1641 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1645 if (asprintf(&t, "%lu", ul) < 0)
1648 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1652 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1659 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) {
1670 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1671 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1675 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1678 r = unit_add_cgroup_attribute(u,
1680 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1685 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1692 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1700 l = strv_split_quoted(value);
1704 assert(strv_length(l) >= 1);
1706 if (streq(l[0], "*")) {
1708 if (asprintf(ret, "a *:*%s%s",
1709 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1717 if (stat(l[0], &st) < 0) {
1718 log_warning("Couldn't stat device %s", l[0]);
1723 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1724 log_warning("%s is not a device.", l[0]);
1729 if (asprintf(ret, "%c %u:%u%s%s",
1730 S_ISCHR(st.st_mode) ? 'c' : 'b',
1731 major(st.st_rdev), minor(st.st_rdev),
1732 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1743 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) {
1754 l = strv_split_quoted(rvalue);
1759 if (k < 1 || k > 2) {
1760 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1765 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1766 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1771 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1772 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1778 r = unit_add_cgroup_attribute(u, "devices",
1779 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1780 rvalue, device_map);
1783 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1790 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1800 l = strv_split_quoted(value);
1804 assert(strv_length(l) == 2);
1806 if (stat(l[0], &st) < 0) {
1807 log_warning("Couldn't stat device %s", l[0]);
1812 if (S_ISBLK(st.st_mode))
1814 else if (major(st.st_dev) != 0) {
1815 /* If this is not a device node then find the block
1816 * device this file is stored on */
1819 /* If this is a partition, try to get the originating
1821 block_get_whole_disk(d, &d);
1823 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1828 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1837 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) {
1841 const char *device = NULL, *weight;
1850 l = strv_split_quoted(rvalue);
1855 if (k < 1 || k > 2) {
1856 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1868 if (device && !path_is_absolute(device)) {
1869 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1874 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1875 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1881 r = asprintf(&t, "%s %lu", device, ul);
1883 r = asprintf(&t, "%lu", ul);
1890 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1892 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1896 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1903 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) {
1915 l = strv_split_quoted(rvalue);
1921 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1926 if (!path_is_absolute(l[0])) {
1927 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1932 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1933 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1938 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1944 r = unit_add_cgroup_attribute(u, "blkio",
1945 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1950 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1957 int config_parse_unit_requires_mounts_for(
1958 const char *filename,
1960 const char *section,
1976 empty_before = !u->requires_mounts_for;
1978 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1980 /* Make it easy to find units with requires_mounts set */
1981 if (empty_before && u->requires_mounts_for)
1982 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1987 int config_parse_documentation(
1988 const char *filename,
1990 const char *section,
2006 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2010 for (a = b = u->documentation; a && *a; a++) {
2012 if (is_valid_documentation_url(*a))
2015 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2024 static void syscall_set(uint32_t *p, int nr) {
2025 p[nr >> 4] |= 1 << (nr & 31);
2028 static void syscall_unset(uint32_t *p, int nr) {
2029 p[nr >> 4] &= ~(1 << (nr & 31));
2032 int config_parse_syscall_filter(
2033 const char *filename,
2035 const char *section,
2042 ExecContext *c = data;
2044 bool invert = false;
2054 if (rvalue[0] == '~') {
2059 if (!c->syscall_filter) {
2062 n = (syscall_max() + 31) >> 4;
2063 c->syscall_filter = new(uint32_t, n);
2064 if (!c->syscall_filter)
2067 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2069 /* Add these by default */
2070 syscall_set(c->syscall_filter, __NR_execve);
2071 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2072 #ifdef __NR_sigreturn
2073 syscall_set(c->syscall_filter, __NR_sigreturn);
2075 syscall_set(c->syscall_filter, __NR_exit_group);
2076 syscall_set(c->syscall_filter, __NR_exit);
2079 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2087 id = syscall_from_name(t);
2091 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2096 syscall_unset(c->syscall_filter, id);
2098 syscall_set(c->syscall_filter, id);
2101 c->no_new_privileges = true;
2106 #define FOLLOW_MAX 8
2108 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2119 /* This will update the filename pointer if the loaded file is
2120 * reached by a symlink. The old string will be freed. */
2123 char *target, *name;
2125 if (c++ >= FOLLOW_MAX)
2128 path_kill_slashes(*filename);
2130 /* Add the file name we are currently looking at to
2131 * the names of this unit, but only if it is a valid
2133 name = path_get_file_name(*filename);
2135 if (unit_name_is_valid(name, true)) {
2137 id = set_get(names, name);
2143 r = set_put(names, id);
2151 /* Try to open the file name, but don't if its a symlink */
2152 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2159 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2160 r = readlink_and_make_absolute(*filename, &target);
2168 f = fdopen(fd, "re");
2171 close_nointr_nofail(fd);
2180 static int merge_by_names(Unit **u, Set *names, const char *id) {
2188 /* Let's try to add in all symlink names we found */
2189 while ((k = set_steal_first(names))) {
2191 /* First try to merge in the other name into our
2193 r = unit_merge_by_name(*u, k);
2197 /* Hmm, we couldn't merge the other unit into
2198 * ours? Then let's try it the other way
2201 other = manager_get_unit((*u)->manager, k);
2205 r = unit_merge(other, *u);
2208 return merge_by_names(u, names, NULL);
2216 unit_choose_id(*u, id);
2224 static int load_from_path(Unit *u, const char *path) {
2228 char *filename = NULL, *id = NULL;
2235 symlink_names = set_new(string_hash_func, string_compare_func);
2239 if (path_is_absolute(path)) {
2241 filename = strdup(path);
2247 r = open_follow(&filename, &f, symlink_names, &id);
2259 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2261 /* Instead of opening the path right away, we manually
2262 * follow all symlinks and add their name to our unit
2263 * name set while doing so */
2264 filename = path_make_absolute(path, *p);
2270 if (u->manager->unit_path_cache &&
2271 !set_get(u->manager->unit_path_cache, filename))
2274 r = open_follow(&filename, &f, symlink_names, &id);
2283 /* Empty the symlink names for the next run */
2284 set_clear_free(symlink_names);
2293 /* Hmm, no suitable file found? */
2299 r = merge_by_names(&merged, symlink_names, id);
2304 u->load_state = UNIT_MERGED;
2309 if (fstat(fileno(f), &st) < 0) {
2314 if (null_or_empty(&st))
2315 u->load_state = UNIT_MASKED;
2317 /* Now, parse the file contents */
2318 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2322 u->load_state = UNIT_LOADED;
2325 free(u->fragment_path);
2326 u->fragment_path = filename;
2329 u->fragment_mtime = timespec_load(&st.st_mtim);
2331 if (u->source_path) {
2332 if (stat(u->source_path, &st) >= 0)
2333 u->source_mtime = timespec_load(&st.st_mtim);
2335 u->source_mtime = 0;
2341 set_free_free(symlink_names);
2350 int unit_load_fragment(Unit *u) {
2356 assert(u->load_state == UNIT_STUB);
2359 /* First, try to find the unit under its id. We always look
2360 * for unit files in the default directories, to make it easy
2361 * to override things by placing things in /etc/systemd/system */
2362 r = load_from_path(u, u->id);
2366 /* Try to find an alias we can load this with */
2367 if (u->load_state == UNIT_STUB)
2368 SET_FOREACH(t, u->names, i) {
2373 r = load_from_path(u, t);
2377 if (u->load_state != UNIT_STUB)
2381 /* And now, try looking for it under the suggested (originally linked) path */
2382 if (u->load_state == UNIT_STUB && u->fragment_path) {
2384 r = load_from_path(u, u->fragment_path);
2388 if (u->load_state == UNIT_STUB) {
2389 /* Hmm, this didn't work? Then let's get rid
2390 * of the fragment path stored for us, so that
2391 * we don't point to an invalid location. */
2392 free(u->fragment_path);
2393 u->fragment_path = NULL;
2397 /* Look for a template */
2398 if (u->load_state == UNIT_STUB && u->instance) {
2401 k = unit_name_template(u->id);
2405 r = load_from_path(u, k);
2411 if (u->load_state == UNIT_STUB)
2412 SET_FOREACH(t, u->names, i) {
2417 k = unit_name_template(t);
2421 r = load_from_path(u, k);
2427 if (u->load_state != UNIT_STUB)
2435 void unit_dump_config_items(FILE *f) {
2436 static const struct {
2437 const ConfigParserCallback callback;
2440 { config_parse_int, "INTEGER" },
2441 { config_parse_unsigned, "UNSIGNED" },
2442 { config_parse_bytes_size, "SIZE" },
2443 { config_parse_bool, "BOOLEAN" },
2444 { config_parse_string, "STRING" },
2445 { config_parse_path, "PATH" },
2446 { config_parse_unit_path_printf, "PATH" },
2447 { config_parse_strv, "STRING [...]" },
2448 { config_parse_exec_nice, "NICE" },
2449 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2450 { config_parse_exec_io_class, "IOCLASS" },
2451 { config_parse_exec_io_priority, "IOPRIORITY" },
2452 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2453 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2454 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2455 { config_parse_mode, "MODE" },
2456 { config_parse_unit_env_file, "FILE" },
2457 { config_parse_output, "OUTPUT" },
2458 { config_parse_input, "INPUT" },
2459 { config_parse_facility, "FACILITY" },
2460 { config_parse_level, "LEVEL" },
2461 { config_parse_exec_capabilities, "CAPABILITIES" },
2462 { config_parse_exec_secure_bits, "SECUREBITS" },
2463 { config_parse_bounding_set, "BOUNDINGSET" },
2464 { config_parse_limit, "LIMIT" },
2465 { config_parse_unit_cgroup, "CGROUP [...]" },
2466 { config_parse_unit_deps, "UNIT [...]" },
2467 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2468 { config_parse_service_type, "SERVICETYPE" },
2469 { config_parse_service_restart, "SERVICERESTART" },
2470 #ifdef HAVE_SYSV_COMPAT
2471 { config_parse_sysv_priority, "SYSVPRIORITY" },
2473 { config_parse_warn_compat, "NOTSUPPORTED" },
2475 { config_parse_kill_mode, "KILLMODE" },
2476 { config_parse_kill_signal, "SIGNAL" },
2477 { config_parse_socket_listen, "SOCKET [...]" },
2478 { config_parse_socket_bind, "SOCKETBIND" },
2479 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2480 { config_parse_usec, "SECONDS" },
2481 { config_parse_nsec, "NANOSECONDS" },
2482 { config_parse_path_strv, "PATH [...]" },
2483 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2484 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2485 { config_parse_unit_string_printf, "STRING" },
2486 { config_parse_timer, "TIMER" },
2487 { config_parse_timer_unit, "NAME" },
2488 { config_parse_path_spec, "PATH" },
2489 { config_parse_path_unit, "UNIT" },
2490 { config_parse_notify_access, "ACCESS" },
2491 { config_parse_ip_tos, "TOS" },
2492 { config_parse_unit_condition_path, "CONDITION" },
2493 { config_parse_unit_condition_string, "CONDITION" },
2494 { config_parse_unit_condition_null, "CONDITION" },
2497 const char *prev = NULL;
2502 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2503 const char *rvalue = "OTHER", *lvalue;
2507 const ConfigPerfItem *p;
2509 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2511 dot = strchr(i, '.');
2512 lvalue = dot ? dot + 1 : i;
2516 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2520 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2523 for (j = 0; j < ELEMENTSOF(table); j++)
2524 if (p->parse == table[j].callback) {
2525 rvalue = table[j].rvalue;
2529 fprintf(f, "%s=%s\n", lvalue, rvalue);