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"
49 #ifndef HAVE_SYSV_COMPAT
50 int config_parse_warn_compat(
60 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
65 int config_parse_unit_deps(
75 UnitDependency d = ltype;
85 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
93 k = unit_name_printf(u, t);
98 r = unit_add_dependency_by_name(u, d, k, NULL, true);
100 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
108 int config_parse_unit_names(
109 const char *filename,
128 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
136 k = unit_name_printf(u, t);
141 r = unit_merge_by_name(u, k);
143 log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
151 int config_parse_unit_string_printf(
152 const char *filename,
170 k = unit_full_printf(u, rvalue);
174 r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
180 int config_parse_unit_strv_printf(
181 const char *filename,
199 k = unit_full_printf(u, rvalue);
203 r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
209 int config_parse_unit_path_printf(
210 const char *filename,
228 k = unit_full_printf(u, rvalue);
232 r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
238 int config_parse_socket_listen(
239 const char *filename,
248 SocketPort *p, *tail;
258 p = new0(SocketPort, 1);
262 if (streq(lvalue, "ListenFIFO")) {
263 p->type = SOCKET_FIFO;
265 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
270 path_kill_slashes(p->path);
272 } else if (streq(lvalue, "ListenSpecial")) {
273 p->type = SOCKET_SPECIAL;
275 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
280 path_kill_slashes(p->path);
282 } else if (streq(lvalue, "ListenMessageQueue")) {
284 p->type = SOCKET_MQUEUE;
286 if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
291 path_kill_slashes(p->path);
293 } else if (streq(lvalue, "ListenNetlink")) {
297 p->type = SOCKET_SOCKET;
298 k = unit_full_printf(UNIT(s), rvalue);
299 r = socket_address_parse_netlink(&p->address, k);
303 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
312 p->type = SOCKET_SOCKET;
313 k = unit_full_printf(UNIT(s), rvalue);
314 r = socket_address_parse(&p->address, k);
318 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
323 if (streq(lvalue, "ListenStream"))
324 p->address.type = SOCK_STREAM;
325 else if (streq(lvalue, "ListenDatagram"))
326 p->address.type = SOCK_DGRAM;
328 assert(streq(lvalue, "ListenSequentialPacket"));
329 p->address.type = SOCK_SEQPACKET;
332 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
333 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
342 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
343 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
345 LIST_PREPEND(SocketPort, port, s->ports, p);
350 int config_parse_socket_bind(
351 const char *filename,
361 SocketAddressBindIPv6Only b;
370 if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) {
373 if ((r = parse_boolean(rvalue)) < 0) {
374 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
378 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
380 s->bind_ipv6_only = b;
385 int config_parse_exec_nice(
386 const char *filename,
395 ExecContext *c = data;
403 if (safe_atoi(rvalue, &priority) < 0) {
404 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
408 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
409 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
419 int config_parse_exec_oom_score_adjust(
420 const char *filename,
429 ExecContext *c = data;
437 if (safe_atoi(rvalue, &oa) < 0) {
438 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
442 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
443 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
447 c->oom_score_adjust = oa;
448 c->oom_score_adjust_set = true;
453 int config_parse_exec(
454 const char *filename,
463 ExecCommand **e = data, *nce;
473 /* We accept an absolute path as first argument, or
474 * alternatively an absolute prefixed with @ to allow
475 * overriding of argv[0]. */
483 bool honour_argv0 = false, ignore = false;
489 rvalue += strspn(rvalue, WHITESPACE);
494 if (rvalue[0] == '-') {
499 if (rvalue[0] == '@') {
504 if (*rvalue != '/') {
505 log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
510 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
511 if (strncmp(w, ";", MAX(l, 1U)) == 0)
517 n = new(char*, k + !honour_argv0);
522 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
523 if (strncmp(w, ";", MAX(l, 1U)) == 0)
526 if (honour_argv0 && w == rvalue) {
529 path = strndup(w, l);
535 if (!utf8_is_valid(path)) {
536 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
544 c = n[k++] = cunescape_length(w, l);
550 if (!utf8_is_valid(c)) {
551 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
561 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
574 assert(path_is_absolute(path));
576 nce = new0(ExecCommand, 1);
584 nce->ignore = ignore;
586 path_kill_slashes(nce->path);
588 exec_command_append_list(e, nce);
604 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
605 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
607 int config_parse_socket_bindtodevice(
608 const char *filename,
625 if (rvalue[0] && !streq(rvalue, "*")) {
626 if (!(n = strdup(rvalue)))
631 free(s->bind_to_device);
632 s->bind_to_device = n;
637 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
638 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
640 int config_parse_facility(
641 const char *filename,
658 if ((x = log_facility_unshifted_from_string(rvalue)) < 0) {
659 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
663 *o = (x << 3) | LOG_PRI(*o);
668 int config_parse_level(
669 const char *filename,
686 if ((x = log_level_from_string(rvalue)) < 0) {
687 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
691 *o = (*o & LOG_FACMASK) | x;
695 int config_parse_exec_io_class(
696 const char *filename,
705 ExecContext *c = data;
713 if ((x = ioprio_class_from_string(rvalue)) < 0) {
714 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
718 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
719 c->ioprio_set = true;
724 int config_parse_exec_io_priority(
725 const char *filename,
734 ExecContext *c = data;
742 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
743 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
747 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
748 c->ioprio_set = true;
753 int config_parse_exec_cpu_sched_policy(
754 const char *filename,
764 ExecContext *c = data;
772 if ((x = sched_policy_from_string(rvalue)) < 0) {
773 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
777 c->cpu_sched_policy = x;
778 c->cpu_sched_set = true;
783 int config_parse_exec_cpu_sched_prio(
784 const char *filename,
793 ExecContext *c = data;
801 /* On Linux RR/FIFO have the same range */
802 if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
803 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
807 c->cpu_sched_priority = i;
808 c->cpu_sched_set = true;
813 int config_parse_exec_cpu_affinity(
814 const char *filename,
823 ExecContext *c = data;
833 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
838 if (!(t = strndup(w, l)))
841 r = safe_atou(t, &cpu);
845 if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
848 if (r < 0 || cpu >= c->cpuset_ncpus) {
849 log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
853 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
859 int config_parse_exec_capabilities(
860 const char *filename,
869 ExecContext *c = data;
877 if (!(cap = cap_from_text(rvalue))) {
881 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
886 cap_free(c->capabilities);
887 c->capabilities = cap;
892 int config_parse_exec_secure_bits(
893 const char *filename,
902 ExecContext *c = data;
912 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
913 if (first_word(w, "keep-caps"))
914 c->secure_bits |= SECURE_KEEP_CAPS;
915 else if (first_word(w, "keep-caps-locked"))
916 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
917 else if (first_word(w, "no-setuid-fixup"))
918 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
919 else if (first_word(w, "no-setuid-fixup-locked"))
920 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
921 else if (first_word(w, "noroot"))
922 c->secure_bits |= SECURE_NOROOT;
923 else if (first_word(w, "noroot-locked"))
924 c->secure_bits |= SECURE_NOROOT_LOCKED;
926 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
934 int config_parse_bounding_set(
935 const char *filename,
944 uint64_t *capability_bounding_set_drop = data;
956 if (rvalue[0] == '~') {
961 /* Note that we store this inverted internally, since the
962 * kernel wants it like this. But we actually expose it
963 * non-inverted everywhere to have a fully normalized
966 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
975 r = cap_from_name(t, &cap);
979 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
983 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
987 *capability_bounding_set_drop |= sum;
989 *capability_bounding_set_drop |= ~sum;
994 int config_parse_limit(
995 const char *filename,
1004 struct rlimit **rl = data;
1005 unsigned long long u;
1014 if (streq(rvalue, "infinity"))
1015 u = (unsigned long long) RLIM_INFINITY;
1016 else if (safe_atollu(rvalue, &u) < 0) {
1017 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
1022 if (!(*rl = new(struct rlimit, 1)))
1025 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1029 int config_parse_unit_cgroup(
1030 const char *filename,
1032 const char *section,
1044 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1052 k = unit_full_printf(u, t);
1064 r = unit_add_cgroup_from_text(u, t);
1068 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
1076 #ifdef HAVE_SYSV_COMPAT
1077 int config_parse_sysv_priority(
1078 const char *filename,
1080 const char *section,
1087 int *priority = data;
1095 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1096 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1100 *priority = (int) i;
1105 int config_parse_fsck_passno(
1106 const char *filename,
1108 const char *section,
1123 if (safe_atoi(rvalue, &i) || i < 0) {
1124 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1132 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1134 int config_parse_kill_signal(
1135 const char *filename,
1137 const char *section,
1152 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1153 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1161 int config_parse_exec_mount_flags(
1162 const char *filename,
1164 const char *section,
1171 ExecContext *c = data;
1175 unsigned long flags = 0;
1182 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1183 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1185 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1187 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1188 flags |= MS_PRIVATE;
1190 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1195 c->mount_flags = flags;
1199 int config_parse_timer(
1200 const char *filename,
1202 const char *section,
1219 if ((b = timer_base_from_string(lvalue)) < 0) {
1220 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1224 if (parse_usec(rvalue, &u) < 0) {
1225 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1229 if (!(v = new0(TimerValue, 1)))
1235 LIST_PREPEND(TimerValue, value, t->values, v);
1240 int config_parse_timer_unit(
1241 const char *filename,
1243 const char *section,
1260 dbus_error_init(&error);
1262 if (endswith(rvalue, ".timer")) {
1263 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1267 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1269 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1270 dbus_error_free(&error);
1274 unit_ref_set(&t->unit, u);
1279 int config_parse_path_spec(
1280 const char *filename,
1282 const char *section,
1298 if ((b = path_type_from_string(lvalue)) < 0) {
1299 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1303 if (!path_is_absolute(rvalue)) {
1304 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1308 if (!(s = new0(PathSpec, 1)))
1311 if (!(s->path = strdup(rvalue))) {
1316 path_kill_slashes(s->path);
1321 LIST_PREPEND(PathSpec, spec, p->specs, s);
1326 int config_parse_path_unit(
1327 const char *filename,
1329 const char *section,
1346 dbus_error_init(&error);
1348 if (endswith(rvalue, ".path")) {
1349 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1353 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1354 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1355 dbus_error_free(&error);
1359 unit_ref_set(&t->unit, u);
1364 int config_parse_socket_service(
1365 const char *filename,
1367 const char *section,
1384 dbus_error_init(&error);
1386 if (!endswith(rvalue, ".service")) {
1387 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1391 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1393 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1394 dbus_error_free(&error);
1398 unit_ref_set(&s->service, x);
1403 int config_parse_service_sockets(
1404 const char *filename,
1406 const char *section,
1423 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1430 k = unit_name_printf(UNIT(s), t);
1436 if (!endswith(k, ".socket")) {
1437 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1442 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1444 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1446 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1456 int config_parse_unit_env_file(
1457 const char *filename,
1459 const char *section,
1466 char ***env = data, **k;
1475 s = unit_full_printf(u, rvalue);
1479 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1480 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1485 k = strv_append(*env, s);
1496 int config_parse_ip_tos(
1497 const char *filename,
1499 const char *section,
1506 int *ip_tos = data, x;
1513 if ((x = ip_tos_from_string(rvalue)) < 0)
1514 if (safe_atoi(rvalue, &x) < 0) {
1515 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1523 int config_parse_unit_condition_path(
1524 const char *filename,
1526 const char *section,
1533 ConditionType cond = ltype;
1535 bool trigger, negate;
1543 trigger = rvalue[0] == '|';
1547 negate = rvalue[0] == '!';
1551 if (!path_is_absolute(rvalue)) {
1552 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1556 c = condition_new(cond, rvalue, trigger, negate);
1560 LIST_PREPEND(Condition, conditions, u->conditions, c);
1564 int config_parse_unit_condition_string(
1565 const char *filename,
1567 const char *section,
1574 ConditionType cond = ltype;
1576 bool trigger, negate;
1584 if ((trigger = rvalue[0] == '|'))
1587 if ((negate = rvalue[0] == '!'))
1590 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1593 LIST_PREPEND(Condition, conditions, u->conditions, c);
1597 int config_parse_unit_condition_null(
1598 const char *filename,
1600 const char *section,
1609 bool trigger, negate;
1617 if ((trigger = rvalue[0] == '|'))
1620 if ((negate = rvalue[0] == '!'))
1623 if ((b = parse_boolean(rvalue)) < 0) {
1624 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1631 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1634 LIST_PREPEND(Condition, conditions, u->conditions, c);
1638 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1639 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1641 int config_parse_unit_cgroup_attr(
1642 const char *filename,
1644 const char *section,
1660 l = strv_split_quoted(rvalue);
1664 if (strv_length(l) != 2) {
1665 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1670 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1674 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1681 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) {
1692 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1693 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1697 if (asprintf(&t, "%lu", ul) < 0)
1700 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1704 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1711 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) {
1722 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1723 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1727 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1730 r = unit_add_cgroup_attribute(u,
1732 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1737 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1744 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1752 l = strv_split_quoted(value);
1756 assert(strv_length(l) >= 1);
1758 if (streq(l[0], "*")) {
1760 if (asprintf(ret, "a *:*%s%s",
1761 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1769 if (stat(l[0], &st) < 0) {
1770 log_warning("Couldn't stat device %s", l[0]);
1775 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1776 log_warning("%s is not a device.", l[0]);
1781 if (asprintf(ret, "%c %u:%u%s%s",
1782 S_ISCHR(st.st_mode) ? 'c' : 'b',
1783 major(st.st_rdev), minor(st.st_rdev),
1784 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1795 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) {
1806 l = strv_split_quoted(rvalue);
1811 if (k < 1 || k > 2) {
1812 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1817 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1818 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1823 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1824 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1830 r = unit_add_cgroup_attribute(u, "devices",
1831 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1832 rvalue, device_map);
1835 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1842 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1852 l = strv_split_quoted(value);
1856 assert(strv_length(l) == 2);
1858 if (stat(l[0], &st) < 0) {
1859 log_warning("Couldn't stat device %s", l[0]);
1864 if (S_ISBLK(st.st_mode))
1866 else if (major(st.st_dev) != 0) {
1867 /* If this is not a device node then find the block
1868 * device this file is stored on */
1871 /* If this is a partition, try to get the originating
1873 block_get_whole_disk(d, &d);
1875 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1880 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1889 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) {
1893 const char *device = NULL, *weight;
1902 l = strv_split_quoted(rvalue);
1907 if (k < 1 || k > 2) {
1908 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1920 if (device && !path_is_absolute(device)) {
1921 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1926 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1927 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1933 r = asprintf(&t, "%s %lu", device, ul);
1935 r = asprintf(&t, "%lu", ul);
1942 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1944 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1948 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1955 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) {
1967 l = strv_split_quoted(rvalue);
1973 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
1978 if (!path_is_absolute(l[0])) {
1979 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1984 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
1985 log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
1990 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
1996 r = unit_add_cgroup_attribute(u, "blkio",
1997 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
2002 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
2009 int config_parse_unit_requires_mounts_for(
2010 const char *filename,
2012 const char *section,
2028 empty_before = !u->requires_mounts_for;
2030 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2032 /* Make it easy to find units with requires_mounts set */
2033 if (empty_before && u->requires_mounts_for)
2034 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2039 int config_parse_documentation(
2040 const char *filename,
2042 const char *section,
2058 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2062 for (a = b = u->documentation; a && *a; a++) {
2064 if (is_valid_documentation_url(*a))
2067 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2076 #define FOLLOW_MAX 8
2078 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2089 /* This will update the filename pointer if the loaded file is
2090 * reached by a symlink. The old string will be freed. */
2093 char *target, *name;
2095 if (c++ >= FOLLOW_MAX)
2098 path_kill_slashes(*filename);
2100 /* Add the file name we are currently looking at to
2101 * the names of this unit, but only if it is a valid
2103 name = path_get_file_name(*filename);
2105 if (unit_name_is_valid(name, true)) {
2107 id = set_get(names, name);
2113 r = set_put(names, id);
2121 /* Try to open the file name, but don't if its a symlink */
2122 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
2128 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2129 if ((r = readlink_and_make_absolute(*filename, &target)) < 0)
2136 if (!(f = fdopen(fd, "re"))) {
2138 close_nointr_nofail(fd);
2147 static int merge_by_names(Unit **u, Set *names, const char *id) {
2155 /* Let's try to add in all symlink names we found */
2156 while ((k = set_steal_first(names))) {
2158 /* First try to merge in the other name into our
2160 if ((r = unit_merge_by_name(*u, k)) < 0) {
2163 /* Hmm, we couldn't merge the other unit into
2164 * ours? Then let's try it the other way
2167 other = manager_get_unit((*u)->manager, k);
2171 if ((r = unit_merge(other, *u)) >= 0) {
2173 return merge_by_names(u, names, NULL);
2180 unit_choose_id(*u, id);
2188 static int load_from_path(Unit *u, const char *path) {
2192 char *filename = NULL, *id = NULL;
2199 symlink_names = set_new(string_hash_func, string_compare_func);
2203 if (path_is_absolute(path)) {
2205 if (!(filename = strdup(path))) {
2210 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
2221 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2223 /* Instead of opening the path right away, we manually
2224 * follow all symlinks and add their name to our unit
2225 * name set while doing so */
2226 if (!(filename = path_make_absolute(path, *p))) {
2231 if (u->manager->unit_path_cache &&
2232 !set_get(u->manager->unit_path_cache, filename))
2235 r = open_follow(&filename, &f, symlink_names, &id);
2246 /* Empty the symlink names for the next run */
2247 while ((sn = set_steal_first(symlink_names)))
2258 /* Hmm, no suitable file found? */
2264 if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
2268 u->load_state = UNIT_MERGED;
2274 if (fstat(fileno(f), &st) < 0) {
2279 if (null_or_empty(&st))
2280 u->load_state = UNIT_MASKED;
2282 /* Now, parse the file contents */
2283 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2287 u->load_state = UNIT_LOADED;
2290 free(u->fragment_path);
2291 u->fragment_path = filename;
2294 u->fragment_mtime = timespec_load(&st.st_mtim);
2296 if (u->source_path) {
2297 if (stat(u->source_path, &st) >= 0)
2298 u->source_mtime = timespec_load(&st.st_mtim);
2300 u->source_mtime = 0;
2306 set_free_free(symlink_names);
2315 int unit_load_fragment(Unit *u) {
2321 assert(u->load_state == UNIT_STUB);
2324 /* First, try to find the unit under its id. We always look
2325 * for unit files in the default directories, to make it easy
2326 * to override things by placing things in /etc/systemd/system */
2327 if ((r = load_from_path(u, u->id)) < 0)
2330 /* Try to find an alias we can load this with */
2331 if (u->load_state == UNIT_STUB)
2332 SET_FOREACH(t, u->names, i) {
2337 if ((r = load_from_path(u, t)) < 0)
2340 if (u->load_state != UNIT_STUB)
2344 /* And now, try looking for it under the suggested (originally linked) path */
2345 if (u->load_state == UNIT_STUB && u->fragment_path) {
2347 if ((r = load_from_path(u, u->fragment_path)) < 0)
2350 if (u->load_state == UNIT_STUB) {
2351 /* Hmm, this didn't work? Then let's get rid
2352 * of the fragment path stored for us, so that
2353 * we don't point to an invalid location. */
2354 free(u->fragment_path);
2355 u->fragment_path = NULL;
2359 /* Look for a template */
2360 if (u->load_state == UNIT_STUB && u->instance) {
2363 if (!(k = unit_name_template(u->id)))
2366 r = load_from_path(u, k);
2372 if (u->load_state == UNIT_STUB)
2373 SET_FOREACH(t, u->names, i) {
2378 if (!(k = unit_name_template(t)))
2381 r = load_from_path(u, k);
2387 if (u->load_state != UNIT_STUB)
2395 void unit_dump_config_items(FILE *f) {
2396 static const struct {
2397 const ConfigParserCallback callback;
2400 { config_parse_int, "INTEGER" },
2401 { config_parse_unsigned, "UNSIGNED" },
2402 { config_parse_bytes_size, "SIZE" },
2403 { config_parse_bool, "BOOLEAN" },
2404 { config_parse_string, "STRING" },
2405 { config_parse_path, "PATH" },
2406 { config_parse_unit_path_printf, "PATH" },
2407 { config_parse_strv, "STRING [...]" },
2408 { config_parse_exec_nice, "NICE" },
2409 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2410 { config_parse_exec_io_class, "IOCLASS" },
2411 { config_parse_exec_io_priority, "IOPRIORITY" },
2412 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2413 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2414 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2415 { config_parse_mode, "MODE" },
2416 { config_parse_unit_env_file, "FILE" },
2417 { config_parse_output, "OUTPUT" },
2418 { config_parse_input, "INPUT" },
2419 { config_parse_facility, "FACILITY" },
2420 { config_parse_level, "LEVEL" },
2421 { config_parse_exec_capabilities, "CAPABILITIES" },
2422 { config_parse_exec_secure_bits, "SECUREBITS" },
2423 { config_parse_bounding_set, "BOUNDINGSET" },
2424 { config_parse_limit, "LIMIT" },
2425 { config_parse_unit_cgroup, "CGROUP [...]" },
2426 { config_parse_unit_deps, "UNIT [...]" },
2427 { config_parse_unit_names, "UNIT [...]" },
2428 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2429 { config_parse_service_type, "SERVICETYPE" },
2430 { config_parse_service_restart, "SERVICERESTART" },
2431 #ifdef HAVE_SYSV_COMPAT
2432 { config_parse_sysv_priority, "SYSVPRIORITY" },
2434 { config_parse_warn_compat, "NOTSUPPORTED" },
2436 { config_parse_kill_mode, "KILLMODE" },
2437 { config_parse_kill_signal, "SIGNAL" },
2438 { config_parse_socket_listen, "SOCKET [...]" },
2439 { config_parse_socket_bind, "SOCKETBIND" },
2440 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2441 { config_parse_usec, "SECONDS" },
2442 { config_parse_nsec, "NANOSECONDS" },
2443 { config_parse_path_strv, "PATH [...]" },
2444 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2445 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2446 { config_parse_unit_string_printf, "STRING" },
2447 { config_parse_timer, "TIMER" },
2448 { config_parse_timer_unit, "NAME" },
2449 { config_parse_path_spec, "PATH" },
2450 { config_parse_path_unit, "UNIT" },
2451 { config_parse_notify_access, "ACCESS" },
2452 { config_parse_ip_tos, "TOS" },
2453 { config_parse_unit_condition_path, "CONDITION" },
2454 { config_parse_unit_condition_string, "CONDITION" },
2455 { config_parse_unit_condition_null, "CONDITION" },
2458 const char *prev = NULL;
2463 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2464 const char *rvalue = "OTHER", *lvalue;
2468 const ConfigPerfItem *p;
2470 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2472 dot = strchr(i, '.');
2473 lvalue = dot ? dot + 1 : i;
2477 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2481 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2484 for (j = 0; j < ELEMENTSOF(table); j++)
2485 if (p->parse == table[j].callback) {
2486 rvalue = table[j].rvalue;
2490 fprintf(f, "%s=%s\n", lvalue, rvalue);