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 "unit-printf.h"
46 #include "bus-errors.h"
48 #include "path-util.h"
49 #include "syscall-list.h"
51 #ifndef HAVE_SYSV_COMPAT
52 int config_parse_warn_compat(
62 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
67 int config_parse_unit_deps(
77 UnitDependency d = ltype;
87 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
95 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", filename, line, k, strerror(-r));
110 int config_parse_unit_string_printf(
111 const char *filename,
129 k = unit_full_printf(u, rvalue);
133 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
139 int config_parse_unit_strv_printf(
140 const char *filename,
158 k = unit_full_printf(u, rvalue);
162 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
168 int config_parse_unit_path_printf(
169 const char *filename,
187 k = unit_full_printf(u, rvalue);
191 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
197 int config_parse_socket_listen(
198 const char *filename,
207 SocketPort *p, *tail;
217 p = new0(SocketPort, 1);
221 if (streq(lvalue, "ListenFIFO")) {
222 p->type = SOCKET_FIFO;
224 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
229 path_kill_slashes(p->path);
231 } else if (streq(lvalue, "ListenSpecial")) {
232 p->type = SOCKET_SPECIAL;
234 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
239 path_kill_slashes(p->path);
241 } else if (streq(lvalue, "ListenMessageQueue")) {
243 p->type = SOCKET_MQUEUE;
245 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
250 path_kill_slashes(p->path);
252 } else if (streq(lvalue, "ListenNetlink")) {
256 p->type = SOCKET_SOCKET;
257 k = unit_full_printf(UNIT(s), rvalue);
258 r = socket_address_parse_netlink(&p->address, k);
262 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
271 p->type = SOCKET_SOCKET;
272 k = unit_full_printf(UNIT(s), rvalue);
273 r = socket_address_parse(&p->address, k);
277 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
282 if (streq(lvalue, "ListenStream"))
283 p->address.type = SOCK_STREAM;
284 else if (streq(lvalue, "ListenDatagram"))
285 p->address.type = SOCK_DGRAM;
287 assert(streq(lvalue, "ListenSequentialPacket"));
288 p->address.type = SOCK_SEQPACKET;
291 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
292 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
301 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
302 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
304 LIST_PREPEND(SocketPort, port, s->ports, p);
309 int config_parse_socket_bind(
310 const char *filename,
320 SocketAddressBindIPv6Only b;
329 if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
332 if ((r = parse_boolean(rvalue)) < 0) {
333 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
337 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
339 s->bind_ipv6_only = b;
344 int config_parse_exec_nice(
345 const char *filename,
354 ExecContext *c = data;
362 if (safe_atoi(rvalue, &priority) < 0) {
363 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
367 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
368 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
378 int config_parse_exec_oom_score_adjust(
379 const char *filename,
388 ExecContext *c = data;
396 if (safe_atoi(rvalue, &oa) < 0) {
397 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
401 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
402 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
406 c->oom_score_adjust = oa;
407 c->oom_score_adjust_set = true;
412 int config_parse_exec(
413 const char *filename,
422 ExecCommand **e = data, *nce;
432 /* We accept an absolute path as first argument, or
433 * alternatively an absolute prefixed with @ to allow
434 * overriding of argv[0]. */
442 bool honour_argv0 = false, ignore = false;
448 rvalue += strspn(rvalue, WHITESPACE);
453 if (rvalue[0] == '-') {
458 if (rvalue[0] == '@') {
463 if (*rvalue != '/') {
464 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
469 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
470 if (strncmp(w, ";", MAX(l, 1U)) == 0)
476 n = new(char*, k + !honour_argv0);
481 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
482 if (strncmp(w, ";", MAX(l, 1U)) == 0)
485 if (honour_argv0 && w == rvalue) {
488 path = strndup(w, l);
494 if (!utf8_is_valid(path)) {
495 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
503 c = n[k++] = cunescape_length(w, l);
509 if (!utf8_is_valid(c)) {
510 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
520 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
533 assert(path_is_absolute(path));
535 nce = new0(ExecCommand, 1);
543 nce->ignore = ignore;
545 path_kill_slashes(nce->path);
547 exec_command_append_list(e, nce);
563 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
564 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
566 int config_parse_socket_bindtodevice(
567 const char *filename,
584 if (rvalue[0] && !streq(rvalue, "*")) {
585 if (!(n = strdup(rvalue)))
590 free(s->bind_to_device);
591 s->bind_to_device = n;
596 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
597 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
599 int config_parse_exec_io_class(
600 const char *filename,
609 ExecContext *c = data;
617 if ((x = ioprio_class_from_string(rvalue)) < 0) {
618 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
622 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
623 c->ioprio_set = true;
628 int config_parse_exec_io_priority(
629 const char *filename,
638 ExecContext *c = data;
646 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
647 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
651 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
652 c->ioprio_set = true;
657 int config_parse_exec_cpu_sched_policy(
658 const char *filename,
668 ExecContext *c = data;
676 if ((x = sched_policy_from_string(rvalue)) < 0) {
677 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
681 c->cpu_sched_policy = x;
682 c->cpu_sched_set = true;
687 int config_parse_exec_cpu_sched_prio(
688 const char *filename,
697 ExecContext *c = data;
705 /* On Linux RR/FIFO have the same range */
706 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
707 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
711 c->cpu_sched_priority = i;
712 c->cpu_sched_set = true;
717 int config_parse_exec_cpu_affinity(
718 const char *filename,
727 ExecContext *c = data;
737 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
742 if (!(t = strndup(w, l)))
745 r = safe_atou(t, &cpu);
749 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
752 if (r < 0 || cpu >= c->cpuset_ncpus) {
753 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
757 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
763 int config_parse_exec_capabilities(
764 const char *filename,
773 ExecContext *c = data;
781 if (!(cap = cap_from_text(rvalue))) {
785 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
790 cap_free(c->capabilities);
791 c->capabilities = cap;
796 int config_parse_exec_secure_bits(
797 const char *filename,
806 ExecContext *c = data;
816 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
817 if (first_word(w, "keep-caps"))
818 c->secure_bits |= SECURE_KEEP_CAPS;
819 else if (first_word(w, "keep-caps-locked"))
820 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
821 else if (first_word(w, "no-setuid-fixup"))
822 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
823 else if (first_word(w, "no-setuid-fixup-locked"))
824 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
825 else if (first_word(w, "noroot"))
826 c->secure_bits |= SECURE_NOROOT;
827 else if (first_word(w, "noroot-locked"))
828 c->secure_bits |= SECURE_NOROOT_LOCKED;
830 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
838 int config_parse_bounding_set(
839 const char *filename,
848 uint64_t *capability_bounding_set_drop = data;
860 if (rvalue[0] == '~') {
865 /* Note that we store this inverted internally, since the
866 * kernel wants it like this. But we actually expose it
867 * non-inverted everywhere to have a fully normalized
870 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
879 r = cap_from_name(t, &cap);
883 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
887 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
891 *capability_bounding_set_drop |= sum;
893 *capability_bounding_set_drop |= ~sum;
898 int config_parse_limit(
899 const char *filename,
908 struct rlimit **rl = data;
909 unsigned long long u;
918 if (streq(rvalue, "infinity"))
919 u = (unsigned long long) RLIM_INFINITY;
920 else if (safe_atollu(rvalue, &u) < 0) {
921 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
926 if (!(*rl = new(struct rlimit, 1)))
929 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
933 int config_parse_unit_cgroup(
934 const char *filename,
948 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
956 k = unit_full_printf(u, t);
968 r = unit_add_cgroup_from_text(u, t);
972 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
980 #ifdef HAVE_SYSV_COMPAT
981 int config_parse_sysv_priority(
982 const char *filename,
991 int *priority = data;
999 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1000 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1004 *priority = (int) i;
1009 int config_parse_fsck_passno(
1010 const char *filename,
1012 const char *section,
1027 if (safe_atoi(rvalue, &i) || i < 0) {
1028 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1036 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1038 int config_parse_kill_signal(
1039 const char *filename,
1041 const char *section,
1056 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1057 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1065 int config_parse_exec_mount_flags(
1066 const char *filename,
1068 const char *section,
1075 ExecContext *c = data;
1079 unsigned long flags = 0;
1086 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1087 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1089 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1091 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1092 flags |= MS_PRIVATE;
1094 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1099 c->mount_flags = flags;
1103 int config_parse_timer(
1104 const char *filename,
1106 const char *section,
1123 if ((b = timer_base_from_string(lvalue)) < 0) {
1124 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1128 if (parse_usec(rvalue, &u) < 0) {
1129 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1133 if (!(v = new0(TimerValue, 1)))
1139 LIST_PREPEND(TimerValue, value, t->values, v);
1144 int config_parse_timer_unit(
1145 const char *filename,
1147 const char *section,
1164 dbus_error_init(&error);
1166 if (endswith(rvalue, ".timer")) {
1167 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1171 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1173 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1174 dbus_error_free(&error);
1178 unit_ref_set(&t->unit, u);
1183 int config_parse_path_spec(
1184 const char *filename,
1186 const char *section,
1202 if ((b = path_type_from_string(lvalue)) < 0) {
1203 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1207 if (!path_is_absolute(rvalue)) {
1208 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1212 if (!(s = new0(PathSpec, 1)))
1215 if (!(s->path = strdup(rvalue))) {
1220 path_kill_slashes(s->path);
1225 LIST_PREPEND(PathSpec, spec, p->specs, s);
1230 int config_parse_path_unit(
1231 const char *filename,
1233 const char *section,
1250 dbus_error_init(&error);
1252 if (endswith(rvalue, ".path")) {
1253 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1257 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1258 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1259 dbus_error_free(&error);
1263 unit_ref_set(&t->unit, u);
1268 int config_parse_socket_service(
1269 const char *filename,
1271 const char *section,
1288 dbus_error_init(&error);
1290 if (!endswith(rvalue, ".service")) {
1291 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1295 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1297 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1298 dbus_error_free(&error);
1302 unit_ref_set(&s->service, x);
1307 int config_parse_service_sockets(
1308 const char *filename,
1310 const char *section,
1327 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1334 k = unit_name_printf(UNIT(s), t);
1340 if (!endswith(k, ".socket")) {
1341 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1346 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1348 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1350 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1360 int config_parse_service_timeout(
1361 const char *filename,
1363 const char *section,
1370 Service *s = userdata;
1378 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1383 if (streq(lvalue, "TimeoutSec")) {
1384 s->start_timeout_defined = true;
1385 s->timeout_stop_usec = s->timeout_start_usec;
1386 } else if (streq(lvalue, "TimeoutStartSec"))
1387 s->start_timeout_defined = true;
1392 int config_parse_unit_env_file(
1393 const char *filename,
1395 const char *section,
1402 char ***env = data, **k;
1411 s = unit_full_printf(u, rvalue);
1415 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1416 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1421 k = strv_append(*env, s);
1432 int config_parse_ip_tos(
1433 const char *filename,
1435 const char *section,
1442 int *ip_tos = data, x;
1449 if ((x = ip_tos_from_string(rvalue)) < 0)
1450 if (safe_atoi(rvalue, &x) < 0) {
1451 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1459 int config_parse_unit_condition_path(
1460 const char *filename,
1462 const char *section,
1469 ConditionType cond = ltype;
1471 bool trigger, negate;
1473 _cleanup_free_ char *p = NULL;
1480 trigger = rvalue[0] == '|';
1484 negate = rvalue[0] == '!';
1488 p = unit_full_printf(u, rvalue);
1492 if (!path_is_absolute(p)) {
1493 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1497 c = condition_new(cond, p, trigger, negate);
1501 LIST_PREPEND(Condition, conditions, u->conditions, c);
1505 int config_parse_unit_condition_string(
1506 const char *filename,
1508 const char *section,
1515 ConditionType cond = ltype;
1517 bool trigger, negate;
1519 _cleanup_free_ char *s = NULL;
1526 trigger = rvalue[0] == '|';
1530 negate = rvalue[0] == '!';
1534 s = unit_full_printf(u, rvalue);
1538 c = condition_new(cond, s, trigger, negate);
1542 LIST_PREPEND(Condition, conditions, u->conditions, c);
1546 int config_parse_unit_condition_null(
1547 const char *filename,
1549 const char *section,
1558 bool trigger, negate;
1566 if ((trigger = rvalue[0] == '|'))
1569 if ((negate = rvalue[0] == '!'))
1572 if ((b = parse_boolean(rvalue)) < 0) {
1573 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1580 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1583 LIST_PREPEND(Condition, conditions, u->conditions, c);
1587 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1588 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1590 int config_parse_unit_cgroup_attr(
1591 const char *filename,
1593 const char *section,
1609 l = strv_split_quoted(rvalue);
1613 if (strv_length(l) != 2) {
1614 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1619 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1623 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1630 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) {
1641 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1642 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1646 if (asprintf(&t, "%lu", ul) < 0)
1649 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1653 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1660 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) {
1671 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1672 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1676 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1679 r = unit_add_cgroup_attribute(u,
1681 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1686 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1693 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1701 l = strv_split_quoted(value);
1705 assert(strv_length(l) >= 1);
1707 if (streq(l[0], "*")) {
1709 if (asprintf(ret, "a *:*%s%s",
1710 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1718 if (stat(l[0], &st) < 0) {
1719 log_warning("Couldn't stat device %s", l[0]);
1724 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1725 log_warning("%s is not a device.", l[0]);
1730 if (asprintf(ret, "%c %u:%u%s%s",
1731 S_ISCHR(st.st_mode) ? 'c' : 'b',
1732 major(st.st_rdev), minor(st.st_rdev),
1733 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1744 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) {
1755 l = strv_split_quoted(rvalue);
1760 if (k < 1 || k > 2) {
1761 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1766 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1767 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1772 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1773 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1779 r = unit_add_cgroup_attribute(u, "devices",
1780 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1781 rvalue, device_map);
1784 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1791 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1801 l = strv_split_quoted(value);
1805 assert(strv_length(l) == 2);
1807 if (stat(l[0], &st) < 0) {
1808 log_warning("Couldn't stat device %s", l[0]);
1813 if (S_ISBLK(st.st_mode))
1815 else if (major(st.st_dev) != 0) {
1816 /* If this is not a device node then find the block
1817 * device this file is stored on */
1820 /* If this is a partition, try to get the originating
1822 block_get_whole_disk(d, &d);
1824 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1829 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1838 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) {
1842 const char *device = NULL, *weight;
1851 l = strv_split_quoted(rvalue);
1856 if (k < 1 || k > 2) {
1857 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1869 if (device && !path_is_absolute(device)) {
1870 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1875 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1876 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1882 r = asprintf(&t, "%s %lu", device, ul);
1884 r = asprintf(&t, "%lu", ul);
1891 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1893 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1897 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1904 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) {
1916 l = strv_split_quoted(rvalue);
1922 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1927 if (!path_is_absolute(l[0])) {
1928 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1933 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1934 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1939 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1945 r = unit_add_cgroup_attribute(u, "blkio",
1946 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1951 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1958 int config_parse_unit_requires_mounts_for(
1959 const char *filename,
1961 const char *section,
1977 empty_before = !u->requires_mounts_for;
1979 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1981 /* Make it easy to find units with requires_mounts set */
1982 if (empty_before && u->requires_mounts_for)
1983 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1988 int config_parse_documentation(
1989 const char *filename,
1991 const char *section,
2007 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2011 for (a = b = u->documentation; a && *a; a++) {
2013 if (is_valid_documentation_url(*a))
2016 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2025 static void syscall_set(uint32_t *p, int nr) {
2026 p[nr >> 4] |= 1 << (nr & 31);
2029 static void syscall_unset(uint32_t *p, int nr) {
2030 p[nr >> 4] &= ~(1 << (nr & 31));
2033 int config_parse_syscall_filter(
2034 const char *filename,
2036 const char *section,
2043 ExecContext *c = data;
2045 bool invert = false;
2055 if (rvalue[0] == '~') {
2060 if (!c->syscall_filter) {
2063 n = (syscall_max() + 31) >> 4;
2064 c->syscall_filter = new(uint32_t, n);
2065 if (!c->syscall_filter)
2068 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2070 /* Add these by default */
2071 syscall_set(c->syscall_filter, __NR_execve);
2072 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2073 #ifdef __NR_sigreturn
2074 syscall_set(c->syscall_filter, __NR_sigreturn);
2076 syscall_set(c->syscall_filter, __NR_exit_group);
2077 syscall_set(c->syscall_filter, __NR_exit);
2080 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2088 id = syscall_from_name(t);
2092 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2097 syscall_unset(c->syscall_filter, id);
2099 syscall_set(c->syscall_filter, id);
2102 c->no_new_privileges = true;
2107 #define FOLLOW_MAX 8
2109 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2120 /* This will update the filename pointer if the loaded file is
2121 * reached by a symlink. The old string will be freed. */
2124 char *target, *name;
2126 if (c++ >= FOLLOW_MAX)
2129 path_kill_slashes(*filename);
2131 /* Add the file name we are currently looking at to
2132 * the names of this unit, but only if it is a valid
2134 name = path_get_file_name(*filename);
2136 if (unit_name_is_valid(name, true)) {
2138 id = set_get(names, name);
2144 r = set_put(names, id);
2152 /* Try to open the file name, but don't if its a symlink */
2153 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2160 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2161 r = readlink_and_make_absolute(*filename, &target);
2169 f = fdopen(fd, "re");
2172 close_nointr_nofail(fd);
2181 static int merge_by_names(Unit **u, Set *names, const char *id) {
2189 /* Let's try to add in all symlink names we found */
2190 while ((k = set_steal_first(names))) {
2192 /* First try to merge in the other name into our
2194 r = unit_merge_by_name(*u, k);
2198 /* Hmm, we couldn't merge the other unit into
2199 * ours? Then let's try it the other way
2202 other = manager_get_unit((*u)->manager, k);
2206 r = unit_merge(other, *u);
2209 return merge_by_names(u, names, NULL);
2217 unit_choose_id(*u, id);
2225 static int load_from_path(Unit *u, const char *path) {
2229 char *filename = NULL, *id = NULL;
2236 symlink_names = set_new(string_hash_func, string_compare_func);
2240 if (path_is_absolute(path)) {
2242 filename = strdup(path);
2248 r = open_follow(&filename, &f, symlink_names, &id);
2260 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2262 /* Instead of opening the path right away, we manually
2263 * follow all symlinks and add their name to our unit
2264 * name set while doing so */
2265 filename = path_make_absolute(path, *p);
2271 if (u->manager->unit_path_cache &&
2272 !set_get(u->manager->unit_path_cache, filename))
2275 r = open_follow(&filename, &f, symlink_names, &id);
2284 /* Empty the symlink names for the next run */
2285 set_clear_free(symlink_names);
2294 /* Hmm, no suitable file found? */
2300 r = merge_by_names(&merged, symlink_names, id);
2305 u->load_state = UNIT_MERGED;
2310 if (fstat(fileno(f), &st) < 0) {
2315 if (null_or_empty(&st))
2316 u->load_state = UNIT_MASKED;
2318 /* Now, parse the file contents */
2319 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2323 u->load_state = UNIT_LOADED;
2326 free(u->fragment_path);
2327 u->fragment_path = filename;
2330 u->fragment_mtime = timespec_load(&st.st_mtim);
2332 if (u->source_path) {
2333 if (stat(u->source_path, &st) >= 0)
2334 u->source_mtime = timespec_load(&st.st_mtim);
2336 u->source_mtime = 0;
2342 set_free_free(symlink_names);
2351 int unit_load_fragment(Unit *u) {
2357 assert(u->load_state == UNIT_STUB);
2360 /* First, try to find the unit under its id. We always look
2361 * for unit files in the default directories, to make it easy
2362 * to override things by placing things in /etc/systemd/system */
2363 r = load_from_path(u, u->id);
2367 /* Try to find an alias we can load this with */
2368 if (u->load_state == UNIT_STUB)
2369 SET_FOREACH(t, u->names, i) {
2374 r = load_from_path(u, t);
2378 if (u->load_state != UNIT_STUB)
2382 /* And now, try looking for it under the suggested (originally linked) path */
2383 if (u->load_state == UNIT_STUB && u->fragment_path) {
2385 r = load_from_path(u, u->fragment_path);
2389 if (u->load_state == UNIT_STUB) {
2390 /* Hmm, this didn't work? Then let's get rid
2391 * of the fragment path stored for us, so that
2392 * we don't point to an invalid location. */
2393 free(u->fragment_path);
2394 u->fragment_path = NULL;
2398 /* Look for a template */
2399 if (u->load_state == UNIT_STUB && u->instance) {
2402 k = unit_name_template(u->id);
2406 r = load_from_path(u, k);
2412 if (u->load_state == UNIT_STUB)
2413 SET_FOREACH(t, u->names, i) {
2418 k = unit_name_template(t);
2422 r = load_from_path(u, k);
2428 if (u->load_state != UNIT_STUB)
2436 void unit_dump_config_items(FILE *f) {
2437 static const struct {
2438 const ConfigParserCallback callback;
2441 { config_parse_int, "INTEGER" },
2442 { config_parse_unsigned, "UNSIGNED" },
2443 { config_parse_bytes_size, "SIZE" },
2444 { config_parse_bool, "BOOLEAN" },
2445 { config_parse_string, "STRING" },
2446 { config_parse_path, "PATH" },
2447 { config_parse_unit_path_printf, "PATH" },
2448 { config_parse_strv, "STRING [...]" },
2449 { config_parse_exec_nice, "NICE" },
2450 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2451 { config_parse_exec_io_class, "IOCLASS" },
2452 { config_parse_exec_io_priority, "IOPRIORITY" },
2453 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2454 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2455 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2456 { config_parse_mode, "MODE" },
2457 { config_parse_unit_env_file, "FILE" },
2458 { config_parse_output, "OUTPUT" },
2459 { config_parse_input, "INPUT" },
2460 { config_parse_facility, "FACILITY" },
2461 { config_parse_level, "LEVEL" },
2462 { config_parse_exec_capabilities, "CAPABILITIES" },
2463 { config_parse_exec_secure_bits, "SECUREBITS" },
2464 { config_parse_bounding_set, "BOUNDINGSET" },
2465 { config_parse_limit, "LIMIT" },
2466 { config_parse_unit_cgroup, "CGROUP [...]" },
2467 { config_parse_unit_deps, "UNIT [...]" },
2468 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2469 { config_parse_service_type, "SERVICETYPE" },
2470 { config_parse_service_restart, "SERVICERESTART" },
2471 #ifdef HAVE_SYSV_COMPAT
2472 { config_parse_sysv_priority, "SYSVPRIORITY" },
2474 { config_parse_warn_compat, "NOTSUPPORTED" },
2476 { config_parse_kill_mode, "KILLMODE" },
2477 { config_parse_kill_signal, "SIGNAL" },
2478 { config_parse_socket_listen, "SOCKET [...]" },
2479 { config_parse_socket_bind, "SOCKETBIND" },
2480 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2481 { config_parse_usec, "SECONDS" },
2482 { config_parse_nsec, "NANOSECONDS" },
2483 { config_parse_path_strv, "PATH [...]" },
2484 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2485 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2486 { config_parse_unit_string_printf, "STRING" },
2487 { config_parse_timer, "TIMER" },
2488 { config_parse_timer_unit, "NAME" },
2489 { config_parse_path_spec, "PATH" },
2490 { config_parse_path_unit, "UNIT" },
2491 { config_parse_notify_access, "ACCESS" },
2492 { config_parse_ip_tos, "TOS" },
2493 { config_parse_unit_condition_path, "CONDITION" },
2494 { config_parse_unit_condition_string, "CONDITION" },
2495 { config_parse_unit_condition_null, "CONDITION" },
2498 const char *prev = NULL;
2503 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2504 const char *rvalue = "OTHER", *lvalue;
2508 const ConfigPerfItem *p;
2510 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2512 dot = strchr(i, '.');
2513 lvalue = dot ? dot + 1 : i;
2517 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2521 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2524 for (j = 0; j < ELEMENTSOF(table); j++)
2525 if (p->parse == table[j].callback) {
2526 rvalue = table[j].rvalue;
2530 fprintf(f, "%s=%s\n", lvalue, rvalue);