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;
1478 trigger = rvalue[0] == '|';
1482 negate = rvalue[0] == '!';
1486 if (!path_is_absolute(rvalue)) {
1487 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1491 c = condition_new(cond, rvalue, trigger, negate);
1495 LIST_PREPEND(Condition, conditions, u->conditions, c);
1499 int config_parse_unit_condition_string(
1500 const char *filename,
1502 const char *section,
1509 ConditionType cond = ltype;
1511 bool trigger, negate;
1519 trigger = rvalue[0] == '|';
1523 negate = rvalue[0] == '!';
1527 c = condition_new(cond, rvalue, trigger, negate);
1531 LIST_PREPEND(Condition, conditions, u->conditions, c);
1535 int config_parse_unit_condition_null(
1536 const char *filename,
1538 const char *section,
1547 bool trigger, negate;
1555 if ((trigger = rvalue[0] == '|'))
1558 if ((negate = rvalue[0] == '!'))
1561 if ((b = parse_boolean(rvalue)) < 0) {
1562 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1569 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1572 LIST_PREPEND(Condition, conditions, u->conditions, c);
1576 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1577 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1579 int config_parse_unit_cgroup_attr(
1580 const char *filename,
1582 const char *section,
1598 l = strv_split_quoted(rvalue);
1602 if (strv_length(l) != 2) {
1603 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1608 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1612 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1619 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) {
1630 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1631 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1635 if (asprintf(&t, "%lu", ul) < 0)
1638 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1642 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1649 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) {
1660 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1661 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1665 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1668 r = unit_add_cgroup_attribute(u,
1670 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1675 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1682 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1690 l = strv_split_quoted(value);
1694 assert(strv_length(l) >= 1);
1696 if (streq(l[0], "*")) {
1698 if (asprintf(ret, "a *:*%s%s",
1699 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1707 if (stat(l[0], &st) < 0) {
1708 log_warning("Couldn't stat device %s", l[0]);
1713 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1714 log_warning("%s is not a device.", l[0]);
1719 if (asprintf(ret, "%c %u:%u%s%s",
1720 S_ISCHR(st.st_mode) ? 'c' : 'b',
1721 major(st.st_rdev), minor(st.st_rdev),
1722 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1733 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) {
1744 l = strv_split_quoted(rvalue);
1749 if (k < 1 || k > 2) {
1750 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1755 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1756 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1761 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1762 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1768 r = unit_add_cgroup_attribute(u, "devices",
1769 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1770 rvalue, device_map);
1773 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1780 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1790 l = strv_split_quoted(value);
1794 assert(strv_length(l) == 2);
1796 if (stat(l[0], &st) < 0) {
1797 log_warning("Couldn't stat device %s", l[0]);
1802 if (S_ISBLK(st.st_mode))
1804 else if (major(st.st_dev) != 0) {
1805 /* If this is not a device node then find the block
1806 * device this file is stored on */
1809 /* If this is a partition, try to get the originating
1811 block_get_whole_disk(d, &d);
1813 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1818 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1827 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) {
1831 const char *device = NULL, *weight;
1840 l = strv_split_quoted(rvalue);
1845 if (k < 1 || k > 2) {
1846 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1858 if (device && !path_is_absolute(device)) {
1859 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1864 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1865 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1871 r = asprintf(&t, "%s %lu", device, ul);
1873 r = asprintf(&t, "%lu", ul);
1880 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1882 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1886 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1893 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) {
1905 l = strv_split_quoted(rvalue);
1911 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1916 if (!path_is_absolute(l[0])) {
1917 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1922 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1923 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
1928 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1934 r = unit_add_cgroup_attribute(u, "blkio",
1935 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
1940 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1947 int config_parse_unit_requires_mounts_for(
1948 const char *filename,
1950 const char *section,
1966 empty_before = !u->requires_mounts_for;
1968 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1970 /* Make it easy to find units with requires_mounts set */
1971 if (empty_before && u->requires_mounts_for)
1972 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1977 int config_parse_documentation(
1978 const char *filename,
1980 const char *section,
1996 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2000 for (a = b = u->documentation; a && *a; a++) {
2002 if (is_valid_documentation_url(*a))
2005 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2014 static void syscall_set(uint32_t *p, int nr) {
2015 p[nr >> 4] |= 1 << (nr & 31);
2018 static void syscall_unset(uint32_t *p, int nr) {
2019 p[nr >> 4] &= ~(1 << (nr & 31));
2022 int config_parse_syscall_filter(
2023 const char *filename,
2025 const char *section,
2032 ExecContext *c = data;
2044 if (rvalue[0] == '~') {
2049 if (!c->syscall_filter) {
2052 n = (syscall_max() + 31) >> 4;
2053 c->syscall_filter = new(uint32_t, n);
2054 if (!c->syscall_filter)
2057 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2059 /* Add these by default */
2060 syscall_set(c->syscall_filter, __NR_execve);
2061 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2062 #ifdef __NR_sigreturn
2063 syscall_set(c->syscall_filter, __NR_sigreturn);
2065 syscall_set(c->syscall_filter, __NR_exit_group);
2066 syscall_set(c->syscall_filter, __NR_exit);
2069 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2077 id = syscall_from_name(t);
2081 log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
2086 syscall_unset(c->syscall_filter, id);
2088 syscall_set(c->syscall_filter, id);
2091 c->no_new_privileges = true;
2096 #define FOLLOW_MAX 8
2098 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2109 /* This will update the filename pointer if the loaded file is
2110 * reached by a symlink. The old string will be freed. */
2113 char *target, *name;
2115 if (c++ >= FOLLOW_MAX)
2118 path_kill_slashes(*filename);
2120 /* Add the file name we are currently looking at to
2121 * the names of this unit, but only if it is a valid
2123 name = path_get_file_name(*filename);
2125 if (unit_name_is_valid(name, true)) {
2127 id = set_get(names, name);
2133 r = set_put(names, id);
2141 /* Try to open the file name, but don't if its a symlink */
2142 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2149 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2150 r = readlink_and_make_absolute(*filename, &target);
2158 f = fdopen(fd, "re");
2161 close_nointr_nofail(fd);
2170 static int merge_by_names(Unit **u, Set *names, const char *id) {
2178 /* Let's try to add in all symlink names we found */
2179 while ((k = set_steal_first(names))) {
2181 /* First try to merge in the other name into our
2183 r = unit_merge_by_name(*u, k);
2187 /* Hmm, we couldn't merge the other unit into
2188 * ours? Then let's try it the other way
2191 other = manager_get_unit((*u)->manager, k);
2195 r = unit_merge(other, *u);
2198 return merge_by_names(u, names, NULL);
2206 unit_choose_id(*u, id);
2214 static int load_from_path(Unit *u, const char *path) {
2218 char *filename = NULL, *id = NULL;
2225 symlink_names = set_new(string_hash_func, string_compare_func);
2229 if (path_is_absolute(path)) {
2231 filename = strdup(path);
2237 r = open_follow(&filename, &f, symlink_names, &id);
2249 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2251 /* Instead of opening the path right away, we manually
2252 * follow all symlinks and add their name to our unit
2253 * name set while doing so */
2254 filename = path_make_absolute(path, *p);
2260 if (u->manager->unit_path_cache &&
2261 !set_get(u->manager->unit_path_cache, filename))
2264 r = open_follow(&filename, &f, symlink_names, &id);
2273 /* Empty the symlink names for the next run */
2274 set_clear_free(symlink_names);
2283 /* Hmm, no suitable file found? */
2289 r = merge_by_names(&merged, symlink_names, id);
2294 u->load_state = UNIT_MERGED;
2299 if (fstat(fileno(f), &st) < 0) {
2304 if (null_or_empty(&st))
2305 u->load_state = UNIT_MASKED;
2307 /* Now, parse the file contents */
2308 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2312 u->load_state = UNIT_LOADED;
2315 free(u->fragment_path);
2316 u->fragment_path = filename;
2319 u->fragment_mtime = timespec_load(&st.st_mtim);
2321 if (u->source_path) {
2322 if (stat(u->source_path, &st) >= 0)
2323 u->source_mtime = timespec_load(&st.st_mtim);
2325 u->source_mtime = 0;
2331 set_free_free(symlink_names);
2340 int unit_load_fragment(Unit *u) {
2346 assert(u->load_state == UNIT_STUB);
2349 /* First, try to find the unit under its id. We always look
2350 * for unit files in the default directories, to make it easy
2351 * to override things by placing things in /etc/systemd/system */
2352 r = load_from_path(u, u->id);
2356 /* Try to find an alias we can load this with */
2357 if (u->load_state == UNIT_STUB)
2358 SET_FOREACH(t, u->names, i) {
2363 r = load_from_path(u, t);
2367 if (u->load_state != UNIT_STUB)
2371 /* And now, try looking for it under the suggested (originally linked) path */
2372 if (u->load_state == UNIT_STUB && u->fragment_path) {
2374 r = load_from_path(u, u->fragment_path);
2378 if (u->load_state == UNIT_STUB) {
2379 /* Hmm, this didn't work? Then let's get rid
2380 * of the fragment path stored for us, so that
2381 * we don't point to an invalid location. */
2382 free(u->fragment_path);
2383 u->fragment_path = NULL;
2387 /* Look for a template */
2388 if (u->load_state == UNIT_STUB && u->instance) {
2391 k = unit_name_template(u->id);
2395 r = load_from_path(u, k);
2401 if (u->load_state == UNIT_STUB)
2402 SET_FOREACH(t, u->names, i) {
2407 k = unit_name_template(t);
2411 r = load_from_path(u, k);
2417 if (u->load_state != UNIT_STUB)
2425 void unit_dump_config_items(FILE *f) {
2426 static const struct {
2427 const ConfigParserCallback callback;
2430 { config_parse_int, "INTEGER" },
2431 { config_parse_unsigned, "UNSIGNED" },
2432 { config_parse_bytes_size, "SIZE" },
2433 { config_parse_bool, "BOOLEAN" },
2434 { config_parse_string, "STRING" },
2435 { config_parse_path, "PATH" },
2436 { config_parse_unit_path_printf, "PATH" },
2437 { config_parse_strv, "STRING [...]" },
2438 { config_parse_exec_nice, "NICE" },
2439 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2440 { config_parse_exec_io_class, "IOCLASS" },
2441 { config_parse_exec_io_priority, "IOPRIORITY" },
2442 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2443 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2444 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2445 { config_parse_mode, "MODE" },
2446 { config_parse_unit_env_file, "FILE" },
2447 { config_parse_output, "OUTPUT" },
2448 { config_parse_input, "INPUT" },
2449 { config_parse_facility, "FACILITY" },
2450 { config_parse_level, "LEVEL" },
2451 { config_parse_exec_capabilities, "CAPABILITIES" },
2452 { config_parse_exec_secure_bits, "SECUREBITS" },
2453 { config_parse_bounding_set, "BOUNDINGSET" },
2454 { config_parse_limit, "LIMIT" },
2455 { config_parse_unit_cgroup, "CGROUP [...]" },
2456 { config_parse_unit_deps, "UNIT [...]" },
2457 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2458 { config_parse_service_type, "SERVICETYPE" },
2459 { config_parse_service_restart, "SERVICERESTART" },
2460 #ifdef HAVE_SYSV_COMPAT
2461 { config_parse_sysv_priority, "SYSVPRIORITY" },
2463 { config_parse_warn_compat, "NOTSUPPORTED" },
2465 { config_parse_kill_mode, "KILLMODE" },
2466 { config_parse_kill_signal, "SIGNAL" },
2467 { config_parse_socket_listen, "SOCKET [...]" },
2468 { config_parse_socket_bind, "SOCKETBIND" },
2469 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2470 { config_parse_usec, "SECONDS" },
2471 { config_parse_nsec, "NANOSECONDS" },
2472 { config_parse_path_strv, "PATH [...]" },
2473 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2474 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2475 { config_parse_unit_string_printf, "STRING" },
2476 { config_parse_timer, "TIMER" },
2477 { config_parse_timer_unit, "NAME" },
2478 { config_parse_path_spec, "PATH" },
2479 { config_parse_path_unit, "UNIT" },
2480 { config_parse_notify_access, "ACCESS" },
2481 { config_parse_ip_tos, "TOS" },
2482 { config_parse_unit_condition_path, "CONDITION" },
2483 { config_parse_unit_condition_string, "CONDITION" },
2484 { config_parse_unit_condition_null, "CONDITION" },
2487 const char *prev = NULL;
2492 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2493 const char *rvalue = "OTHER", *lvalue;
2497 const ConfigPerfItem *p;
2499 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2501 dot = strchr(i, '.');
2502 lvalue = dot ? dot + 1 : i;
2506 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2510 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2513 for (j = 0; j < ELEMENTSOF(table); j++)
2514 if (p->parse == table[j].callback) {
2515 rvalue = table[j].rvalue;
2519 fprintf(f, "%s=%s\n", lvalue, rvalue);