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"
53 #ifndef HAVE_SYSV_COMPAT
54 int config_parse_warn_compat(
64 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
69 int config_parse_unit_deps(
79 UnitDependency d = ltype;
89 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
90 char _cleanup_free_ *t = NULL, *k = NULL;
97 k = unit_name_printf(u, t);
101 r = unit_add_dependency_by_name(u, d, k, NULL, true);
103 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
104 filename, line, k, strerror(-r));
110 int config_parse_unit_string_printf(
111 const char *filename,
121 _cleanup_free_ char *k = NULL;
128 k = unit_full_printf(u, rvalue);
132 return config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
135 int config_parse_unit_strv_printf(
136 const char *filename,
146 _cleanup_free_ char *k = NULL;
153 k = unit_full_printf(u, rvalue);
157 return config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
160 int config_parse_unit_path_printf(
161 const char *filename,
171 _cleanup_free_ char *k = NULL;
178 k = unit_full_printf(u, rvalue);
182 return config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
185 int config_parse_socket_listen(
186 const char *filename,
195 SocketPort *p, *tail;
205 if (isempty(rvalue)) {
206 /* An empty assignment removes all ports */
207 socket_free_ports(s);
211 p = new0(SocketPort, 1);
215 if (ltype != SOCKET_SOCKET) {
218 p->path = unit_full_printf(UNIT(s), rvalue);
224 path_kill_slashes(p->path);
226 } else if (streq(lvalue, "ListenNetlink")) {
227 _cleanup_free_ char *k = NULL;
230 p->type = SOCKET_SOCKET;
231 k = unit_full_printf(UNIT(s), rvalue);
237 r = socket_address_parse_netlink(&p->address, k);
239 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
245 _cleanup_free_ char *k = NULL;
248 p->type = SOCKET_SOCKET;
249 k = unit_full_printf(UNIT(s), rvalue);
255 r = socket_address_parse(&p->address, k);
257 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
262 if (streq(lvalue, "ListenStream"))
263 p->address.type = SOCK_STREAM;
264 else if (streq(lvalue, "ListenDatagram"))
265 p->address.type = SOCK_DGRAM;
267 assert(streq(lvalue, "ListenSequentialPacket"));
268 p->address.type = SOCK_SEQPACKET;
271 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
272 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
281 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
282 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
284 LIST_PREPEND(SocketPort, port, s->ports, p);
289 int config_parse_socket_bind(
290 const char *filename,
300 SocketAddressBindIPv6Only b;
309 b = socket_address_bind_ipv6_only_from_string(rvalue);
313 r = parse_boolean(rvalue);
315 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
319 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
321 s->bind_ipv6_only = b;
326 int config_parse_exec_nice(
327 const char *filename,
336 ExecContext *c = data;
344 if (safe_atoi(rvalue, &priority) < 0) {
345 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
349 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
350 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
360 int config_parse_exec_oom_score_adjust(
361 const char *filename,
370 ExecContext *c = data;
378 if (safe_atoi(rvalue, &oa) < 0) {
379 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
383 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
384 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
388 c->oom_score_adjust = oa;
389 c->oom_score_adjust_set = true;
394 int config_parse_exec(
395 const char *filename,
404 ExecCommand **e = data, *nce;
416 if (isempty(rvalue)) {
417 /* An empty assignment resets the list */
418 exec_command_free_list(*e);
423 /* We accept an absolute path as first argument, or
424 * alternatively an absolute prefixed with @ to allow
425 * overriding of argv[0]. */
431 bool honour_argv0 = false, ignore = false;
437 rvalue += strspn(rvalue, WHITESPACE);
442 for (i = 0; i < 2; i++) {
443 if (rvalue[0] == '-' && !ignore) {
448 if (rvalue[0] == '@' && !honour_argv0) {
454 if (*rvalue != '/') {
455 log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
456 filename, line, rvalue);
461 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
462 if (strneq(w, ";", MAX(l, 1U)))
468 n = new(char*, k + !honour_argv0);
473 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
474 if (strneq(w, ";", MAX(l, 1U)))
476 else if (strneq(w, "\\;", MAX(l, 1U)))
479 if (honour_argv0 && w == rvalue) {
482 path = strndup(w, l);
488 if (!utf8_is_valid(path)) {
489 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
497 c = n[k++] = cunescape_length(w, l);
503 if (!utf8_is_valid(c)) {
504 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
514 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
527 assert(path_is_absolute(path));
529 nce = new0(ExecCommand, 1);
537 nce->ignore = ignore;
539 path_kill_slashes(nce->path);
541 exec_command_append_list(e, nce);
557 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
558 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
560 int config_parse_socket_bindtodevice(
561 const char *filename,
578 if (rvalue[0] && !streq(rvalue, "*")) {
585 free(s->bind_to_device);
586 s->bind_to_device = n;
591 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
592 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
594 int config_parse_exec_io_class(
595 const char *filename,
604 ExecContext *c = data;
612 x = ioprio_class_from_string(rvalue);
614 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
618 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
619 c->ioprio_set = true;
624 int config_parse_exec_io_priority(
625 const char *filename,
634 ExecContext *c = data;
642 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
643 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
647 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
648 c->ioprio_set = true;
653 int config_parse_exec_cpu_sched_policy(
654 const char *filename,
664 ExecContext *c = data;
672 x = sched_policy_from_string(rvalue);
674 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
678 c->cpu_sched_policy = x;
679 /* Moving to or from real-time policy? We need to adjust the priority */
680 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
681 c->cpu_sched_set = true;
686 int config_parse_exec_cpu_sched_prio(
687 const char *filename,
696 ExecContext *c = data;
704 if (safe_atoi(rvalue, &i) < 0) {
705 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
709 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
710 min = sched_get_priority_min(c->cpu_sched_policy);
711 max = sched_get_priority_max(c->cpu_sched_policy);
713 if (i < min || i > max) {
714 log_error("[%s:%u] CPU scheduling priority is out of range, ignoring: %s", filename, line, rvalue);
718 c->cpu_sched_priority = i;
719 c->cpu_sched_set = true;
724 int config_parse_exec_cpu_affinity(
725 const char *filename,
734 ExecContext *c = data;
744 if (isempty(rvalue)) {
745 /* An empty assignment resets the CPU list */
752 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
753 char _cleanup_free_ *t = NULL;
761 r = safe_atou(t, &cpu);
764 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
769 if (r < 0 || cpu >= c->cpuset_ncpus) {
770 log_error("[%s:%u] Failed to parse CPU affinity %s, ignoring: %s",
771 filename, line, t, rvalue);
775 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
781 int config_parse_exec_capabilities(
782 const char *filename,
791 ExecContext *c = data;
799 cap = cap_from_text(rvalue);
804 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
809 cap_free(c->capabilities);
810 c->capabilities = cap;
815 int config_parse_exec_secure_bits(
816 const char *filename,
825 ExecContext *c = data;
835 if (isempty(rvalue)) {
836 /* An empty assignment resets the field */
841 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
842 if (first_word(w, "keep-caps"))
843 c->secure_bits |= SECURE_KEEP_CAPS;
844 else if (first_word(w, "keep-caps-locked"))
845 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
846 else if (first_word(w, "no-setuid-fixup"))
847 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
848 else if (first_word(w, "no-setuid-fixup-locked"))
849 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
850 else if (first_word(w, "noroot"))
851 c->secure_bits |= SECURE_NOROOT;
852 else if (first_word(w, "noroot-locked"))
853 c->secure_bits |= SECURE_NOROOT_LOCKED;
855 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s",
856 filename, line, rvalue);
864 int config_parse_bounding_set(
865 const char *filename,
874 uint64_t *capability_bounding_set_drop = data;
886 if (isempty(rvalue)) {
887 /* An empty assignment resets */
888 *capability_bounding_set_drop = 0;
892 if (rvalue[0] == '~') {
897 /* Note that we store this inverted internally, since the
898 * kernel wants it like this. But we actually expose it
899 * non-inverted everywhere to have a fully normalized
902 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
903 char _cleanup_free_ *t = NULL;
911 r = cap_from_name(t, &cap);
913 log_error("[%s:%u] Failed to parse capability in bounding set, ignoring: %s",
918 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
922 *capability_bounding_set_drop |= sum;
924 *capability_bounding_set_drop |= ~sum;
929 int config_parse_limit(
930 const char *filename,
939 struct rlimit **rl = data;
940 unsigned long long u;
949 if (streq(rvalue, "infinity"))
950 u = (unsigned long long) RLIM_INFINITY;
951 else if (safe_atollu(rvalue, &u) < 0) {
952 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
957 *rl = new(struct rlimit, 1);
962 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
966 int config_parse_unit_cgroup(
967 const char *filename,
981 if (isempty(rvalue)) {
982 /* An empty assignment resets the list */
983 cgroup_bonding_free_list(u->cgroup_bondings, false);
984 u->cgroup_bondings = NULL;
988 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
989 char _cleanup_free_ *t = NULL, *k = NULL, *ku = NULL;
996 k = unit_full_printf(u, t);
1004 r = unit_add_cgroup_from_text(u, ku, true, NULL);
1006 log_error("[%s:%u] Failed to parse cgroup value %s, ignoring: %s",
1007 filename, line, k, rvalue);
1015 #ifdef HAVE_SYSV_COMPAT
1016 int config_parse_sysv_priority(
1017 const char *filename,
1019 const char *section,
1026 int *priority = data;
1034 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1035 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1039 *priority = (int) i;
1044 int config_parse_fsck_passno(
1045 const char *filename,
1047 const char *section,
1062 if (safe_atoi(rvalue, &i) || i < 0) {
1063 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1071 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1073 int config_parse_kill_signal(
1074 const char *filename,
1076 const char *section,
1091 r = signal_from_string_try_harder(rvalue);
1093 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1101 int config_parse_exec_mount_flags(
1102 const char *filename,
1104 const char *section,
1111 ExecContext *c = data;
1115 unsigned long flags = 0;
1122 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1123 char _cleanup_free_ *t;
1129 if (streq(t, "shared"))
1131 else if (streq(t, "slave"))
1133 else if (streq(w, "private"))
1134 flags |= MS_PRIVATE;
1136 log_error("[%s:%u] Failed to parse mount flag %s, ignoring: %s",
1137 filename, line, t, rvalue);
1142 c->mount_flags = flags;
1146 int config_parse_timer(
1147 const char *filename,
1149 const char *section,
1160 CalendarSpec *c = NULL;
1168 if (isempty(rvalue)) {
1169 /* Empty assignment resets list */
1170 timer_free_values(t);
1174 b = timer_base_from_string(lvalue);
1176 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1180 if (b == TIMER_CALENDAR) {
1181 if (calendar_spec_from_string(rvalue, &c) < 0) {
1182 log_error("[%s:%u] Failed to parse calendar specification, ignoring: %s", filename, line, rvalue);
1186 id = CLOCK_REALTIME;
1188 if (parse_usec(rvalue, &u) < 0) {
1189 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1193 id = CLOCK_MONOTONIC;
1196 v = new0(TimerValue, 1);
1203 v->calendar_spec = c;
1205 LIST_PREPEND(TimerValue, value, t->values, v);
1210 int config_parse_timer_unit(
1211 const char *filename,
1213 const char *section,
1224 _cleanup_free_ char *p = NULL;
1231 dbus_error_init(&error);
1233 p = unit_name_printf(UNIT(t), rvalue);
1237 if (endswith(p, ".timer")) {
1238 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1242 r = manager_load_unit(UNIT(t)->manager, p, NULL, NULL, &u);
1244 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1245 dbus_error_free(&error);
1249 unit_ref_set(&t->unit, u);
1254 int config_parse_path_spec(
1255 const char *filename,
1257 const char *section,
1274 if (isempty(rvalue)) {
1275 /* Empty assignment clears list */
1280 b = path_type_from_string(lvalue);
1282 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1286 k = unit_full_printf(UNIT(p), rvalue);
1290 if (!path_is_absolute(k)) {
1291 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1296 s = new0(PathSpec, 1);
1302 s->path = path_kill_slashes(k);
1306 LIST_PREPEND(PathSpec, spec, p->specs, s);
1311 int config_parse_path_unit(
1312 const char *filename,
1314 const char *section,
1325 _cleanup_free_ char *p = NULL;
1332 dbus_error_init(&error);
1334 p = unit_name_printf(UNIT(t), rvalue);
1338 if (endswith(p, ".path")) {
1339 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, p);
1343 r = manager_load_unit(UNIT(t)->manager, p, NULL, &error, &u);
1345 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, p, bus_error(&error, r));
1346 dbus_error_free(&error);
1350 unit_ref_set(&t->unit, u);
1355 int config_parse_socket_service(
1356 const char *filename,
1358 const char *section,
1369 _cleanup_free_ char *p = NULL;
1376 dbus_error_init(&error);
1378 p = unit_name_printf(UNIT(s), rvalue);
1382 if (!endswith(p, ".service")) {
1383 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1387 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1389 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1390 dbus_error_free(&error);
1394 unit_ref_set(&s->service, x);
1399 int config_parse_service_sockets(
1400 const char *filename,
1402 const char *section,
1419 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1420 char _cleanup_free_ *t = NULL, *k = NULL;
1426 k = unit_name_printf(UNIT(s), t);
1430 if (!endswith(k, ".socket")) {
1431 log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1436 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1438 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1439 filename, line, k, strerror(-r));
1441 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1449 int config_parse_service_timeout(
1450 const char *filename,
1452 const char *section,
1459 Service *s = userdata;
1467 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1471 if (streq(lvalue, "TimeoutSec")) {
1472 s->start_timeout_defined = true;
1473 s->timeout_stop_usec = s->timeout_start_usec;
1474 } else if (streq(lvalue, "TimeoutStartSec"))
1475 s->start_timeout_defined = true;
1480 int config_parse_unit_env_file(
1481 const char *filename,
1483 const char *section,
1492 _cleanup_free_ char *s = NULL;
1500 if (isempty(rvalue)) {
1501 /* Empty assignment frees the list */
1507 s = unit_full_printf(u, rvalue);
1511 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1512 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1516 r = strv_extend(env, s);
1523 int config_parse_environ(
1524 const char *filename,
1526 const char *section,
1534 char*** env = data, *w, *state;
1536 _cleanup_free_ char *k = NULL;
1543 if (isempty(rvalue)) {
1544 /* Empty assignment resets the list */
1550 k = unit_full_printf(u, rvalue);
1554 FOREACH_WORD_QUOTED(w, l, k, state) {
1555 _cleanup_free_ char *n;
1558 n = cunescape_length(w, l);
1562 if (!env_assignment_is_valid(n)) {
1563 log_error("[%s:%u] Invalid environment assignment, ignoring: %s", filename, line, rvalue);
1567 x = strv_env_set(*env, n);
1578 int config_parse_ip_tos(
1579 const char *filename,
1581 const char *section,
1588 int *ip_tos = data, x;
1595 x = ip_tos_from_string(rvalue);
1597 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1605 int config_parse_unit_condition_path(
1606 const char *filename,
1608 const char *section,
1615 ConditionType cond = ltype;
1617 bool trigger, negate;
1619 _cleanup_free_ char *p = NULL;
1626 if (isempty(rvalue)) {
1627 /* Empty assignment resets the list */
1628 condition_free_list(u->conditions);
1629 u->conditions = NULL;
1633 trigger = rvalue[0] == '|';
1637 negate = rvalue[0] == '!';
1641 p = unit_full_printf(u, rvalue);
1645 if (!path_is_absolute(p)) {
1646 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1650 c = condition_new(cond, p, trigger, negate);
1654 LIST_PREPEND(Condition, conditions, u->conditions, c);
1658 int config_parse_unit_condition_string(
1659 const char *filename,
1661 const char *section,
1668 ConditionType cond = ltype;
1670 bool trigger, negate;
1672 _cleanup_free_ char *s = NULL;
1679 if (isempty(rvalue)) {
1680 /* Empty assignment resets the list */
1681 condition_free_list(u->conditions);
1682 u->conditions = NULL;
1686 trigger = rvalue[0] == '|';
1690 negate = rvalue[0] == '!';
1694 s = unit_full_printf(u, rvalue);
1698 c = condition_new(cond, s, trigger, negate);
1702 LIST_PREPEND(Condition, conditions, u->conditions, c);
1706 int config_parse_unit_condition_null(
1707 const char *filename,
1709 const char *section,
1718 bool trigger, negate;
1726 if (isempty(rvalue)) {
1727 /* Empty assignment resets the list */
1728 condition_free_list(u->conditions);
1729 u->conditions = NULL;
1733 trigger = rvalue[0] == '|';
1737 negate = rvalue[0] == '!';
1741 b = parse_boolean(rvalue);
1743 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1750 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1754 LIST_PREPEND(Condition, conditions, u->conditions, c);
1758 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1759 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1761 int config_parse_unit_cgroup_attr(
1762 const char *filename,
1764 const char *section,
1773 _cleanup_free_ char *n = NULL, *v = NULL;
1774 const CGroupSemantics *s;
1782 if (isempty(rvalue)) {
1783 /* Empty assignment clears the list */
1784 cgroup_attribute_free_list(u->cgroup_attributes);
1785 u->cgroup_attributes = NULL;
1789 a = strcspn(rvalue, WHITESPACE);
1790 b = strspn(rvalue + a, WHITESPACE);
1791 if (a <= 0 || b <= 0) {
1792 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1796 n = strndup(rvalue, a);
1800 r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1802 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1806 r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1808 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1815 int config_parse_unit_cgroup_attr_pretty(
1816 const char *filename,
1818 const char *section,
1826 _cleanup_free_ char *v = NULL;
1827 const CGroupSemantics *s;
1835 r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1837 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1839 } else if (r == 0) {
1840 log_error("[%s:%u] Unknown or unsupported cgroup attribute %s, ignoring: %s", filename, line, lvalue, rvalue);
1844 r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1846 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1853 int config_parse_unit_requires_mounts_for(
1854 const char *filename,
1856 const char *section,
1872 empty_before = !u->requires_mounts_for;
1874 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1876 /* Make it easy to find units with requires_mounts set */
1877 if (empty_before && u->requires_mounts_for)
1878 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1883 int config_parse_documentation(
1884 const char *filename,
1886 const char *section,
1902 if (isempty(rvalue)) {
1903 /* Empty assignment resets the list */
1904 strv_free(u->documentation);
1905 u->documentation = NULL;
1909 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1913 for (a = b = u->documentation; a && *a; a++) {
1915 if (is_valid_documentation_url(*a))
1918 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
1927 static void syscall_set(uint32_t *p, int nr) {
1928 nr = SYSCALL_TO_INDEX(nr);
1929 p[nr >> 4] |= 1 << (nr & 31);
1932 static void syscall_unset(uint32_t *p, int nr) {
1933 nr = SYSCALL_TO_INDEX(nr);
1934 p[nr >> 4] &= ~(1 << (nr & 31));
1937 int config_parse_syscall_filter(
1938 const char *filename,
1940 const char *section,
1947 ExecContext *c = data;
1949 bool invert = false;
1959 if (isempty(rvalue)) {
1960 /* Empty assignment resets the list */
1961 free(c->syscall_filter);
1962 c->syscall_filter = NULL;
1966 if (rvalue[0] == '~') {
1971 if (!c->syscall_filter) {
1974 n = (syscall_max() + 31) >> 4;
1975 c->syscall_filter = new(uint32_t, n);
1976 if (!c->syscall_filter)
1979 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1981 /* Add these by default */
1982 syscall_set(c->syscall_filter, __NR_execve);
1983 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1984 #ifdef __NR_sigreturn
1985 syscall_set(c->syscall_filter, __NR_sigreturn);
1987 syscall_set(c->syscall_filter, __NR_exit_group);
1988 syscall_set(c->syscall_filter, __NR_exit);
1991 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1993 char _cleanup_free_ *t = NULL;
1999 id = syscall_from_name(t);
2001 log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2007 syscall_unset(c->syscall_filter, id);
2009 syscall_set(c->syscall_filter, id);
2012 c->no_new_privileges = true;
2017 #define FOLLOW_MAX 8
2019 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2030 /* This will update the filename pointer if the loaded file is
2031 * reached by a symlink. The old string will be freed. */
2034 char *target, *name;
2036 if (c++ >= FOLLOW_MAX)
2039 path_kill_slashes(*filename);
2041 /* Add the file name we are currently looking at to
2042 * the names of this unit, but only if it is a valid
2044 name = path_get_file_name(*filename);
2046 if (unit_name_is_valid(name, true)) {
2048 id = set_get(names, name);
2054 r = set_put(names, id);
2062 /* Try to open the file name, but don't if its a symlink */
2063 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2070 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2071 r = readlink_and_make_absolute(*filename, &target);
2079 f = fdopen(fd, "re");
2082 close_nointr_nofail(fd);
2091 static int merge_by_names(Unit **u, Set *names, const char *id) {
2099 /* Let's try to add in all symlink names we found */
2100 while ((k = set_steal_first(names))) {
2102 /* First try to merge in the other name into our
2104 r = unit_merge_by_name(*u, k);
2108 /* Hmm, we couldn't merge the other unit into
2109 * ours? Then let's try it the other way
2112 other = manager_get_unit((*u)->manager, k);
2116 r = unit_merge(other, *u);
2119 return merge_by_names(u, names, NULL);
2127 unit_choose_id(*u, id);
2135 static int load_from_path(Unit *u, const char *path) {
2139 char *filename = NULL, *id = NULL;
2146 symlink_names = set_new(string_hash_func, string_compare_func);
2150 if (path_is_absolute(path)) {
2152 filename = strdup(path);
2158 r = open_follow(&filename, &f, symlink_names, &id);
2170 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2172 /* Instead of opening the path right away, we manually
2173 * follow all symlinks and add their name to our unit
2174 * name set while doing so */
2175 filename = path_make_absolute(path, *p);
2181 if (u->manager->unit_path_cache &&
2182 !set_get(u->manager->unit_path_cache, filename))
2185 r = open_follow(&filename, &f, symlink_names, &id);
2194 /* Empty the symlink names for the next run */
2195 set_clear_free(symlink_names);
2204 /* Hmm, no suitable file found? */
2210 r = merge_by_names(&merged, symlink_names, id);
2215 u->load_state = UNIT_MERGED;
2220 if (fstat(fileno(f), &st) < 0) {
2225 if (null_or_empty(&st))
2226 u->load_state = UNIT_MASKED;
2228 /* Now, parse the file contents */
2229 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2233 u->load_state = UNIT_LOADED;
2236 free(u->fragment_path);
2237 u->fragment_path = filename;
2240 u->fragment_mtime = timespec_load(&st.st_mtim);
2242 if (u->source_path) {
2243 if (stat(u->source_path, &st) >= 0)
2244 u->source_mtime = timespec_load(&st.st_mtim);
2246 u->source_mtime = 0;
2252 set_free_free(symlink_names);
2261 int unit_load_fragment(Unit *u) {
2267 assert(u->load_state == UNIT_STUB);
2270 /* First, try to find the unit under its id. We always look
2271 * for unit files in the default directories, to make it easy
2272 * to override things by placing things in /etc/systemd/system */
2273 r = load_from_path(u, u->id);
2277 /* Try to find an alias we can load this with */
2278 if (u->load_state == UNIT_STUB)
2279 SET_FOREACH(t, u->names, i) {
2284 r = load_from_path(u, t);
2288 if (u->load_state != UNIT_STUB)
2292 /* And now, try looking for it under the suggested (originally linked) path */
2293 if (u->load_state == UNIT_STUB && u->fragment_path) {
2295 r = load_from_path(u, u->fragment_path);
2299 if (u->load_state == UNIT_STUB) {
2300 /* Hmm, this didn't work? Then let's get rid
2301 * of the fragment path stored for us, so that
2302 * we don't point to an invalid location. */
2303 free(u->fragment_path);
2304 u->fragment_path = NULL;
2308 /* Look for a template */
2309 if (u->load_state == UNIT_STUB && u->instance) {
2312 k = unit_name_template(u->id);
2316 r = load_from_path(u, k);
2322 if (u->load_state == UNIT_STUB)
2323 SET_FOREACH(t, u->names, i) {
2328 k = unit_name_template(t);
2332 r = load_from_path(u, k);
2338 if (u->load_state != UNIT_STUB)
2346 void unit_dump_config_items(FILE *f) {
2347 static const struct {
2348 const ConfigParserCallback callback;
2351 { config_parse_int, "INTEGER" },
2352 { config_parse_unsigned, "UNSIGNED" },
2353 { config_parse_bytes_size, "SIZE" },
2354 { config_parse_bool, "BOOLEAN" },
2355 { config_parse_string, "STRING" },
2356 { config_parse_path, "PATH" },
2357 { config_parse_unit_path_printf, "PATH" },
2358 { config_parse_strv, "STRING [...]" },
2359 { config_parse_exec_nice, "NICE" },
2360 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2361 { config_parse_exec_io_class, "IOCLASS" },
2362 { config_parse_exec_io_priority, "IOPRIORITY" },
2363 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2364 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2365 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2366 { config_parse_mode, "MODE" },
2367 { config_parse_unit_env_file, "FILE" },
2368 { config_parse_output, "OUTPUT" },
2369 { config_parse_input, "INPUT" },
2370 { config_parse_facility, "FACILITY" },
2371 { config_parse_level, "LEVEL" },
2372 { config_parse_exec_capabilities, "CAPABILITIES" },
2373 { config_parse_exec_secure_bits, "SECUREBITS" },
2374 { config_parse_bounding_set, "BOUNDINGSET" },
2375 { config_parse_limit, "LIMIT" },
2376 { config_parse_unit_cgroup, "CGROUP [...]" },
2377 { config_parse_unit_deps, "UNIT [...]" },
2378 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2379 { config_parse_service_type, "SERVICETYPE" },
2380 { config_parse_service_restart, "SERVICERESTART" },
2381 #ifdef HAVE_SYSV_COMPAT
2382 { config_parse_sysv_priority, "SYSVPRIORITY" },
2384 { config_parse_warn_compat, "NOTSUPPORTED" },
2386 { config_parse_kill_mode, "KILLMODE" },
2387 { config_parse_kill_signal, "SIGNAL" },
2388 { config_parse_socket_listen, "SOCKET [...]" },
2389 { config_parse_socket_bind, "SOCKETBIND" },
2390 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2391 { config_parse_usec, "SECONDS" },
2392 { config_parse_nsec, "NANOSECONDS" },
2393 { config_parse_path_strv, "PATH [...]" },
2394 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2395 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2396 { config_parse_unit_string_printf, "STRING" },
2397 { config_parse_timer, "TIMER" },
2398 { config_parse_timer_unit, "NAME" },
2399 { config_parse_path_spec, "PATH" },
2400 { config_parse_path_unit, "UNIT" },
2401 { config_parse_notify_access, "ACCESS" },
2402 { config_parse_ip_tos, "TOS" },
2403 { config_parse_unit_condition_path, "CONDITION" },
2404 { config_parse_unit_condition_string, "CONDITION" },
2405 { config_parse_unit_condition_null, "CONDITION" },
2408 const char *prev = NULL;
2413 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2414 const char *rvalue = "OTHER", *lvalue;
2418 const ConfigPerfItem *p;
2420 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2422 dot = strchr(i, '.');
2423 lvalue = dot ? dot + 1 : i;
2427 if (!prev || !strneq(prev, i, prefix_len+1)) {
2431 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2434 for (j = 0; j < ELEMENTSOF(table); j++)
2435 if (p->parse == table[j].callback) {
2436 rvalue = table[j].rvalue;
2440 fprintf(f, "%s=%s\n", lvalue, rvalue);