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_exec_bounding_set(
935 const char *filename,
944 ExecContext *c = 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) {
971 if (!(t = strndup(w, l)))
974 r = cap_from_name(t, &cap);
978 log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
982 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
986 c->capability_bounding_set_drop |= sum;
988 c->capability_bounding_set_drop |= ~sum;
993 int config_parse_exec_timer_slack_nsec(
994 const char *filename,
1003 ExecContext *c = data;
1011 if (safe_atolu(rvalue, &u) < 0) {
1012 log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue);
1016 c->timer_slack_nsec = u;
1021 int config_parse_limit(
1022 const char *filename,
1024 const char *section,
1031 struct rlimit **rl = data;
1032 unsigned long long u;
1041 if (streq(rvalue, "infinity"))
1042 u = (unsigned long long) RLIM_INFINITY;
1043 else if (safe_atollu(rvalue, &u) < 0) {
1044 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
1049 if (!(*rl = new(struct rlimit, 1)))
1052 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1056 int config_parse_unit_cgroup(
1057 const char *filename,
1059 const char *section,
1071 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1079 k = unit_full_printf(u, t);
1091 r = unit_add_cgroup_from_text(u, t);
1095 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
1103 #ifdef HAVE_SYSV_COMPAT
1104 int config_parse_sysv_priority(
1105 const char *filename,
1107 const char *section,
1114 int *priority = data;
1122 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1123 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1127 *priority = (int) i;
1132 int config_parse_fsck_passno(
1133 const char *filename,
1135 const char *section,
1150 if (safe_atoi(rvalue, &i) || i < 0) {
1151 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1159 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1161 int config_parse_kill_signal(
1162 const char *filename,
1164 const char *section,
1179 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1180 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1188 int config_parse_exec_mount_flags(
1189 const char *filename,
1191 const char *section,
1198 ExecContext *c = data;
1202 unsigned long flags = 0;
1209 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1210 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1212 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1214 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1215 flags |= MS_PRIVATE;
1217 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1222 c->mount_flags = flags;
1226 int config_parse_timer(
1227 const char *filename,
1229 const char *section,
1246 if ((b = timer_base_from_string(lvalue)) < 0) {
1247 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1251 if (parse_usec(rvalue, &u) < 0) {
1252 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1256 if (!(v = new0(TimerValue, 1)))
1262 LIST_PREPEND(TimerValue, value, t->values, v);
1267 int config_parse_timer_unit(
1268 const char *filename,
1270 const char *section,
1287 dbus_error_init(&error);
1289 if (endswith(rvalue, ".timer")) {
1290 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1294 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
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(&t->unit, u);
1306 int config_parse_path_spec(
1307 const char *filename,
1309 const char *section,
1325 if ((b = path_type_from_string(lvalue)) < 0) {
1326 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1330 if (!path_is_absolute(rvalue)) {
1331 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1335 if (!(s = new0(PathSpec, 1)))
1338 if (!(s->path = strdup(rvalue))) {
1343 path_kill_slashes(s->path);
1348 LIST_PREPEND(PathSpec, spec, p->specs, s);
1353 int config_parse_path_unit(
1354 const char *filename,
1356 const char *section,
1373 dbus_error_init(&error);
1375 if (endswith(rvalue, ".path")) {
1376 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1380 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1381 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1382 dbus_error_free(&error);
1386 unit_ref_set(&t->unit, u);
1391 int config_parse_socket_service(
1392 const char *filename,
1394 const char *section,
1411 dbus_error_init(&error);
1413 if (!endswith(rvalue, ".service")) {
1414 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1418 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1420 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1421 dbus_error_free(&error);
1425 unit_ref_set(&s->service, x);
1430 int config_parse_service_sockets(
1431 const char *filename,
1433 const char *section,
1450 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1457 k = unit_name_printf(UNIT(s), t);
1463 if (!endswith(k, ".socket")) {
1464 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1469 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1471 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1473 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1483 int config_parse_unit_env_file(
1484 const char *filename,
1486 const char *section,
1493 char ***env = data, **k;
1502 s = unit_full_printf(u, rvalue);
1506 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1507 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1512 k = strv_append(*env, s);
1523 int config_parse_ip_tos(
1524 const char *filename,
1526 const char *section,
1533 int *ip_tos = data, x;
1540 if ((x = ip_tos_from_string(rvalue)) < 0)
1541 if (safe_atoi(rvalue, &x) < 0) {
1542 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1550 int config_parse_unit_condition_path(
1551 const char *filename,
1553 const char *section,
1560 ConditionType cond = ltype;
1562 bool trigger, negate;
1570 trigger = rvalue[0] == '|';
1574 negate = rvalue[0] == '!';
1578 if (!path_is_absolute(rvalue)) {
1579 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1583 c = condition_new(cond, rvalue, trigger, negate);
1587 LIST_PREPEND(Condition, conditions, u->conditions, c);
1591 int config_parse_unit_condition_string(
1592 const char *filename,
1594 const char *section,
1601 ConditionType cond = ltype;
1603 bool trigger, negate;
1611 if ((trigger = rvalue[0] == '|'))
1614 if ((negate = rvalue[0] == '!'))
1617 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1620 LIST_PREPEND(Condition, conditions, u->conditions, c);
1624 int config_parse_unit_condition_null(
1625 const char *filename,
1627 const char *section,
1636 bool trigger, negate;
1644 if ((trigger = rvalue[0] == '|'))
1647 if ((negate = rvalue[0] == '!'))
1650 if ((b = parse_boolean(rvalue)) < 0) {
1651 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1658 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1661 LIST_PREPEND(Condition, conditions, u->conditions, c);
1665 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1666 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1668 int config_parse_unit_cgroup_attr(
1669 const char *filename,
1671 const char *section,
1687 l = strv_split_quoted(rvalue);
1691 if (strv_length(l) != 2) {
1692 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1697 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1701 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1708 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) {
1719 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1720 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1724 if (asprintf(&t, "%lu", ul) < 0)
1727 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1731 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1738 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) {
1749 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1750 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1754 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1757 r = unit_add_cgroup_attribute(u,
1759 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1764 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1771 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1779 l = strv_split_quoted(value);
1783 assert(strv_length(l) >= 1);
1785 if (streq(l[0], "*")) {
1787 if (asprintf(ret, "a *:*%s%s",
1788 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1796 if (stat(l[0], &st) < 0) {
1797 log_warning("Couldn't stat device %s", l[0]);
1802 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1803 log_warning("%s is not a device.", l[0]);
1808 if (asprintf(ret, "%c %u:%u%s%s",
1809 S_ISCHR(st.st_mode) ? 'c' : 'b',
1810 major(st.st_rdev), minor(st.st_rdev),
1811 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1822 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) {
1833 l = strv_split_quoted(rvalue);
1838 if (k < 1 || k > 2) {
1839 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1844 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1845 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1850 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1851 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1857 r = unit_add_cgroup_attribute(u, "devices",
1858 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1859 rvalue, device_map);
1862 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1869 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1879 l = strv_split_quoted(value);
1883 assert(strv_length(l) == 2);
1885 if (stat(l[0], &st) < 0) {
1886 log_warning("Couldn't stat device %s", l[0]);
1891 if (S_ISBLK(st.st_mode))
1893 else if (major(st.st_dev) != 0) {
1894 /* If this is not a device node then find the block
1895 * device this file is stored on */
1898 /* If this is a partition, try to get the originating
1900 block_get_whole_disk(d, &d);
1902 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1907 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1916 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) {
1920 const char *device = NULL, *weight;
1929 l = strv_split_quoted(rvalue);
1934 if (k < 1 || k > 2) {
1935 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1947 if (device && !path_is_absolute(device)) {
1948 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1953 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1954 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1960 r = asprintf(&t, "%s %lu", device, ul);
1962 r = asprintf(&t, "%lu", ul);
1969 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1971 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1975 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1982 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) {
1994 l = strv_split_quoted(rvalue);
2000 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
2005 if (!path_is_absolute(l[0])) {
2006 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
2011 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
2012 log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
2017 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
2023 r = unit_add_cgroup_attribute(u, "blkio",
2024 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
2029 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
2036 int config_parse_unit_requires_mounts_for(
2037 const char *filename,
2039 const char *section,
2055 empty_before = !u->requires_mounts_for;
2057 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2059 /* Make it easy to find units with requires_mounts set */
2060 if (empty_before && u->requires_mounts_for)
2061 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2066 int config_parse_documentation(
2067 const char *filename,
2069 const char *section,
2085 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2089 for (a = b = u->documentation; a && *a; a++) {
2091 if (is_valid_documentation_url(*a))
2094 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2103 #define FOLLOW_MAX 8
2105 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2116 /* This will update the filename pointer if the loaded file is
2117 * reached by a symlink. The old string will be freed. */
2120 char *target, *name;
2122 if (c++ >= FOLLOW_MAX)
2125 path_kill_slashes(*filename);
2127 /* Add the file name we are currently looking at to
2128 * the names of this unit, but only if it is a valid
2130 name = path_get_file_name(*filename);
2132 if (unit_name_is_valid(name, true)) {
2134 id = set_get(names, name);
2140 r = set_put(names, id);
2148 /* Try to open the file name, but don't if its a symlink */
2149 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
2155 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2156 if ((r = readlink_and_make_absolute(*filename, &target)) < 0)
2163 if (!(f = fdopen(fd, "re"))) {
2165 close_nointr_nofail(fd);
2174 static int merge_by_names(Unit **u, Set *names, const char *id) {
2182 /* Let's try to add in all symlink names we found */
2183 while ((k = set_steal_first(names))) {
2185 /* First try to merge in the other name into our
2187 if ((r = unit_merge_by_name(*u, k)) < 0) {
2190 /* Hmm, we couldn't merge the other unit into
2191 * ours? Then let's try it the other way
2194 other = manager_get_unit((*u)->manager, k);
2198 if ((r = unit_merge(other, *u)) >= 0) {
2200 return merge_by_names(u, names, NULL);
2207 unit_choose_id(*u, id);
2215 static int load_from_path(Unit *u, const char *path) {
2219 char *filename = NULL, *id = NULL;
2226 symlink_names = set_new(string_hash_func, string_compare_func);
2230 if (path_is_absolute(path)) {
2232 if (!(filename = strdup(path))) {
2237 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
2248 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2250 /* Instead of opening the path right away, we manually
2251 * follow all symlinks and add their name to our unit
2252 * name set while doing so */
2253 if (!(filename = path_make_absolute(path, *p))) {
2258 if (u->manager->unit_path_cache &&
2259 !set_get(u->manager->unit_path_cache, filename))
2262 r = open_follow(&filename, &f, symlink_names, &id);
2273 /* Empty the symlink names for the next run */
2274 while ((sn = set_steal_first(symlink_names)))
2285 /* Hmm, no suitable file found? */
2291 if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
2295 u->load_state = UNIT_MERGED;
2301 if (fstat(fileno(f), &st) < 0) {
2306 if (null_or_empty(&st))
2307 u->load_state = UNIT_MASKED;
2309 /* Now, parse the file contents */
2310 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2314 u->load_state = UNIT_LOADED;
2317 free(u->fragment_path);
2318 u->fragment_path = filename;
2321 u->fragment_mtime = timespec_load(&st.st_mtim);
2326 set_free_free(symlink_names);
2335 int unit_load_fragment(Unit *u) {
2341 assert(u->load_state == UNIT_STUB);
2344 /* First, try to find the unit under its id. We always look
2345 * for unit files in the default directories, to make it easy
2346 * to override things by placing things in /etc/systemd/system */
2347 if ((r = load_from_path(u, u->id)) < 0)
2350 /* Try to find an alias we can load this with */
2351 if (u->load_state == UNIT_STUB)
2352 SET_FOREACH(t, u->names, i) {
2357 if ((r = load_from_path(u, t)) < 0)
2360 if (u->load_state != UNIT_STUB)
2364 /* And now, try looking for it under the suggested (originally linked) path */
2365 if (u->load_state == UNIT_STUB && u->fragment_path) {
2367 if ((r = load_from_path(u, u->fragment_path)) < 0)
2370 if (u->load_state == UNIT_STUB) {
2371 /* Hmm, this didn't work? Then let's get rid
2372 * of the fragment path stored for us, so that
2373 * we don't point to an invalid location. */
2374 free(u->fragment_path);
2375 u->fragment_path = NULL;
2379 /* Look for a template */
2380 if (u->load_state == UNIT_STUB && u->instance) {
2383 if (!(k = unit_name_template(u->id)))
2386 r = load_from_path(u, k);
2392 if (u->load_state == UNIT_STUB)
2393 SET_FOREACH(t, u->names, i) {
2398 if (!(k = unit_name_template(t)))
2401 r = load_from_path(u, k);
2407 if (u->load_state != UNIT_STUB)
2415 void unit_dump_config_items(FILE *f) {
2416 static const struct {
2417 const ConfigParserCallback callback;
2420 { config_parse_int, "INTEGER" },
2421 { config_parse_unsigned, "UNSIGNED" },
2422 { config_parse_bytes_size, "SIZE" },
2423 { config_parse_bool, "BOOLEAN" },
2424 { config_parse_string, "STRING" },
2425 { config_parse_path, "PATH" },
2426 { config_parse_unit_path_printf, "PATH" },
2427 { config_parse_strv, "STRING [...]" },
2428 { config_parse_exec_nice, "NICE" },
2429 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2430 { config_parse_exec_io_class, "IOCLASS" },
2431 { config_parse_exec_io_priority, "IOPRIORITY" },
2432 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2433 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2434 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2435 { config_parse_mode, "MODE" },
2436 { config_parse_unit_env_file, "FILE" },
2437 { config_parse_output, "OUTPUT" },
2438 { config_parse_input, "INPUT" },
2439 { config_parse_facility, "FACILITY" },
2440 { config_parse_level, "LEVEL" },
2441 { config_parse_exec_capabilities, "CAPABILITIES" },
2442 { config_parse_exec_secure_bits, "SECUREBITS" },
2443 { config_parse_exec_bounding_set, "BOUNDINGSET" },
2444 { config_parse_exec_timer_slack_nsec, "TIMERSLACK" },
2445 { config_parse_limit, "LIMIT" },
2446 { config_parse_unit_cgroup, "CGROUP [...]" },
2447 { config_parse_unit_deps, "UNIT [...]" },
2448 { config_parse_unit_names, "UNIT [...]" },
2449 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2450 { config_parse_service_type, "SERVICETYPE" },
2451 { config_parse_service_restart, "SERVICERESTART" },
2452 #ifdef HAVE_SYSV_COMPAT
2453 { config_parse_sysv_priority, "SYSVPRIORITY" },
2455 { config_parse_warn_compat, "NOTSUPPORTED" },
2457 { config_parse_kill_mode, "KILLMODE" },
2458 { config_parse_kill_signal, "SIGNAL" },
2459 { config_parse_socket_listen, "SOCKET [...]" },
2460 { config_parse_socket_bind, "SOCKETBIND" },
2461 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2462 { config_parse_usec, "SECONDS" },
2463 { config_parse_path_strv, "PATH [...]" },
2464 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2465 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2466 { config_parse_unit_string_printf, "STRING" },
2467 { config_parse_timer, "TIMER" },
2468 { config_parse_timer_unit, "NAME" },
2469 { config_parse_path_spec, "PATH" },
2470 { config_parse_path_unit, "UNIT" },
2471 { config_parse_notify_access, "ACCESS" },
2472 { config_parse_ip_tos, "TOS" },
2473 { config_parse_unit_condition_path, "CONDITION" },
2474 { config_parse_unit_condition_string, "CONDITION" },
2475 { config_parse_unit_condition_null, "CONDITION" },
2478 const char *prev = NULL;
2483 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2484 const char *rvalue = "OTHER", *lvalue;
2488 const ConfigPerfItem *p;
2490 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2492 dot = strchr(i, '.');
2493 lvalue = dot ? dot + 1 : i;
2497 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2501 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2504 for (j = 0; j < ELEMENTSOF(table); j++)
2505 if (p->parse == table[j].callback) {
2506 rvalue = table[j].rvalue;
2510 fprintf(f, "%s=%s\n", lvalue, rvalue);