1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2012 Holger Hans Peter Freyther
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/oom.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
35 #include <sys/resource.h>
39 #include "conf-parser.h"
40 #include "load-fragment.h"
43 #include "securebits.h"
45 #include "unit-name.h"
46 #include "unit-printf.h"
47 #include "bus-errors.h"
49 #include "path-util.h"
50 #include "syscall-list.h"
52 #ifndef HAVE_SYSV_COMPAT
53 int config_parse_warn_compat(
63 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
68 int config_parse_unit_deps(
78 UnitDependency d = ltype;
88 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
89 char _cleanup_free_ *t = NULL, *k = NULL;
96 k = unit_name_printf(u, t);
100 r = unit_add_dependency_by_name(u, d, k, NULL, true);
102 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
103 filename, line, k, strerror(-r));
109 int config_parse_unit_string_printf(
110 const char *filename,
120 _cleanup_free_ char *k = NULL;
127 k = unit_full_printf(u, rvalue);
131 return config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
134 int config_parse_unit_strv_printf(
135 const char *filename,
145 _cleanup_free_ char *k = NULL;
152 k = unit_full_printf(u, rvalue);
156 return config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
159 int config_parse_unit_path_printf(
160 const char *filename,
170 _cleanup_free_ char *k = NULL;
177 k = unit_full_printf(u, rvalue);
181 return config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
184 int config_parse_socket_listen(
185 const char *filename,
194 SocketPort *p, *tail;
204 if (isempty(rvalue)) {
205 /* An empty assignment removes all ports */
206 socket_free_ports(s);
210 p = new0(SocketPort, 1);
214 if (ltype != SOCKET_SOCKET) {
217 p->path = unit_full_printf(UNIT(s), rvalue);
223 path_kill_slashes(p->path);
225 } else if (streq(lvalue, "ListenNetlink")) {
226 _cleanup_free_ char *k = NULL;
229 p->type = SOCKET_SOCKET;
230 k = unit_full_printf(UNIT(s), rvalue);
236 r = socket_address_parse_netlink(&p->address, k);
238 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
244 _cleanup_free_ char *k = NULL;
247 p->type = SOCKET_SOCKET;
248 k = unit_full_printf(UNIT(s), rvalue);
254 r = socket_address_parse(&p->address, k);
256 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
261 if (streq(lvalue, "ListenStream"))
262 p->address.type = SOCK_STREAM;
263 else if (streq(lvalue, "ListenDatagram"))
264 p->address.type = SOCK_DGRAM;
266 assert(streq(lvalue, "ListenSequentialPacket"));
267 p->address.type = SOCK_SEQPACKET;
270 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
271 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
280 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
281 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
283 LIST_PREPEND(SocketPort, port, s->ports, p);
288 int config_parse_socket_bind(
289 const char *filename,
299 SocketAddressBindIPv6Only b;
308 b = socket_address_bind_ipv6_only_from_string(rvalue);
312 r = parse_boolean(rvalue);
314 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
318 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
320 s->bind_ipv6_only = b;
325 int config_parse_exec_nice(
326 const char *filename,
335 ExecContext *c = data;
343 if (safe_atoi(rvalue, &priority) < 0) {
344 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
348 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
349 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
359 int config_parse_exec_oom_score_adjust(
360 const char *filename,
369 ExecContext *c = data;
377 if (safe_atoi(rvalue, &oa) < 0) {
378 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
382 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
383 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
387 c->oom_score_adjust = oa;
388 c->oom_score_adjust_set = true;
393 int config_parse_exec(
394 const char *filename,
403 ExecCommand **e = data, *nce;
415 if (isempty(rvalue)) {
416 /* An empty assignment resets the list */
417 exec_command_free_list(*e);
422 /* We accept an absolute path as first argument, or
423 * alternatively an absolute prefixed with @ to allow
424 * overriding of argv[0]. */
430 bool honour_argv0 = false, ignore = false;
436 rvalue += strspn(rvalue, WHITESPACE);
441 for (i = 0; i < 2; i++) {
442 if (rvalue[0] == '-' && !ignore) {
447 if (rvalue[0] == '@' && !honour_argv0) {
453 if (*rvalue != '/') {
454 log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
455 filename, line, rvalue);
460 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
461 if (strncmp(w, ";", MAX(l, 1U)) == 0)
467 n = new(char*, k + !honour_argv0);
472 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
473 if (strncmp(w, ";", MAX(l, 1U)) == 0)
475 else if (strncmp(w, "\\;", MAX(l, 1U)) == 0)
478 if (honour_argv0 && w == rvalue) {
481 path = strndup(w, l);
487 if (!utf8_is_valid(path)) {
488 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
496 c = n[k++] = cunescape_length(w, l);
502 if (!utf8_is_valid(c)) {
503 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
513 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
526 assert(path_is_absolute(path));
528 nce = new0(ExecCommand, 1);
536 nce->ignore = ignore;
538 path_kill_slashes(nce->path);
540 exec_command_append_list(e, nce);
556 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
557 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
559 int config_parse_socket_bindtodevice(
560 const char *filename,
577 if (rvalue[0] && !streq(rvalue, "*")) {
584 free(s->bind_to_device);
585 s->bind_to_device = n;
590 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
591 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
593 int config_parse_exec_io_class(
594 const char *filename,
603 ExecContext *c = data;
611 x = ioprio_class_from_string(rvalue);
613 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
617 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
618 c->ioprio_set = true;
623 int config_parse_exec_io_priority(
624 const char *filename,
633 ExecContext *c = data;
641 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
642 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
646 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
647 c->ioprio_set = true;
652 int config_parse_exec_cpu_sched_policy(
653 const char *filename,
663 ExecContext *c = data;
671 x = sched_policy_from_string(rvalue);
673 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
677 c->cpu_sched_policy = x;
678 /* Moving to or from real-time policy? We need to adjust the priority */
679 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
680 c->cpu_sched_set = true;
685 int config_parse_exec_cpu_sched_prio(
686 const char *filename,
695 ExecContext *c = data;
703 if (safe_atoi(rvalue, &i) < 0) {
704 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
708 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
709 min = sched_get_priority_min(c->cpu_sched_policy);
710 max = sched_get_priority_max(c->cpu_sched_policy);
712 if (i < min || i > max) {
713 log_error("[%s:%u] CPU scheduling priority is out of range, ignoring: %s", filename, line, rvalue);
717 c->cpu_sched_priority = i;
718 c->cpu_sched_set = true;
723 int config_parse_exec_cpu_affinity(
724 const char *filename,
733 ExecContext *c = data;
743 if (isempty(rvalue)) {
744 /* An empty assignment resets the CPU list */
751 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
752 char _cleanup_free_ *t = NULL;
760 r = safe_atou(t, &cpu);
763 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
768 if (r < 0 || cpu >= c->cpuset_ncpus) {
769 log_error("[%s:%u] Failed to parse CPU affinity %s, ignoring: %s",
770 filename, line, t, rvalue);
774 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
780 int config_parse_exec_capabilities(
781 const char *filename,
790 ExecContext *c = data;
798 cap = cap_from_text(rvalue);
803 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
808 cap_free(c->capabilities);
809 c->capabilities = cap;
814 int config_parse_exec_secure_bits(
815 const char *filename,
824 ExecContext *c = data;
834 if (isempty(rvalue)) {
835 /* An empty assignment resets the field */
840 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
841 if (first_word(w, "keep-caps"))
842 c->secure_bits |= SECURE_KEEP_CAPS;
843 else if (first_word(w, "keep-caps-locked"))
844 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
845 else if (first_word(w, "no-setuid-fixup"))
846 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
847 else if (first_word(w, "no-setuid-fixup-locked"))
848 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
849 else if (first_word(w, "noroot"))
850 c->secure_bits |= SECURE_NOROOT;
851 else if (first_word(w, "noroot-locked"))
852 c->secure_bits |= SECURE_NOROOT_LOCKED;
854 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s",
855 filename, line, rvalue);
863 int config_parse_bounding_set(
864 const char *filename,
873 uint64_t *capability_bounding_set_drop = data;
885 if (isempty(rvalue)) {
886 /* An empty assignment resets */
887 *capability_bounding_set_drop = 0;
891 if (rvalue[0] == '~') {
896 /* Note that we store this inverted internally, since the
897 * kernel wants it like this. But we actually expose it
898 * non-inverted everywhere to have a fully normalized
901 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
902 char _cleanup_free_ *t = NULL;
910 r = cap_from_name(t, &cap);
912 log_error("[%s:%u] Failed to parse capability in bounding set, ignoring: %s",
917 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
921 *capability_bounding_set_drop |= sum;
923 *capability_bounding_set_drop |= ~sum;
928 int config_parse_limit(
929 const char *filename,
938 struct rlimit **rl = data;
939 unsigned long long u;
948 if (streq(rvalue, "infinity"))
949 u = (unsigned long long) RLIM_INFINITY;
950 else if (safe_atollu(rvalue, &u) < 0) {
951 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
956 *rl = new(struct rlimit, 1);
961 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
965 int config_parse_unit_cgroup(
966 const char *filename,
980 if (isempty(rvalue)) {
981 /* An empty assignment resets the list */
982 cgroup_bonding_free_list(u->cgroup_bondings, false);
983 u->cgroup_bondings = NULL;
987 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
988 char _cleanup_free_ *t = NULL, *k = NULL, *ku = NULL;
995 k = unit_full_printf(u, t);
1003 r = unit_add_cgroup_from_text(u, ku, true, NULL);
1005 log_error("[%s:%u] Failed to parse cgroup value %s, ignoring: %s",
1006 filename, line, k, rvalue);
1014 #ifdef HAVE_SYSV_COMPAT
1015 int config_parse_sysv_priority(
1016 const char *filename,
1018 const char *section,
1025 int *priority = data;
1033 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1034 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1038 *priority = (int) i;
1043 int config_parse_fsck_passno(
1044 const char *filename,
1046 const char *section,
1061 if (safe_atoi(rvalue, &i) || i < 0) {
1062 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1070 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1072 int config_parse_kill_signal(
1073 const char *filename,
1075 const char *section,
1090 r = signal_from_string_try_harder(rvalue);
1092 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1100 int config_parse_exec_mount_flags(
1101 const char *filename,
1103 const char *section,
1110 ExecContext *c = data;
1114 unsigned long flags = 0;
1121 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1122 char _cleanup_free_ *t;
1128 if (streq(t, "shared"))
1130 else if (streq(t, "slave"))
1132 else if (streq(w, "private"))
1133 flags |= MS_PRIVATE;
1135 log_error("[%s:%u] Failed to parse mount flag %s, ignoring: %s",
1136 filename, line, t, rvalue);
1141 c->mount_flags = flags;
1145 int config_parse_timer(
1146 const char *filename,
1148 const char *section,
1159 CalendarSpec *c = NULL;
1167 if (isempty(rvalue)) {
1168 /* Empty assignment resets list */
1169 timer_free_values(t);
1173 b = timer_base_from_string(lvalue);
1175 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1179 if (b == TIMER_CALENDAR) {
1180 if (calendar_spec_from_string(rvalue, &c) < 0) {
1181 log_error("[%s:%u] Failed to parse calendar specification, ignoring: %s", filename, line, rvalue);
1185 id = CLOCK_REALTIME;
1187 if (parse_usec(rvalue, &u) < 0) {
1188 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1192 id = CLOCK_MONOTONIC;
1195 v = new0(TimerValue, 1);
1202 v->calendar_spec = c;
1204 LIST_PREPEND(TimerValue, value, t->values, v);
1209 int config_parse_timer_unit(
1210 const char *filename,
1212 const char *section,
1223 _cleanup_free_ char *p = NULL;
1230 dbus_error_init(&error);
1232 p = unit_name_printf(UNIT(t), rvalue);
1236 if (endswith(p, ".timer")) {
1237 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1241 r = manager_load_unit(UNIT(t)->manager, p, NULL, NULL, &u);
1243 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1244 dbus_error_free(&error);
1248 unit_ref_set(&t->unit, u);
1253 int config_parse_path_spec(
1254 const char *filename,
1256 const char *section,
1273 if (isempty(rvalue)) {
1274 /* Empty assignment clears list */
1279 b = path_type_from_string(lvalue);
1281 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1285 k = unit_full_printf(UNIT(p), rvalue);
1289 if (!path_is_absolute(k)) {
1290 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1295 s = new0(PathSpec, 1);
1301 s->path = path_kill_slashes(k);
1305 LIST_PREPEND(PathSpec, spec, p->specs, s);
1310 int config_parse_path_unit(
1311 const char *filename,
1313 const char *section,
1324 _cleanup_free_ char *p = NULL;
1331 dbus_error_init(&error);
1333 p = unit_name_printf(UNIT(t), rvalue);
1337 if (endswith(p, ".path")) {
1338 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, p);
1342 r = manager_load_unit(UNIT(t)->manager, p, NULL, &error, &u);
1344 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, p, bus_error(&error, r));
1345 dbus_error_free(&error);
1349 unit_ref_set(&t->unit, u);
1354 int config_parse_socket_service(
1355 const char *filename,
1357 const char *section,
1368 _cleanup_free_ char *p = NULL;
1375 dbus_error_init(&error);
1377 p = unit_name_printf(UNIT(s), rvalue);
1381 if (!endswith(p, ".service")) {
1382 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1386 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1388 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1389 dbus_error_free(&error);
1393 unit_ref_set(&s->service, x);
1398 int config_parse_service_sockets(
1399 const char *filename,
1401 const char *section,
1418 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1419 char _cleanup_free_ *t = NULL, *k = NULL;
1425 k = unit_name_printf(UNIT(s), t);
1429 if (!endswith(k, ".socket")) {
1430 log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1435 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1437 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1438 filename, line, k, strerror(-r));
1440 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1448 int config_parse_service_timeout(
1449 const char *filename,
1451 const char *section,
1458 Service *s = userdata;
1466 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1470 if (streq(lvalue, "TimeoutSec")) {
1471 s->start_timeout_defined = true;
1472 s->timeout_stop_usec = s->timeout_start_usec;
1473 } else if (streq(lvalue, "TimeoutStartSec"))
1474 s->start_timeout_defined = true;
1479 int config_parse_unit_env_file(
1480 const char *filename,
1482 const char *section,
1489 char ***env = data, **k;
1498 if (isempty(rvalue)) {
1499 /* Empty assignment frees the list */
1506 s = unit_full_printf(u, rvalue);
1510 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1511 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1516 k = strv_append(*env, s);
1527 int config_parse_ip_tos(
1528 const char *filename,
1530 const char *section,
1537 int *ip_tos = data, x;
1544 x = ip_tos_from_string(rvalue);
1546 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1554 int config_parse_unit_condition_path(
1555 const char *filename,
1557 const char *section,
1564 ConditionType cond = ltype;
1566 bool trigger, negate;
1568 _cleanup_free_ char *p = NULL;
1575 if (isempty(rvalue)) {
1576 /* Empty assignment resets the list */
1577 condition_free_list(u->conditions);
1578 u->conditions = NULL;
1582 trigger = rvalue[0] == '|';
1586 negate = rvalue[0] == '!';
1590 p = unit_full_printf(u, rvalue);
1594 if (!path_is_absolute(p)) {
1595 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1599 c = condition_new(cond, p, trigger, negate);
1603 LIST_PREPEND(Condition, conditions, u->conditions, c);
1607 int config_parse_unit_condition_string(
1608 const char *filename,
1610 const char *section,
1617 ConditionType cond = ltype;
1619 bool trigger, negate;
1621 _cleanup_free_ char *s = NULL;
1628 if (isempty(rvalue)) {
1629 /* Empty assignment resets the list */
1630 condition_free_list(u->conditions);
1631 u->conditions = NULL;
1635 trigger = rvalue[0] == '|';
1639 negate = rvalue[0] == '!';
1643 s = unit_full_printf(u, rvalue);
1647 c = condition_new(cond, s, trigger, negate);
1651 LIST_PREPEND(Condition, conditions, u->conditions, c);
1655 int config_parse_unit_condition_null(
1656 const char *filename,
1658 const char *section,
1667 bool trigger, negate;
1675 if (isempty(rvalue)) {
1676 /* Empty assignment resets the list */
1677 condition_free_list(u->conditions);
1678 u->conditions = NULL;
1682 trigger = rvalue[0] == '|';
1686 negate = rvalue[0] == '!';
1690 b = parse_boolean(rvalue);
1692 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1699 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1703 LIST_PREPEND(Condition, conditions, u->conditions, c);
1707 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1708 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1710 int config_parse_unit_cgroup_attr(
1711 const char *filename,
1713 const char *section,
1721 _cleanup_strv_free_ char **l = NULL;
1729 if (isempty(rvalue)) {
1730 /* Empty assignment clears the list */
1731 cgroup_attribute_free_list(u->cgroup_attributes);
1732 u->cgroup_attributes = NULL;
1736 l = strv_split_quoted(rvalue);
1740 if (strv_length(l) != 2) {
1741 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1745 r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL, NULL);
1747 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1754 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) {
1758 _cleanup_free_ char *t = NULL;
1765 if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
1766 log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
1770 if (asprintf(&t, "%lu", ul) < 0)
1773 r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL, NULL);
1775 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1782 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) {
1786 _cleanup_free_ char *t = NULL;
1793 if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
1794 log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
1798 if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
1801 r = unit_add_cgroup_attribute(u,
1803 streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
1806 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1813 static int device_map(const char *controller, const char *name, const char *value, char **ret) {
1814 _cleanup_strv_free_ char **l = NULL;
1821 l = strv_split_quoted(value);
1825 assert(strv_length(l) >= 1);
1827 if (streq(l[0], "*")) {
1829 if (asprintf(ret, "a *:*%s%s",
1830 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0)
1835 if (stat(l[0], &st) < 0) {
1836 log_warning("Couldn't stat device %s", l[0]);
1840 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
1841 log_warning("%s is not a device.", l[0]);
1845 if (asprintf(ret, "%c %u:%u%s%s",
1846 S_ISCHR(st.st_mode) ? 'c' : 'b',
1847 major(st.st_rdev), minor(st.st_rdev),
1848 isempty(l[1]) ? "" : " ", strempty(l[1])) < 0)
1855 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) {
1857 _cleanup_strv_free_ char **l = NULL;
1866 l = strv_split_quoted(rvalue);
1871 if (k < 1 || k > 2) {
1872 log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
1876 if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
1877 log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
1881 if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
1882 log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
1886 r = unit_add_cgroup_attribute(u, "devices",
1887 streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
1888 rvalue, device_map, NULL);
1891 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1898 static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
1900 _cleanup_strv_free_ char **l = NULL;
1908 l = strv_split_quoted(value);
1912 assert(strv_length(l) == 2);
1914 if (stat(l[0], &st) < 0) {
1915 log_warning("Couldn't stat device %s", l[0]);
1919 if (S_ISBLK(st.st_mode))
1921 else if (major(st.st_dev) != 0) {
1922 /* If this is not a device node then find the block
1923 * device this file is stored on */
1926 /* If this is a partition, try to get the originating
1928 block_get_whole_disk(d, &d);
1930 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
1934 if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0)
1940 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) {
1944 const char *device = NULL, *weight;
1946 _cleanup_free_ char *t = NULL;
1947 _cleanup_strv_free_ char **l = NULL;
1954 l = strv_split_quoted(rvalue);
1959 if (k < 1 || k > 2) {
1960 log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
1971 if (device && !path_is_absolute(device)) {
1972 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
1976 if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
1977 log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
1982 r = asprintf(&t, "%s %lu", device, ul);
1984 r = asprintf(&t, "%lu", ul);
1989 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map, NULL);
1991 r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL, NULL);
1993 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
2000 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) {
2005 _cleanup_free_ char *t = NULL;
2006 _cleanup_strv_free_ char **l = NULL;
2013 l = strv_split_quoted(rvalue);
2019 log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
2023 if (!path_is_absolute(l[0])) {
2024 log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
2028 if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
2029 log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
2033 r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
2037 r = unit_add_cgroup_attribute(u, "blkio",
2038 streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
2039 t, blkio_map, NULL);
2041 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
2048 int config_parse_unit_requires_mounts_for(
2049 const char *filename,
2051 const char *section,
2067 empty_before = !u->requires_mounts_for;
2069 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2071 /* Make it easy to find units with requires_mounts set */
2072 if (empty_before && u->requires_mounts_for)
2073 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
2078 int config_parse_documentation(
2079 const char *filename,
2081 const char *section,
2097 if (isempty(rvalue)) {
2098 /* Empty assignment resets the list */
2099 strv_free(u->documentation);
2100 u->documentation = NULL;
2104 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
2108 for (a = b = u->documentation; a && *a; a++) {
2110 if (is_valid_documentation_url(*a))
2113 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
2122 static void syscall_set(uint32_t *p, int nr) {
2123 nr = SYSCALL_TO_INDEX(nr);
2124 p[nr >> 4] |= 1 << (nr & 31);
2127 static void syscall_unset(uint32_t *p, int nr) {
2128 nr = SYSCALL_TO_INDEX(nr);
2129 p[nr >> 4] &= ~(1 << (nr & 31));
2132 int config_parse_syscall_filter(
2133 const char *filename,
2135 const char *section,
2142 ExecContext *c = data;
2144 bool invert = false;
2154 if (isempty(rvalue)) {
2155 /* Empty assignment resets the list */
2156 free(c->syscall_filter);
2157 c->syscall_filter = NULL;
2161 if (rvalue[0] == '~') {
2166 if (!c->syscall_filter) {
2169 n = (syscall_max() + 31) >> 4;
2170 c->syscall_filter = new(uint32_t, n);
2171 if (!c->syscall_filter)
2174 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2176 /* Add these by default */
2177 syscall_set(c->syscall_filter, __NR_execve);
2178 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2179 #ifdef __NR_sigreturn
2180 syscall_set(c->syscall_filter, __NR_sigreturn);
2182 syscall_set(c->syscall_filter, __NR_exit_group);
2183 syscall_set(c->syscall_filter, __NR_exit);
2186 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2188 char _cleanup_free_ *t = NULL;
2194 id = syscall_from_name(t);
2196 log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2202 syscall_unset(c->syscall_filter, id);
2204 syscall_set(c->syscall_filter, id);
2207 c->no_new_privileges = true;
2212 #define FOLLOW_MAX 8
2214 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2225 /* This will update the filename pointer if the loaded file is
2226 * reached by a symlink. The old string will be freed. */
2229 char *target, *name;
2231 if (c++ >= FOLLOW_MAX)
2234 path_kill_slashes(*filename);
2236 /* Add the file name we are currently looking at to
2237 * the names of this unit, but only if it is a valid
2239 name = path_get_file_name(*filename);
2241 if (unit_name_is_valid(name, true)) {
2243 id = set_get(names, name);
2249 r = set_put(names, id);
2257 /* Try to open the file name, but don't if its a symlink */
2258 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2265 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2266 r = readlink_and_make_absolute(*filename, &target);
2274 f = fdopen(fd, "re");
2277 close_nointr_nofail(fd);
2286 static int merge_by_names(Unit **u, Set *names, const char *id) {
2294 /* Let's try to add in all symlink names we found */
2295 while ((k = set_steal_first(names))) {
2297 /* First try to merge in the other name into our
2299 r = unit_merge_by_name(*u, k);
2303 /* Hmm, we couldn't merge the other unit into
2304 * ours? Then let's try it the other way
2307 other = manager_get_unit((*u)->manager, k);
2311 r = unit_merge(other, *u);
2314 return merge_by_names(u, names, NULL);
2322 unit_choose_id(*u, id);
2330 static int load_from_path(Unit *u, const char *path) {
2334 char *filename = NULL, *id = NULL;
2341 symlink_names = set_new(string_hash_func, string_compare_func);
2345 if (path_is_absolute(path)) {
2347 filename = strdup(path);
2353 r = open_follow(&filename, &f, symlink_names, &id);
2365 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2367 /* Instead of opening the path right away, we manually
2368 * follow all symlinks and add their name to our unit
2369 * name set while doing so */
2370 filename = path_make_absolute(path, *p);
2376 if (u->manager->unit_path_cache &&
2377 !set_get(u->manager->unit_path_cache, filename))
2380 r = open_follow(&filename, &f, symlink_names, &id);
2389 /* Empty the symlink names for the next run */
2390 set_clear_free(symlink_names);
2399 /* Hmm, no suitable file found? */
2405 r = merge_by_names(&merged, symlink_names, id);
2410 u->load_state = UNIT_MERGED;
2415 if (fstat(fileno(f), &st) < 0) {
2420 if (null_or_empty(&st))
2421 u->load_state = UNIT_MASKED;
2423 /* Now, parse the file contents */
2424 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2428 u->load_state = UNIT_LOADED;
2431 free(u->fragment_path);
2432 u->fragment_path = filename;
2435 u->fragment_mtime = timespec_load(&st.st_mtim);
2437 if (u->source_path) {
2438 if (stat(u->source_path, &st) >= 0)
2439 u->source_mtime = timespec_load(&st.st_mtim);
2441 u->source_mtime = 0;
2447 set_free_free(symlink_names);
2456 int unit_load_fragment(Unit *u) {
2462 assert(u->load_state == UNIT_STUB);
2465 /* First, try to find the unit under its id. We always look
2466 * for unit files in the default directories, to make it easy
2467 * to override things by placing things in /etc/systemd/system */
2468 r = load_from_path(u, u->id);
2472 /* Try to find an alias we can load this with */
2473 if (u->load_state == UNIT_STUB)
2474 SET_FOREACH(t, u->names, i) {
2479 r = load_from_path(u, t);
2483 if (u->load_state != UNIT_STUB)
2487 /* And now, try looking for it under the suggested (originally linked) path */
2488 if (u->load_state == UNIT_STUB && u->fragment_path) {
2490 r = load_from_path(u, u->fragment_path);
2494 if (u->load_state == UNIT_STUB) {
2495 /* Hmm, this didn't work? Then let's get rid
2496 * of the fragment path stored for us, so that
2497 * we don't point to an invalid location. */
2498 free(u->fragment_path);
2499 u->fragment_path = NULL;
2503 /* Look for a template */
2504 if (u->load_state == UNIT_STUB && u->instance) {
2507 k = unit_name_template(u->id);
2511 r = load_from_path(u, k);
2517 if (u->load_state == UNIT_STUB)
2518 SET_FOREACH(t, u->names, i) {
2523 k = unit_name_template(t);
2527 r = load_from_path(u, k);
2533 if (u->load_state != UNIT_STUB)
2541 void unit_dump_config_items(FILE *f) {
2542 static const struct {
2543 const ConfigParserCallback callback;
2546 { config_parse_int, "INTEGER" },
2547 { config_parse_unsigned, "UNSIGNED" },
2548 { config_parse_bytes_size, "SIZE" },
2549 { config_parse_bool, "BOOLEAN" },
2550 { config_parse_string, "STRING" },
2551 { config_parse_path, "PATH" },
2552 { config_parse_unit_path_printf, "PATH" },
2553 { config_parse_strv, "STRING [...]" },
2554 { config_parse_exec_nice, "NICE" },
2555 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2556 { config_parse_exec_io_class, "IOCLASS" },
2557 { config_parse_exec_io_priority, "IOPRIORITY" },
2558 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2559 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2560 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2561 { config_parse_mode, "MODE" },
2562 { config_parse_unit_env_file, "FILE" },
2563 { config_parse_output, "OUTPUT" },
2564 { config_parse_input, "INPUT" },
2565 { config_parse_facility, "FACILITY" },
2566 { config_parse_level, "LEVEL" },
2567 { config_parse_exec_capabilities, "CAPABILITIES" },
2568 { config_parse_exec_secure_bits, "SECUREBITS" },
2569 { config_parse_bounding_set, "BOUNDINGSET" },
2570 { config_parse_limit, "LIMIT" },
2571 { config_parse_unit_cgroup, "CGROUP [...]" },
2572 { config_parse_unit_deps, "UNIT [...]" },
2573 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2574 { config_parse_service_type, "SERVICETYPE" },
2575 { config_parse_service_restart, "SERVICERESTART" },
2576 #ifdef HAVE_SYSV_COMPAT
2577 { config_parse_sysv_priority, "SYSVPRIORITY" },
2579 { config_parse_warn_compat, "NOTSUPPORTED" },
2581 { config_parse_kill_mode, "KILLMODE" },
2582 { config_parse_kill_signal, "SIGNAL" },
2583 { config_parse_socket_listen, "SOCKET [...]" },
2584 { config_parse_socket_bind, "SOCKETBIND" },
2585 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2586 { config_parse_usec, "SECONDS" },
2587 { config_parse_nsec, "NANOSECONDS" },
2588 { config_parse_path_strv, "PATH [...]" },
2589 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2590 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2591 { config_parse_unit_string_printf, "STRING" },
2592 { config_parse_timer, "TIMER" },
2593 { config_parse_timer_unit, "NAME" },
2594 { config_parse_path_spec, "PATH" },
2595 { config_parse_path_unit, "UNIT" },
2596 { config_parse_notify_access, "ACCESS" },
2597 { config_parse_ip_tos, "TOS" },
2598 { config_parse_unit_condition_path, "CONDITION" },
2599 { config_parse_unit_condition_string, "CONDITION" },
2600 { config_parse_unit_condition_null, "CONDITION" },
2603 const char *prev = NULL;
2608 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2609 const char *rvalue = "OTHER", *lvalue;
2613 const ConfigPerfItem *p;
2615 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2617 dot = strchr(i, '.');
2618 lvalue = dot ? dot + 1 : i;
2622 if (!prev || strncmp(prev, i, prefix_len+1) != 0) {
2626 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2629 for (j = 0; j < ELEMENTSOF(table); j++)
2630 if (p->parse == table[j].callback) {
2631 rvalue = table[j].rvalue;
2635 fprintf(f, "%s=%s\n", lvalue, rvalue);