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_exec_timer_slack_nsec(
995 const char *filename,
1004 ExecContext *c = data;
1012 if (safe_atolu(rvalue, &u) < 0) {
1013 log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue);
1017 c->timer_slack_nsec = u;
1022 int config_parse_limit(
1023 const char *filename,
1025 const char *section,
1032 struct rlimit **rl = data;
1033 unsigned long long u;
1042 if (streq(rvalue, "infinity"))
1043 u = (unsigned long long) RLIM_INFINITY;
1044 else if (safe_atollu(rvalue, &u) < 0) {
1045 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
1050 if (!(*rl = new(struct rlimit, 1)))
1053 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1057 int config_parse_unit_cgroup(
1058 const char *filename,
1060 const char *section,
1072 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1080 k = unit_full_printf(u, t);
1092 r = unit_add_cgroup_from_text(u, t);
1096 log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
1104 #ifdef HAVE_SYSV_COMPAT
1105 int config_parse_sysv_priority(
1106 const char *filename,
1108 const char *section,
1115 int *priority = data;
1123 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1124 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1128 *priority = (int) i;
1133 int config_parse_fsck_passno(
1134 const char *filename,
1136 const char *section,
1151 if (safe_atoi(rvalue, &i) || i < 0) {
1152 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1160 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1162 int config_parse_kill_signal(
1163 const char *filename,
1165 const char *section,
1180 if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
1181 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1189 int config_parse_exec_mount_flags(
1190 const char *filename,
1192 const char *section,
1199 ExecContext *c = data;
1203 unsigned long flags = 0;
1210 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1211 if (strncmp(w, "shared", MAX(l, 6U)) == 0)
1213 else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
1215 else if (strncmp(w, "private", MAX(l, 7U)) == 0)
1216 flags |= MS_PRIVATE;
1218 log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
1223 c->mount_flags = flags;
1227 int config_parse_timer(
1228 const char *filename,
1230 const char *section,
1247 if ((b = timer_base_from_string(lvalue)) < 0) {
1248 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1252 if (parse_usec(rvalue, &u) < 0) {
1253 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1257 if (!(v = new0(TimerValue, 1)))
1263 LIST_PREPEND(TimerValue, value, t->values, v);
1268 int config_parse_timer_unit(
1269 const char *filename,
1271 const char *section,
1288 dbus_error_init(&error);
1290 if (endswith(rvalue, ".timer")) {
1291 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1295 r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
1297 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1298 dbus_error_free(&error);
1302 unit_ref_set(&t->unit, u);
1307 int config_parse_path_spec(
1308 const char *filename,
1310 const char *section,
1326 if ((b = path_type_from_string(lvalue)) < 0) {
1327 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1331 if (!path_is_absolute(rvalue)) {
1332 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
1336 if (!(s = new0(PathSpec, 1)))
1339 if (!(s->path = strdup(rvalue))) {
1344 path_kill_slashes(s->path);
1349 LIST_PREPEND(PathSpec, spec, p->specs, s);
1354 int config_parse_path_unit(
1355 const char *filename,
1357 const char *section,
1374 dbus_error_init(&error);
1376 if (endswith(rvalue, ".path")) {
1377 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
1381 if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
1382 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1383 dbus_error_free(&error);
1387 unit_ref_set(&t->unit, u);
1392 int config_parse_socket_service(
1393 const char *filename,
1395 const char *section,
1412 dbus_error_init(&error);
1414 if (!endswith(rvalue, ".service")) {
1415 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1419 r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
1421 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1422 dbus_error_free(&error);
1426 unit_ref_set(&s->service, x);
1431 int config_parse_service_sockets(
1432 const char *filename,
1434 const char *section,
1451 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1458 k = unit_name_printf(UNIT(s), t);
1464 if (!endswith(k, ".socket")) {
1465 log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
1470 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1472 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
1474 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1484 int config_parse_unit_env_file(
1485 const char *filename,
1487 const char *section,
1494 char ***env = data, **k;
1503 s = unit_full_printf(u, rvalue);
1507 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1508 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1513 k = strv_append(*env, s);
1524 int config_parse_ip_tos(
1525 const char *filename,
1527 const char *section,
1534 int *ip_tos = data, x;
1541 if ((x = ip_tos_from_string(rvalue)) < 0)
1542 if (safe_atoi(rvalue, &x) < 0) {
1543 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1551 int config_parse_unit_condition_path(
1552 const char *filename,
1554 const char *section,
1561 ConditionType cond = ltype;
1563 bool trigger, negate;
1571 trigger = rvalue[0] == '|';
1575 negate = rvalue[0] == '!';
1579 if (!path_is_absolute(rvalue)) {
1580 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue);
1584 c = condition_new(cond, rvalue, trigger, negate);
1588 LIST_PREPEND(Condition, conditions, u->conditions, c);
1592 int config_parse_unit_condition_string(
1593 const char *filename,
1595 const char *section,
1602 ConditionType cond = ltype;
1604 bool trigger, negate;
1612 if ((trigger = rvalue[0] == '|'))
1615 if ((negate = rvalue[0] == '!'))
1618 if (!(c = condition_new(cond, rvalue, trigger, negate)))
1621 LIST_PREPEND(Condition, conditions, u->conditions, c);
1625 int config_parse_unit_condition_null(
1626 const char *filename,
1628 const char *section,
1637 bool trigger, negate;
1645 if ((trigger = rvalue[0] == '|'))
1648 if ((negate = rvalue[0] == '!'))
1651 if ((b = parse_boolean(rvalue)) < 0) {
1652 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1659 if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
1662 LIST_PREPEND(Condition, conditions, u->conditions, c);
1666 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1667 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1669 int config_parse_unit_cgroup_attr(
1670 const char *filename,
1672 const char *section,
1688 l = strv_split_quoted(rvalue);
1692 if (strv_length(l) != 2) {
1693 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1698 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
1702 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1709 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) {
1720 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1721 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1725 if (asprintf(&t, "%lu", ul) < 0)
1728 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
1732 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1739 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) {
1750 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1751 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1755 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1758 r = unit_add_cgroup_attribute(u,
1760 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1765 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1772 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1780 l = strv_split_quoted(value);
1784 assert(strv_length(l) >= 1);
1786 if (streq(l[0], "*")) {
1788 if (asprintf(ret, "a *:*%s%s",
1789 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1797 if (stat(l[0], &st) < 0) {
1798 log_warning("Couldn't stat device %s", l[0]);
1803 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1804 log_warning("%s is not a device.", l[0]);
1809 if (asprintf(ret, "%c %u:%u%s%s",
1810 S_ISCHR(st.st_mode) ? 'c' : 'b',
1811 major(st.st_rdev), minor(st.st_rdev),
1812 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
1823 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) {
1834 l = strv_split_quoted(rvalue);
1839 if (k < 1 || k > 2) {
1840 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1845 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1846 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1851 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1852 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1858 r = unit_add_cgroup_attribute(u, "devices",
1859 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1860 rvalue, device_map);
1863 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1870 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1880 l = strv_split_quoted(value);
1884 assert(strv_length(l) == 2);
1886 if (stat(l[0], &st) < 0) {
1887 log_warning("Couldn't stat device %s", l[0]);
1892 if (S_ISBLK(st.st_mode))
1894 else if (major(st.st_dev) != 0) {
1895 /* If this is not a device node then find the block
1896 * device this file is stored on */
1899 /* If this is a partition, try to get the originating
1901 block_get_whole_disk(d, &d);
1903 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1908 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
1917 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) {
1921 const char *device = NULL, *weight;
1930 l = strv_split_quoted(rvalue);
1935 if (k < 1 || k > 2) {
1936 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1948 if (device && !path_is_absolute(device)) {
1949 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1954 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1955 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1961 r = asprintf(&t, "%s %lu", device, ul);
1963 r = asprintf(&t, "%lu", ul);
1970 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
1972 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
1976 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1983 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) {
1995 l = strv_split_quoted(rvalue);
2001 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
2006 if (!path_is_absolute(l[0])) {
2007 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
2012 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
2013 log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
2018 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
2024 r = unit_add_cgroup_attribute(u, "blkio",
2025 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
2030 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
2037 int config_parse_unit_requires_mounts_for(
2038 const char *filename,
2040 const char *section,
2056 empty_before = !u->requires_mounts_for;
2058 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2060 /* Make it easy to find units with requires_mounts set */
2061 if (empty_before && u->requires_mounts_for)
2062 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2067 int config_parse_documentation(
2068 const char *filename,
2070 const char *section,
2086 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2090 for (a = b = u->documentation; a && *a; a++) {
2092 if (is_valid_documentation_url(*a))
2095 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2104 #define FOLLOW_MAX 8
2106 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2117 /* This will update the filename pointer if the loaded file is
2118 * reached by a symlink. The old string will be freed. */
2121 char *target, *name;
2123 if (c++ >= FOLLOW_MAX)
2126 path_kill_slashes(*filename);
2128 /* Add the file name we are currently looking at to
2129 * the names of this unit, but only if it is a valid
2131 name = path_get_file_name(*filename);
2133 if (unit_name_is_valid(name, true)) {
2135 id = set_get(names, name);
2141 r = set_put(names, id);
2149 /* Try to open the file name, but don't if its a symlink */
2150 if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0)
2156 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2157 if ((r = readlink_and_make_absolute(*filename, &target)) < 0)
2164 if (!(f = fdopen(fd, "re"))) {
2166 close_nointr_nofail(fd);
2175 static int merge_by_names(Unit **u, Set *names, const char *id) {
2183 /* Let's try to add in all symlink names we found */
2184 while ((k = set_steal_first(names))) {
2186 /* First try to merge in the other name into our
2188 if ((r = unit_merge_by_name(*u, k)) < 0) {
2191 /* Hmm, we couldn't merge the other unit into
2192 * ours? Then let's try it the other way
2195 other = manager_get_unit((*u)->manager, k);
2199 if ((r = unit_merge(other, *u)) >= 0) {
2201 return merge_by_names(u, names, NULL);
2208 unit_choose_id(*u, id);
2216 static int load_from_path(Unit *u, const char *path) {
2220 char *filename = NULL, *id = NULL;
2227 symlink_names = set_new(string_hash_func, string_compare_func);
2231 if (path_is_absolute(path)) {
2233 if (!(filename = strdup(path))) {
2238 if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
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 if (!(filename = path_make_absolute(path, *p))) {
2259 if (u->manager->unit_path_cache &&
2260 !set_get(u->manager->unit_path_cache, filename))
2263 r = open_follow(&filename, &f, symlink_names, &id);
2274 /* Empty the symlink names for the next run */
2275 while ((sn = set_steal_first(symlink_names)))
2286 /* Hmm, no suitable file found? */
2292 if ((r = merge_by_names(&merged, symlink_names, id)) < 0)
2296 u->load_state = UNIT_MERGED;
2302 if (fstat(fileno(f), &st) < 0) {
2307 if (null_or_empty(&st))
2308 u->load_state = UNIT_MASKED;
2310 /* Now, parse the file contents */
2311 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2315 u->load_state = UNIT_LOADED;
2318 free(u->fragment_path);
2319 u->fragment_path = filename;
2322 u->fragment_mtime = timespec_load(&st.st_mtim);
2324 if (u->source_path) {
2325 if (stat(u->source_path, &st) >= 0)
2326 u->source_mtime = timespec_load(&st.st_mtim);
2328 u->source_mtime = 0;
2334 set_free_free(symlink_names);
2343 int unit_load_fragment(Unit *u) {
2349 assert(u->load_state == UNIT_STUB);
2352 /* First, try to find the unit under its id. We always look
2353 * for unit files in the default directories, to make it easy
2354 * to override things by placing things in /etc/systemd/system */
2355 if ((r = load_from_path(u, u->id)) < 0)
2358 /* Try to find an alias we can load this with */
2359 if (u->load_state == UNIT_STUB)
2360 SET_FOREACH(t, u->names, i) {
2365 if ((r = load_from_path(u, t)) < 0)
2368 if (u->load_state != UNIT_STUB)
2372 /* And now, try looking for it under the suggested (originally linked) path */
2373 if (u->load_state == UNIT_STUB && u->fragment_path) {
2375 if ((r = load_from_path(u, u->fragment_path)) < 0)
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 if (!(k = unit_name_template(u->id)))
2394 r = load_from_path(u, k);
2400 if (u->load_state == UNIT_STUB)
2401 SET_FOREACH(t, u->names, i) {
2406 if (!(k = unit_name_template(t)))
2409 r = load_from_path(u, k);
2415 if (u->load_state != UNIT_STUB)
2423 void unit_dump_config_items(FILE *f) {
2424 static const struct {
2425 const ConfigParserCallback callback;
2428 { config_parse_int, "INTEGER" },
2429 { config_parse_unsigned, "UNSIGNED" },
2430 { config_parse_bytes_size, "SIZE" },
2431 { config_parse_bool, "BOOLEAN" },
2432 { config_parse_string, "STRING" },
2433 { config_parse_path, "PATH" },
2434 { config_parse_unit_path_printf, "PATH" },
2435 { config_parse_strv, "STRING [...]" },
2436 { config_parse_exec_nice, "NICE" },
2437 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2438 { config_parse_exec_io_class, "IOCLASS" },
2439 { config_parse_exec_io_priority, "IOPRIORITY" },
2440 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2441 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2442 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2443 { config_parse_mode, "MODE" },
2444 { config_parse_unit_env_file, "FILE" },
2445 { config_parse_output, "OUTPUT" },
2446 { config_parse_input, "INPUT" },
2447 { config_parse_facility, "FACILITY" },
2448 { config_parse_level, "LEVEL" },
2449 { config_parse_exec_capabilities, "CAPABILITIES" },
2450 { config_parse_exec_secure_bits, "SECUREBITS" },
2451 { config_parse_bounding_set, "BOUNDINGSET" },
2452 { config_parse_exec_timer_slack_nsec, "TIMERSLACK" },
2453 { config_parse_limit, "LIMIT" },
2454 { config_parse_unit_cgroup, "CGROUP [...]" },
2455 { config_parse_unit_deps, "UNIT [...]" },
2456 { config_parse_unit_names, "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_path_strv, "PATH [...]" },
2472 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2473 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2474 { config_parse_unit_string_printf, "STRING" },
2475 { config_parse_timer, "TIMER" },
2476 { config_parse_timer_unit, "NAME" },
2477 { config_parse_path_spec, "PATH" },
2478 { config_parse_path_unit, "UNIT" },
2479 { config_parse_notify_access, "ACCESS" },
2480 { config_parse_ip_tos, "TOS" },
2481 { config_parse_unit_condition_path, "CONDITION" },
2482 { config_parse_unit_condition_string, "CONDITION" },
2483 { config_parse_unit_condition_null, "CONDITION" },
2486 const char *prev = NULL;
2491 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2492 const char *rvalue = "OTHER", *lvalue;
2496 const ConfigPerfItem *p;
2498 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2500 dot = strchr(i, '.');
2501 lvalue = dot ? dot + 1 : i;
2505 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2509 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2512 for (j = 0; j < ELEMENTSOF(table); j++)
2513 if (p->parse == table[j].callback) {
2514 rvalue = table[j].rvalue;
2518 fprintf(f, "%s=%s\n", lvalue, rvalue);